aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorIvan Blinkov <ivan@blinkov.ru>2022-02-10 16:47:11 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:47:11 +0300
commit5b283123c882433dafbaf6b338adeea16c1a0ea0 (patch)
tree339adc63bce23800021202ae4a8328a843dc447a /contrib
parent1aeb9a455974457866f78722ad98114bafc84e8a (diff)
downloadydb-5b283123c882433dafbaf6b338adeea16c1a0ea0.tar.gz
Restoring authorship annotation for Ivan Blinkov <ivan@blinkov.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/libs/hyperscan/include/boost-patched/graph/reverse_graph.hpp54
-rw-r--r--contrib/libs/hyperscan/src/alloc.c20
-rw-r--r--contrib/libs/hyperscan/src/compiler/asserts.cpp54
-rw-r--r--contrib/libs/hyperscan/src/compiler/asserts.h10
-rw-r--r--contrib/libs/hyperscan/src/compiler/compiler.cpp240
-rw-r--r--contrib/libs/hyperscan/src/compiler/compiler.h48
-rw-r--r--contrib/libs/hyperscan/src/compiler/error.cpp34
-rw-r--r--contrib/libs/hyperscan/src/compiler/expression_info.h204
-rw-r--r--contrib/libs/hyperscan/src/crc32.c12
-rw-r--r--contrib/libs/hyperscan/src/database.c48
-rw-r--r--contrib/libs/hyperscan/src/database.h26
-rw-r--r--contrib/libs/hyperscan/src/fdr/engine_description.h6
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr.c1620
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr.h20
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_compile.cpp1152
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_compile.h36
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_compile_internal.h26
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_confirm.h22
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_confirm_compile.cpp214
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_confirm_runtime.h84
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_engine_description.cpp50
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_engine_description.h2
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_internal.h26
-rw-r--r--contrib/libs/hyperscan/src/fdr/fdr_loadval.h36
-rw-r--r--contrib/libs/hyperscan/src/fdr/flood_compile.cpp48
-rw-r--r--contrib/libs/hyperscan/src/fdr/flood_runtime.h64
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy.c1562
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy.h220
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_avx2.c1006
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_compile.cpp612
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_compile.h24
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_engine_description.cpp48
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_engine_description.h2
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_internal.h50
-rw-r--r--contrib/libs/hyperscan/src/fdr/teddy_runtime_common.h886
-rw-r--r--contrib/libs/hyperscan/src/grey.cpp104
-rw-r--r--contrib/libs/hyperscan/src/grey.h58
-rw-r--r--contrib/libs/hyperscan/src/hs.cpp160
-rw-r--r--contrib/libs/hyperscan/src/hs_common.h208
-rw-r--r--contrib/libs/hyperscan/src/hs_compile.h362
-rw-r--r--contrib/libs/hyperscan/src/hs_runtime.h322
-rw-r--r--contrib/libs/hyperscan/src/hs_valid_platform.c82
-rw-r--r--contrib/libs/hyperscan/src/hs_version.c4
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm.c80
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm.h42
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm_build.cpp156
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm_build.h114
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm_literal.cpp24
-rw-r--r--contrib/libs/hyperscan/src/hwlm/hwlm_literal.h68
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_build.cpp184
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_build.h16
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_engine.c394
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_engine.h10
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_engine_avx2.c58
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_engine_avx512.c382
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_engine_sse.c56
-rw-r--r--contrib/libs/hyperscan/src/hwlm/noodle_internal.h24
-rw-r--r--contrib/libs/hyperscan/src/nfa/accel.c32
-rw-r--r--contrib/libs/hyperscan/src/nfa/accel.h36
-rw-r--r--contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.cpp1212
-rw-r--r--contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.h122
-rw-r--r--contrib/libs/hyperscan/src/nfa/accelcompile.cpp148
-rw-r--r--contrib/libs/hyperscan/src/nfa/accelcompile.h12
-rw-r--r--contrib/libs/hyperscan/src/nfa/callback.h30
-rw-r--r--contrib/libs/hyperscan/src/nfa/castle.c804
-rw-r--r--contrib/libs/hyperscan/src/nfa/castle.h36
-rw-r--r--contrib/libs/hyperscan/src/nfa/castle_internal.h114
-rw-r--r--contrib/libs/hyperscan/src/nfa/castlecompile.cpp436
-rw-r--r--contrib/libs/hyperscan/src/nfa/castlecompile.h38
-rw-r--r--contrib/libs/hyperscan/src/nfa/dfa_build_strat.cpp76
-rw-r--r--contrib/libs/hyperscan/src/nfa/dfa_build_strat.h136
-rw-r--r--contrib/libs/hyperscan/src/nfa/dfa_min.cpp230
-rw-r--r--contrib/libs/hyperscan/src/nfa/dfa_min.h8
-rw-r--r--contrib/libs/hyperscan/src/nfa/gough.c78
-rw-r--r--contrib/libs/hyperscan/src/nfa/gough.h10
-rw-r--r--contrib/libs/hyperscan/src/nfa/goughcompile.cpp98
-rw-r--r--contrib/libs/hyperscan/src/nfa/goughcompile.h14
-rw-r--r--contrib/libs/hyperscan/src/nfa/goughcompile_internal.h22
-rw-r--r--contrib/libs/hyperscan/src/nfa/goughcompile_reg.cpp6
-rw-r--r--contrib/libs/hyperscan/src/nfa/lbr.c32
-rw-r--r--contrib/libs/hyperscan/src/nfa/lbr.h12
-rw-r--r--contrib/libs/hyperscan/src/nfa/lbr_common_impl.h24
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex.h28
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_64.c146
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_accel.c86
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_accel.h24
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_common_impl.h316
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_compile.cpp1570
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_compile.h64
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_context.h32
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_exceptional.h90
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_internal.h44
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_limits.h2
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_native.c20
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_runtime.h74
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_runtime_impl.h606
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_shuffle.h156
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_simd128.c12
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_simd256.c12
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_simd384.c12
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_simd512.c120
-rw-r--r--contrib/libs/hyperscan/src/nfa/limex_state_impl.h56
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellan.c746
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellan.h10
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellan_common_impl.h18
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellan_internal.h18
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellancompile.cpp320
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellancompile.h72
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellancompile_util.cpp150
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcclellancompile_util.h40
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng.c2800
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng.h166
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng_compile.cpp2128
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng_compile.h98
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng_data.c84
-rw-r--r--contrib/libs/hyperscan/src/nfa/mcsheng_internal.h186
-rw-r--r--contrib/libs/hyperscan/src/nfa/mpv.c44
-rw-r--r--contrib/libs/hyperscan/src/nfa/mpv.h36
-rw-r--r--contrib/libs/hyperscan/src/nfa/mpv_internal.h20
-rw-r--r--contrib/libs/hyperscan/src/nfa/mpvcompile.cpp66
-rw-r--r--contrib/libs/hyperscan/src/nfa/mpvcompile.h24
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_api.h72
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_api_dispatch.c96
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_api_queue.h2
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_build_util.cpp442
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_internal.h112
-rw-r--r--contrib/libs/hyperscan/src/nfa/nfa_kind.h192
-rw-r--r--contrib/libs/hyperscan/src/nfa/rdfa.cpp110
-rw-r--r--contrib/libs/hyperscan/src/nfa/rdfa.h6
-rw-r--r--contrib/libs/hyperscan/src/nfa/rdfa_graph.cpp136
-rw-r--r--contrib/libs/hyperscan/src/nfa/rdfa_graph.h108
-rw-r--r--contrib/libs/hyperscan/src/nfa/rdfa_merge.cpp24
-rw-r--r--contrib/libs/hyperscan/src/nfa/repeat.c72
-rw-r--r--contrib/libs/hyperscan/src/nfa/repeat.h18
-rw-r--r--contrib/libs/hyperscan/src/nfa/repeat_internal.h36
-rw-r--r--contrib/libs/hyperscan/src/nfa/repeatcompile.cpp32
-rw-r--r--contrib/libs/hyperscan/src/nfa/repeatcompile.h4
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng.c1342
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng.h120
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng_defs.h704
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng_impl.h192
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng_impl4.h566
-rw-r--r--contrib/libs/hyperscan/src/nfa/sheng_internal.h138
-rw-r--r--contrib/libs/hyperscan/src/nfa/shengcompile.cpp986
-rw-r--r--contrib/libs/hyperscan/src/nfa/shengcompile.h166
-rw-r--r--contrib/libs/hyperscan/src/nfa/shufti.c1144
-rw-r--r--contrib/libs/hyperscan/src/nfa/shufticompile.cpp154
-rw-r--r--contrib/libs/hyperscan/src/nfa/shufticompile.h20
-rw-r--r--contrib/libs/hyperscan/src/nfa/tamarama.c882
-rw-r--r--contrib/libs/hyperscan/src/nfa/tamarama.h140
-rw-r--r--contrib/libs/hyperscan/src/nfa/tamarama_internal.h210
-rw-r--r--contrib/libs/hyperscan/src/nfa/tamaramacompile.cpp352
-rw-r--r--contrib/libs/hyperscan/src/nfa/tamaramacompile.h192
-rw-r--r--contrib/libs/hyperscan/src/nfa/truffle.c822
-rw-r--r--contrib/libs/hyperscan/src/nfa/truffle.h16
-rw-r--r--contrib/libs/hyperscan/src/nfa/trufflecompile.cpp28
-rw-r--r--contrib/libs/hyperscan/src/nfa/trufflecompile.h6
-rw-r--r--contrib/libs/hyperscan/src/nfa/vermicelli.h150
-rw-r--r--contrib/libs/hyperscan/src/nfa/vermicelli_sse.h110
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng.cpp322
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng.h24
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_anchored_dots.cpp54
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_asserts.cpp110
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_asserts.h12
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_builder.cpp60
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_builder.h14
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_calc_components.cpp200
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_calc_components.h12
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_cyclic_redundancy.cpp68
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_depth.cpp170
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_depth.h52
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_dominators.cpp46
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_dominators.h10
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_dump.h22
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_edge_redundancy.cpp62
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_equivalence.cpp288
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_execute.cpp106
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_execute.h10
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_expr_info.cpp206
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_expr_info.h14
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_extparam.cpp814
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_extparam.h42
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_fixed_width.cpp8
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.cpp1414
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.h98
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_haig.cpp252
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_haig.h8
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_holder.cpp36
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_holder.h190
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_is_equal.cpp60
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_is_equal.h2
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_lbr.cpp112
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_lbr.h28
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_limex.cpp818
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_limex.h50
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.cpp778
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.h38
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.cpp476
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.h50
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_literal_component.cpp32
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_literal_component.h6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_literal_decorated.cpp28
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_mcclellan.cpp258
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_mcclellan_internal.h24
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.cpp394
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.h20
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_netflow.cpp38
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_prefilter.cpp134
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_prune.cpp66
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_puff.cpp50
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_redundancy.cpp56
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_region.cpp188
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_region.h26
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_region_redundancy.cpp24
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_repeat.cpp396
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_repeat.h6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_reports.cpp42
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_reports.h10
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_restructuring.cpp114
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_restructuring.h14
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_revacc.cpp6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_small_literal_set.cpp28
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_som.cpp356
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_som.h18
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_som_add_redundancy.cpp6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_som_util.cpp54
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_som_util.h8
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_split.cpp96
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_split.h24
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_squash.cpp174
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_squash.h20
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_stop.cpp6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.cpp332
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.h14
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_utf8.cpp48
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_utf8.h6
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_util.cpp586
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_util.h276
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_vacuous.cpp44
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_vacuous.h8
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_violet.cpp6094
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_violet.h130
-rw-r--r--contrib/libs/hyperscan/src/nfagraph/ng_width.cpp40
-rw-r--r--contrib/libs/hyperscan/src/parser/ComponentCondReference.h8
-rw-r--r--contrib/libs/hyperscan/src/parser/ComponentRepeat.cpp56
-rw-r--r--contrib/libs/hyperscan/src/parser/ComponentRepeat.h30
-rw-r--r--contrib/libs/hyperscan/src/parser/Parser.h4
-rw-r--r--contrib/libs/hyperscan/src/parser/Parser.rl6288
-rw-r--r--contrib/libs/hyperscan/src/parser/buildstate.cpp10
-rw-r--r--contrib/libs/hyperscan/src/parser/buildstate.h6
-rw-r--r--contrib/libs/hyperscan/src/parser/check_refs.cpp10
-rw-r--r--contrib/libs/hyperscan/src/parser/check_refs.h18
-rw-r--r--contrib/libs/hyperscan/src/parser/control_verbs.h96
-rw-r--r--contrib/libs/hyperscan/src/parser/control_verbs.rl6242
-rw-r--r--contrib/libs/hyperscan/src/parser/parse_error.cpp10
-rw-r--r--contrib/libs/hyperscan/src/parser/parse_error.h18
-rw-r--r--contrib/libs/hyperscan/src/parser/prefilter.cpp36
-rw-r--r--contrib/libs/hyperscan/src/parser/shortcut_literal.cpp20
-rw-r--r--contrib/libs/hyperscan/src/parser/ucp_table.cpp26
-rw-r--r--contrib/libs/hyperscan/src/parser/unsupported.cpp4
-rw-r--r--contrib/libs/hyperscan/src/report.h502
-rw-r--r--contrib/libs/hyperscan/src/rose/block.c460
-rw-r--r--contrib/libs/hyperscan/src/rose/catchup.c278
-rw-r--r--contrib/libs/hyperscan/src/rose/catchup.h156
-rw-r--r--contrib/libs/hyperscan/src/rose/counting_miracle.h12
-rw-r--r--contrib/libs/hyperscan/src/rose/infix.h50
-rw-r--r--contrib/libs/hyperscan/src/rose/init.c14
-rw-r--r--contrib/libs/hyperscan/src/rose/init.h4
-rw-r--r--contrib/libs/hyperscan/src/rose/match.c412
-rw-r--r--contrib/libs/hyperscan/src/rose/match.h310
-rw-r--r--contrib/libs/hyperscan/src/rose/program_runtime.c92
-rw-r--r--contrib/libs/hyperscan/src/rose/program_runtime.h114
-rw-r--r--contrib/libs/hyperscan/src/rose/rose.h26
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build.h28
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_add.cpp542
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_add_internal.h8
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_add_mask.cpp130
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_anchored.cpp336
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_anchored.h54
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_bytecode.cpp5014
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_castle.cpp792
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_castle.h138
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_compile.cpp854
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_convert.cpp128
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_convert.h2
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_dedupe.cpp776
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_dump.h64
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_engine_blob.cpp234
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_engine_blob.h352
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_exclusive.cpp894
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_exclusive.h254
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_groups.cpp1412
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_groups.h114
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_impl.h476
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_infix.cpp44
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_instructions.cpp1292
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_instructions.h4308
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_lit_accel.cpp934
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_lit_accel.h142
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_long_lit.cpp904
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_long_lit.h102
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_lookaround.cpp588
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_lookaround.h38
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_matchers.cpp2104
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_matchers.h258
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_merge.cpp2042
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_merge.h6
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_misc.cpp480
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_misc.h92
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_program.cpp4632
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_program.h574
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_resources.h118
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.cpp1776
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.h22
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_scatter.cpp24
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_scatter.h10
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_util.h6
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_build_width.cpp16
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_common.h26
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_graph.h54
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_in_graph.h34
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_in_util.cpp14
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_in_util.h10
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_internal.h336
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_program.h1274
-rw-r--r--contrib/libs/hyperscan/src/rose/rose_types.h70
-rw-r--r--contrib/libs/hyperscan/src/rose/runtime.h64
-rw-r--r--contrib/libs/hyperscan/src/rose/stream.c504
-rw-r--r--contrib/libs/hyperscan/src/rose/stream_long_lit.h738
-rw-r--r--contrib/libs/hyperscan/src/rose/stream_long_lit_hash.h210
-rw-r--r--contrib/libs/hyperscan/src/rose/validate_mask.h234
-rw-r--r--contrib/libs/hyperscan/src/rose/validate_shufti.h586
-rw-r--r--contrib/libs/hyperscan/src/runtime.c634
-rw-r--r--contrib/libs/hyperscan/src/scratch.c200
-rw-r--r--contrib/libs/hyperscan/src/scratch.h156
-rw-r--r--contrib/libs/hyperscan/src/smallwrite/smallwrite_build.cpp1398
-rw-r--r--contrib/libs/hyperscan/src/smallwrite/smallwrite_build.h52
-rw-r--r--contrib/libs/hyperscan/src/som/slot_manager.cpp22
-rw-r--r--contrib/libs/hyperscan/src/som/slot_manager.h24
-rw-r--r--contrib/libs/hyperscan/src/som/slot_manager_internal.h14
-rw-r--r--contrib/libs/hyperscan/src/som/som.h14
-rw-r--r--contrib/libs/hyperscan/src/som/som_operation.h168
-rw-r--r--contrib/libs/hyperscan/src/som/som_runtime.c92
-rw-r--r--contrib/libs/hyperscan/src/som/som_runtime.h12
-rw-r--r--contrib/libs/hyperscan/src/stream_compress.c260
-rw-r--r--contrib/libs/hyperscan/src/stream_compress.h102
-rw-r--r--contrib/libs/hyperscan/src/stream_compress_impl.h370
-rw-r--r--contrib/libs/hyperscan/src/ue2common.h38
-rw-r--r--contrib/libs/hyperscan/src/util/accel_scheme.h102
-rw-r--r--contrib/libs/hyperscan/src/util/alloc.h60
-rw-r--r--contrib/libs/hyperscan/src/util/arch.h86
-rw-r--r--contrib/libs/hyperscan/src/util/bitfield.h98
-rw-r--r--contrib/libs/hyperscan/src/util/bitutils.h186
-rw-r--r--contrib/libs/hyperscan/src/util/boundary_reports.h6
-rw-r--r--contrib/libs/hyperscan/src/util/bytecode_ptr.h322
-rw-r--r--contrib/libs/hyperscan/src/util/charreach.cpp2
-rw-r--r--contrib/libs/hyperscan/src/util/charreach.h68
-rw-r--r--contrib/libs/hyperscan/src/util/charreach_util.h4
-rw-r--r--contrib/libs/hyperscan/src/util/clique.cpp260
-rw-r--r--contrib/libs/hyperscan/src/util/clique.h120
-rw-r--r--contrib/libs/hyperscan/src/util/compare.h28
-rw-r--r--contrib/libs/hyperscan/src/util/container.h58
-rw-r--r--contrib/libs/hyperscan/src/util/copybytes.h162
-rw-r--r--contrib/libs/hyperscan/src/util/cpuid_flags.c70
-rw-r--r--contrib/libs/hyperscan/src/util/cpuid_flags.h20
-rw-r--r--contrib/libs/hyperscan/src/util/cpuid_inline.h422
-rw-r--r--contrib/libs/hyperscan/src/util/depth.h112
-rw-r--r--contrib/libs/hyperscan/src/util/determinise.h78
-rw-r--r--contrib/libs/hyperscan/src/util/dump_charclass.h32
-rw-r--r--contrib/libs/hyperscan/src/util/exhaust.h6
-rw-r--r--contrib/libs/hyperscan/src/util/fatbit.h24
-rw-r--r--contrib/libs/hyperscan/src/util/fatbit_build.cpp88
-rw-r--r--contrib/libs/hyperscan/src/util/fatbit_build.h96
-rw-r--r--contrib/libs/hyperscan/src/util/flat_containers.h1328
-rw-r--r--contrib/libs/hyperscan/src/util/graph.h252
-rw-r--r--contrib/libs/hyperscan/src/util/graph_range.h2
-rw-r--r--contrib/libs/hyperscan/src/util/graph_small_color_map.h320
-rw-r--r--contrib/libs/hyperscan/src/util/hash.h414
-rw-r--r--contrib/libs/hyperscan/src/util/hash_dynamic_bitset.h192
-rw-r--r--contrib/libs/hyperscan/src/util/insertion_ordered.h736
-rw-r--r--contrib/libs/hyperscan/src/util/intrinsics.h132
-rw-r--r--contrib/libs/hyperscan/src/util/join.h12
-rw-r--r--contrib/libs/hyperscan/src/util/make_unique.h6
-rw-r--r--contrib/libs/hyperscan/src/util/masked_move.c8
-rw-r--r--contrib/libs/hyperscan/src/util/masked_move.h24
-rw-r--r--contrib/libs/hyperscan/src/util/math.h100
-rw-r--r--contrib/libs/hyperscan/src/util/multibit.c2
-rw-r--r--contrib/libs/hyperscan/src/util/multibit.h160
-rw-r--r--contrib/libs/hyperscan/src/util/multibit_build.cpp68
-rw-r--r--contrib/libs/hyperscan/src/util/multibit_build.h54
-rw-r--r--contrib/libs/hyperscan/src/util/multibit_compress.h408
-rw-r--r--contrib/libs/hyperscan/src/util/multibit_internal.h8
-rw-r--r--contrib/libs/hyperscan/src/util/noncopyable.h100
-rw-r--r--contrib/libs/hyperscan/src/util/operators.h120
-rw-r--r--contrib/libs/hyperscan/src/util/partitioned_set.h16
-rw-r--r--contrib/libs/hyperscan/src/util/popcount.h26
-rw-r--r--contrib/libs/hyperscan/src/util/queue_index_factory.h6
-rw-r--r--contrib/libs/hyperscan/src/util/report.h116
-rw-r--r--contrib/libs/hyperscan/src/util/report_manager.cpp54
-rw-r--r--contrib/libs/hyperscan/src/util/report_manager.h44
-rw-r--r--contrib/libs/hyperscan/src/util/simd_types.h24
-rw-r--r--contrib/libs/hyperscan/src/util/simd_utils.c124
-rw-r--r--contrib/libs/hyperscan/src/util/simd_utils.h982
-rw-r--r--contrib/libs/hyperscan/src/util/small_vector.h140
-rw-r--r--contrib/libs/hyperscan/src/util/state_compress.c44
-rw-r--r--contrib/libs/hyperscan/src/util/target_info.cpp20
-rw-r--r--contrib/libs/hyperscan/src/util/target_info.h4
-rw-r--r--contrib/libs/hyperscan/src/util/ue2_graph.h2462
-rw-r--r--contrib/libs/hyperscan/src/util/ue2string.cpp126
-rw-r--r--contrib/libs/hyperscan/src/util/ue2string.h230
-rw-r--r--contrib/libs/hyperscan/src/util/uniform_ops.h80
-rw-r--r--contrib/libs/hyperscan/src/util/unordered.h106
-rw-r--r--contrib/libs/hyperscan/src/util/verify_types.h78
-rw-r--r--contrib/libs/hyperscan/ya.make50
-rw-r--r--contrib/libs/ya.make2
-rw-r--r--contrib/python/ipython/ya.make2
-rw-r--r--contrib/python/jedi/ya.make2
-rw-r--r--contrib/python/pickleshare/ya.make4
-rw-r--r--contrib/python/prompt-toolkit/py2/LICENSE54
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py38
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py256
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py176
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py2208
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py184
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py16
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py114
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py34
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py78
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py282
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py10
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py122
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py200
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py112
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py152
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py814
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py168
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py130
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py524
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py112
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py4
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py64
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py22
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py362
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py812
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py62
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py1308
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py46
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py92
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py214
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py162
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py160
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py58
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py184
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py528
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py82
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py46
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py324
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py72
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py388
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py370
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py70
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py70
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py236
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py214
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py1746
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py2
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py574
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py612
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py254
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py42
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py1856
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py430
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py116
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py200
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py68
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py206
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py100
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py1978
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py774
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py184
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py84
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py234
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py848
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py58
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py570
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py208
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py286
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py376
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py248
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py86
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py270
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py112
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py944
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py72
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py74
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py838
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py80
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py782
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py590
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py530
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py868
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py302
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py126
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py310
-rw-r--r--contrib/python/prompt-toolkit/py2/ya.make194
-rw-r--r--contrib/python/prompt-toolkit/ya.make6
-rw-r--r--contrib/python/wcwidth/LICENSE42
-rw-r--r--contrib/python/wcwidth/wcwidth/__init__.py2
-rw-r--r--contrib/python/wcwidth/wcwidth/wcwidth.py288
-rw-r--r--contrib/python/wcwidth/ya.make22
-rw-r--r--contrib/python/ya.make4
511 files changed, 69619 insertions, 69619 deletions
diff --git a/contrib/libs/hyperscan/include/boost-patched/graph/reverse_graph.hpp b/contrib/libs/hyperscan/include/boost-patched/graph/reverse_graph.hpp
index e1333f2638f..8f98a1d5fff 100644
--- a/contrib/libs/hyperscan/include/boost-patched/graph/reverse_graph.hpp
+++ b/contrib/libs/hyperscan/include/boost-patched/graph/reverse_graph.hpp
@@ -1,27 +1,27 @@
-#ifndef REVERSE_GRAPH_PATCHED_H_
-#define REVERSE_GRAPH_PATCHED_H_
-
-#include <boost/version.hpp>
-
-#include <boost/graph/reverse_graph.hpp>
-
-#if defined(BOOST_REVGRAPH_PATCH)
-
-// Boost 1.62.0 does not implement degree() in reverse_graph which is required
-// by BidirectionalGraph, so add it.
-
-namespace boost {
-
-template <class BidirectionalGraph, class GRef>
-inline typename graph_traits<BidirectionalGraph>::degree_size_type
-degree(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
- const reverse_graph<BidirectionalGraph,GRef>& g)
-{
- return degree(u, g.m_g);
-}
-
-} // namespace boost
-
-#endif // Boost 1.62.0
-
-#endif
+#ifndef REVERSE_GRAPH_PATCHED_H_
+#define REVERSE_GRAPH_PATCHED_H_
+
+#include <boost/version.hpp>
+
+#include <boost/graph/reverse_graph.hpp>
+
+#if defined(BOOST_REVGRAPH_PATCH)
+
+// Boost 1.62.0 does not implement degree() in reverse_graph which is required
+// by BidirectionalGraph, so add it.
+
+namespace boost {
+
+template <class BidirectionalGraph, class GRef>
+inline typename graph_traits<BidirectionalGraph>::degree_size_type
+degree(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
+ const reverse_graph<BidirectionalGraph,GRef>& g)
+{
+ return degree(u, g.m_g);
+}
+
+} // namespace boost
+
+#endif // Boost 1.62.0
+
+#endif
diff --git a/contrib/libs/hyperscan/src/alloc.c b/contrib/libs/hyperscan/src/alloc.c
index 7cb03ee352f..e27649bce87 100644
--- a/contrib/libs/hyperscan/src/alloc.c
+++ b/contrib/libs/hyperscan/src/alloc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -67,7 +67,7 @@ hs_free_t normalise_free(hs_free_t f) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t allocfunc, hs_free_t freefunc) {
+hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t allocfunc, hs_free_t freefunc) {
hs_set_database_allocator(allocfunc, freefunc);
hs_set_misc_allocator(allocfunc, freefunc);
hs_set_stream_allocator(allocfunc, freefunc);
@@ -77,8 +77,8 @@ hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t allocfunc, hs_free_t freefunc) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t allocfunc,
- hs_free_t freefunc) {
+hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t allocfunc,
+ hs_free_t freefunc) {
hs_database_alloc = normalise_alloc(allocfunc);
hs_database_free = normalise_free(freefunc);
@@ -86,8 +86,8 @@ hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t allocfunc,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t allocfunc,
- hs_free_t freefunc) {
+hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t allocfunc,
+ hs_free_t freefunc) {
hs_misc_alloc = normalise_alloc(allocfunc);
hs_misc_free = normalise_free(freefunc);
@@ -95,8 +95,8 @@ hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t allocfunc,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t allocfunc,
- hs_free_t freefunc) {
+hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t allocfunc,
+ hs_free_t freefunc) {
hs_scratch_alloc = normalise_alloc(allocfunc);
hs_scratch_free = normalise_free(freefunc);
@@ -104,8 +104,8 @@ hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t allocfunc,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_set_stream_allocator(hs_alloc_t allocfunc,
- hs_free_t freefunc) {
+hs_error_t HS_CDECL hs_set_stream_allocator(hs_alloc_t allocfunc,
+ hs_free_t freefunc) {
hs_stream_alloc = normalise_alloc(allocfunc);
hs_stream_free = normalise_free(freefunc);
diff --git a/contrib/libs/hyperscan/src/compiler/asserts.cpp b/contrib/libs/hyperscan/src/compiler/asserts.cpp
index 12f5dbc5bab..444422260c7 100644
--- a/contrib/libs/hyperscan/src/compiler/asserts.cpp
+++ b/contrib/libs/hyperscan/src/compiler/asserts.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,8 +42,8 @@
* word-to-word and word-to-nonword) are dropped.
*/
#include "asserts.h"
-
-#include "compiler/compiler.h"
+
+#include "compiler/compiler.h"
#include "nfagraph/ng.h"
#include "nfagraph/ng_prune.h"
#include "nfagraph/ng_redundancy.h"
@@ -117,13 +117,13 @@ u32 conjunct(u32 flags1, u32 flags2) {
typedef map<pair<NFAVertex, NFAVertex>, NFAEdge> edge_cache_t;
static
-void replaceAssertVertex(NGHolder &g, NFAVertex t, const ExpressionInfo &expr,
- edge_cache_t &edge_cache, u32 &assert_edge_count) {
- DEBUG_PRINTF("replacing assert vertex %zu\n", g[t].index);
+void replaceAssertVertex(NGHolder &g, NFAVertex t, const ExpressionInfo &expr,
+ edge_cache_t &edge_cache, u32 &assert_edge_count) {
+ DEBUG_PRINTF("replacing assert vertex %zu\n", g[t].index);
const u32 flags = g[t].assert_flags;
- DEBUG_PRINTF("consider assert vertex %zu with flags %u\n", g[t].index,
- flags);
+ DEBUG_PRINTF("consider assert vertex %zu with flags %u\n", g[t].index,
+ flags);
// Wire up all the predecessors to all the successors.
@@ -144,7 +144,7 @@ void replaceAssertVertex(NGHolder &g, NFAVertex t, const ExpressionInfo &expr,
for (const auto &outEdge : out_edges_range(t, g)) {
NFAVertex v = target(outEdge, g);
- DEBUG_PRINTF("consider path [%zu,%zu,%zu]\n", g[u].index,
+ DEBUG_PRINTF("consider path [%zu,%zu,%zu]\n", g[u].index,
g[t].index, g[v].index);
if (v == t) {
@@ -175,16 +175,16 @@ void replaceAssertVertex(NGHolder &g, NFAVertex t, const ExpressionInfo &expr,
auto cache_key = make_pair(u, v);
auto ecit = edge_cache.find(cache_key);
if (ecit == edge_cache.end()) {
- DEBUG_PRINTF("adding edge %zu %zu\n", g[u].index, g[v].index);
- NFAEdge e = add_edge(u, v, g);
+ DEBUG_PRINTF("adding edge %zu %zu\n", g[u].index, g[v].index);
+ NFAEdge e = add_edge(u, v, g);
edge_cache.emplace(cache_key, e);
g[e].assert_flags = flags;
if (++assert_edge_count > MAX_ASSERT_EDGES) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
} else {
NFAEdge e = ecit->second;
- DEBUG_PRINTF("updating edge %zu %zu [a %zu]\n", g[u].index,
+ DEBUG_PRINTF("updating edge %zu %zu [a %zu]\n", g[u].index,
g[v].index, g[t].index);
// Edge already exists.
u32 &e_flags = g[e].assert_flags;
@@ -201,29 +201,29 @@ void replaceAssertVertex(NGHolder &g, NFAVertex t, const ExpressionInfo &expr,
}
static
-void setReportId(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
- NFAVertex v, s32 adj) {
+void setReportId(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
+ NFAVertex v, s32 adj) {
// Don't try and set the report ID of a special vertex.
assert(!is_special(v, g));
// There should be no reports set already.
assert(g[v].reports.empty());
- Report r = rm.getBasicInternalReport(expr, adj);
+ Report r = rm.getBasicInternalReport(expr, adj);
g[v].reports.insert(rm.getInternalId(r));
- DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj);
+ DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj);
}
static
-void checkForMultilineStart(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
+void checkForMultilineStart(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
vector<NFAEdge> dead;
for (auto v : adjacent_vertices_range(g.start, g)) {
if (!(g[v].assert_flags & POS_FLAG_MULTILINE_START)) {
continue;
}
- DEBUG_PRINTF("mls %zu %08x\n", g[v].index, g[v].assert_flags);
+ DEBUG_PRINTF("mls %zu %08x\n", g[v].index, g[v].assert_flags);
/* we have found a multi-line start (maybe more than one) */
@@ -241,7 +241,7 @@ void checkForMultilineStart(ReportManager &rm, NGHolder &g,
for (const auto &e : dead) {
NFAVertex dummy = add_vertex(g);
g[dummy].char_reach.setall();
- setReportId(rm, g, expr, dummy, -1);
+ setReportId(rm, g, expr, dummy, -1);
add_edge(source(e, g), dummy, g[e], g);
add_edge(dummy, g.accept, g);
}
@@ -266,8 +266,8 @@ bool hasAssertVertices(const NGHolder &g) {
* Remove the horrors that are the temporary assert vertices which arise from
* our construction method. Allows the rest of our code base to live in
* blissful ignorance of their existence. */
-void removeAssertVertices(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
+void removeAssertVertices(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
size_t num = 0;
DEBUG_PRINTF("before: graph has %zu vertices\n", num_vertices(g));
@@ -289,19 +289,19 @@ void removeAssertVertices(ReportManager &rm, NGHolder &g,
for (auto v : vertices_range(g)) {
if (g[v].assert_flags & WORDBOUNDARY_FLAGS) {
- replaceAssertVertex(g, v, expr, edge_cache, assert_edge_count);
+ replaceAssertVertex(g, v, expr, edge_cache, assert_edge_count);
num++;
}
}
- checkForMultilineStart(rm, g, expr);
+ checkForMultilineStart(rm, g, expr);
if (num) {
DEBUG_PRINTF("resolved %zu assert vertices\n", num);
pruneUseless(g);
pruneEmptyVertices(g);
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
}
DEBUG_PRINTF("after: graph has %zu vertices\n", num_vertices(g));
diff --git a/contrib/libs/hyperscan/src/compiler/asserts.h b/contrib/libs/hyperscan/src/compiler/asserts.h
index 45f2534240d..b4d64c6c9a7 100644
--- a/contrib/libs/hyperscan/src/compiler/asserts.h
+++ b/contrib/libs/hyperscan/src/compiler/asserts.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,9 +35,9 @@
namespace ue2 {
-class ExpressionInfo;
+class ExpressionInfo;
class ReportManager;
-class NGHolder;
+class NGHolder;
/** \brief Convert temporary assert vertices (from construction method) to
* edge-based flags.
@@ -45,8 +45,8 @@ class NGHolder;
* Remove the horrors that are the temporary assert vertices which arise from
* our construction method. Allows the rest of our code base to live in
* blissful ignorance of their existence. */
-void removeAssertVertices(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr);
+void removeAssertVertices(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/compiler/compiler.cpp b/contrib/libs/hyperscan/src/compiler/compiler.cpp
index 86974f92814..5751bd64f43 100644
--- a/contrib/libs/hyperscan/src/compiler/compiler.cpp
+++ b/contrib/libs/hyperscan/src/compiler/compiler.cpp
@@ -29,10 +29,10 @@
/** \file
* \brief Compiler front-end interface.
*/
-#include "allocator.h"
+#include "allocator.h"
#include "asserts.h"
#include "compiler.h"
-#include "crc32.h"
+#include "crc32.h"
#include "database.h"
#include "grey.h"
#include "hs_internal.h"
@@ -58,7 +58,7 @@
#include "rose/rose_build.h"
#include "rose/rose_internal.h"
#include "som/slot_manager_dump.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/compile_error.h"
#include "util/target_info.h"
#include "util/verify_types.h"
@@ -80,9 +80,9 @@ static
void validateExt(const hs_expr_ext &ext) {
static const unsigned long long ALL_EXT_FLAGS = HS_EXT_FLAG_MIN_OFFSET |
HS_EXT_FLAG_MAX_OFFSET |
- HS_EXT_FLAG_MIN_LENGTH |
- HS_EXT_FLAG_EDIT_DISTANCE |
- HS_EXT_FLAG_HAMMING_DISTANCE;
+ HS_EXT_FLAG_MIN_LENGTH |
+ HS_EXT_FLAG_EDIT_DISTANCE |
+ HS_EXT_FLAG_HAMMING_DISTANCE;
if (ext.flags & ~ALL_EXT_FLAGS) {
throw CompileError("Invalid hs_expr_ext flag set.");
}
@@ -100,13 +100,13 @@ void validateExt(const hs_expr_ext &ext) {
throw CompileError("In hs_expr_ext, min_length must be less than or "
"equal to max_offset.");
}
-
- if ((ext.flags & HS_EXT_FLAG_EDIT_DISTANCE) &&
- (ext.flags & HS_EXT_FLAG_HAMMING_DISTANCE)) {
- throw CompileError("In hs_expr_ext, cannot have both edit distance and "
- "Hamming distance.");
- }
-
+
+ if ((ext.flags & HS_EXT_FLAG_EDIT_DISTANCE) &&
+ (ext.flags & HS_EXT_FLAG_HAMMING_DISTANCE)) {
+ throw CompileError("In hs_expr_ext, cannot have both edit distance and "
+ "Hamming distance.");
+ }
+
}
void ParsedLitExpression::parseLiteral(const char *expression, size_t len,
@@ -150,10 +150,10 @@ ParsedLitExpression::ParsedLitExpression(unsigned index_in,
}
ParsedExpression::ParsedExpression(unsigned index_in, const char *expression,
- unsigned flags, ReportID report,
+ unsigned flags, ReportID report,
const hs_expr_ext *ext)
- : expr(index_in, flags & HS_FLAG_ALLOWEMPTY, flags & HS_FLAG_SINGLEMATCH,
- false, flags & HS_FLAG_PREFILTER, SOM_NONE, report, 0, MAX_OFFSET,
+ : expr(index_in, flags & HS_FLAG_ALLOWEMPTY, flags & HS_FLAG_SINGLEMATCH,
+ false, flags & HS_FLAG_PREFILTER, SOM_NONE, report, 0, MAX_OFFSET,
0, 0, 0, flags & HS_FLAG_QUIET) {
// We disallow SOM + Quiet.
if ((flags & HS_FLAG_QUIET) && (flags & HS_FLAG_SOM_LEFTMOST)) {
@@ -165,7 +165,7 @@ ParsedExpression::ParsedExpression(unsigned index_in, const char *expression,
component = parse(expression, mode);
- expr.utf8 = mode.utf8; /* utf8 may be set by parse() */
+ expr.utf8 = mode.utf8; /* utf8 may be set by parse() */
const size_t len = strlen(expression);
if (expr.utf8 && !isValidUtf8(expression, len)) {
@@ -196,7 +196,7 @@ ParsedExpression::ParsedExpression(unsigned index_in, const char *expression,
// Set SOM type.
if (flags & HS_FLAG_SOM_LEFTMOST) {
- expr.som = SOM_LEFT;
+ expr.som = SOM_LEFT;
}
// Set extended parameters, if we have them.
@@ -205,32 +205,32 @@ ParsedExpression::ParsedExpression(unsigned index_in, const char *expression,
validateExt(*ext);
if (ext->flags & HS_EXT_FLAG_MIN_OFFSET) {
- expr.min_offset = ext->min_offset;
+ expr.min_offset = ext->min_offset;
}
if (ext->flags & HS_EXT_FLAG_MAX_OFFSET) {
- expr.max_offset = ext->max_offset;
+ expr.max_offset = ext->max_offset;
}
if (ext->flags & HS_EXT_FLAG_MIN_LENGTH) {
- expr.min_length = ext->min_length;
+ expr.min_length = ext->min_length;
+ }
+ if (ext->flags & HS_EXT_FLAG_EDIT_DISTANCE) {
+ expr.edit_distance = ext->edit_distance;
+ }
+ if (ext->flags & HS_EXT_FLAG_HAMMING_DISTANCE) {
+ expr.hamm_distance = ext->hamming_distance;
}
- if (ext->flags & HS_EXT_FLAG_EDIT_DISTANCE) {
- expr.edit_distance = ext->edit_distance;
- }
- if (ext->flags & HS_EXT_FLAG_HAMMING_DISTANCE) {
- expr.hamm_distance = ext->hamming_distance;
- }
}
// These are validated in validateExt, so an error will already have been
// thrown if these conditions don't hold.
- assert(expr.max_offset >= expr.min_offset);
- assert(expr.max_offset >= expr.min_length);
+ assert(expr.max_offset >= expr.min_offset);
+ assert(expr.max_offset >= expr.min_length);
// Since prefiltering and SOM aren't supported together, we must squash any
// min_length constraint as well.
- if (flags & HS_FLAG_PREFILTER && expr.min_length) {
+ if (flags & HS_FLAG_PREFILTER && expr.min_length) {
DEBUG_PRINTF("prefiltering mode: squashing min_length constraint\n");
- expr.min_length = 0;
+ expr.min_length = 0;
}
}
@@ -239,25 +239,25 @@ ParsedExpression::ParsedExpression(unsigned index_in, const char *expression,
* \brief Dumps the parse tree to screen in debug mode and to disk in dump
* mode.
*/
-void dumpExpression(UNUSED const ParsedExpression &pe,
+void dumpExpression(UNUSED const ParsedExpression &pe,
UNUSED const char *stage, UNUSED const Grey &grey) {
#if defined(DEBUG)
- DEBUG_PRINTF("===== Rule ID: %u (expression index: %u) =====\n",
- pe.expr.report, pe.expr.index);
+ DEBUG_PRINTF("===== Rule ID: %u (expression index: %u) =====\n",
+ pe.expr.report, pe.expr.index);
ostringstream debug_tree;
- dumpTree(debug_tree, pe.component.get());
+ dumpTree(debug_tree, pe.component.get());
printf("%s\n", debug_tree.str().c_str());
#endif // DEBUG
#if defined(DUMP_SUPPORT)
if (grey.dumpFlags & Grey::DUMP_PARSE) {
stringstream ss;
- ss << grey.dumpPath << "Expr_" << pe.expr.index << "_componenttree_"
+ ss << grey.dumpPath << "Expr_" << pe.expr.index << "_componenttree_"
<< stage << ".txt";
ofstream out(ss.str().c_str());
- out << "Component Tree for " << pe.expr.report << endl;
- dumpTree(out, pe.component.get());
- if (pe.expr.utf8) {
+ out << "Component Tree for " << pe.expr.report << endl;
+ dumpTree(out, pe.component.get());
+ if (pe.expr.utf8) {
out << "UTF8 mode" << endl;
}
}
@@ -267,13 +267,13 @@ void dumpExpression(UNUSED const ParsedExpression &pe,
/** \brief Run Component tree optimisations on \a expr. */
static
-void optimise(ParsedExpression &pe) {
- if (pe.expr.min_length || pe.expr.som) {
+void optimise(ParsedExpression &pe) {
+ if (pe.expr.min_length || pe.expr.som) {
return;
}
DEBUG_PRINTF("optimising\n");
- pe.component->optimise(true /* root is connected to sds */);
+ pe.component->optimise(true /* root is connected to sds */);
}
void addExpression(NG &ng, unsigned index, const char *expression,
@@ -329,34 +329,34 @@ void addExpression(NG &ng, unsigned index, const char *expression,
// Do per-expression processing: errors here will result in an exception
// being thrown up to our caller
- ParsedExpression pe(index, expression, flags, id, ext);
- dumpExpression(pe, "orig", cc.grey);
+ ParsedExpression pe(index, expression, flags, id, ext);
+ dumpExpression(pe, "orig", cc.grey);
// Apply prefiltering transformations if desired.
- if (pe.expr.prefilter) {
- prefilterTree(pe.component, ParseMode(flags));
- dumpExpression(pe, "prefiltered", cc.grey);
+ if (pe.expr.prefilter) {
+ prefilterTree(pe.component, ParseMode(flags));
+ dumpExpression(pe, "prefiltered", cc.grey);
}
// Expressions containing zero-width assertions and other extended pcre
// types aren't supported yet. This call will throw a ParseError exception
// if the component tree contains such a construct.
- checkUnsupported(*pe.component);
+ checkUnsupported(*pe.component);
- pe.component->checkEmbeddedStartAnchor(true);
- pe.component->checkEmbeddedEndAnchor(true);
+ pe.component->checkEmbeddedStartAnchor(true);
+ pe.component->checkEmbeddedEndAnchor(true);
if (cc.grey.optimiseComponentTree) {
- optimise(pe);
- dumpExpression(pe, "opt", cc.grey);
+ optimise(pe);
+ dumpExpression(pe, "opt", cc.grey);
}
DEBUG_PRINTF("component=%p, nfaId=%u, reportId=%u\n",
- pe.component.get(), pe.expr.index, pe.expr.report);
+ pe.component.get(), pe.expr.index, pe.expr.report);
// You can only use the SOM flags if you've also specified an SOM
// precision mode.
- if (pe.expr.som != SOM_NONE && cc.streaming && !ng.ssm.somPrecision()) {
+ if (pe.expr.som != SOM_NONE && cc.streaming && !ng.ssm.somPrecision()) {
throw CompileError("To use a SOM expression flag in streaming mode, "
"an SOM precision mode (e.g. "
"HS_MODE_SOM_HORIZON_LARGE) must be specified.");
@@ -364,25 +364,25 @@ void addExpression(NG &ng, unsigned index, const char *expression,
// If this expression is a literal, we can feed it directly to Rose rather
// than building the NFA graph.
- if (shortcutLiteral(ng, pe)) {
+ if (shortcutLiteral(ng, pe)) {
DEBUG_PRINTF("took literal short cut\n");
return;
}
- auto built_expr = buildGraph(ng.rm, cc, pe);
- if (!built_expr.g) {
+ auto built_expr = buildGraph(ng.rm, cc, pe);
+ if (!built_expr.g) {
DEBUG_PRINTF("NFA build failed on ID %u, but no exception was "
- "thrown.\n", pe.expr.report);
+ "thrown.\n", pe.expr.report);
throw CompileError("Internal error.");
}
- if (!pe.expr.allow_vacuous && matches_everywhere(*built_expr.g)) {
+ if (!pe.expr.allow_vacuous && matches_everywhere(*built_expr.g)) {
throw CompileError("Pattern matches empty buffer; use "
"HS_FLAG_ALLOWEMPTY to enable support.");
}
- if (!ng.addGraph(built_expr.expr, std::move(built_expr.g))) {
- DEBUG_PRINTF("NFA addGraph failed on ID %u.\n", pe.expr.report);
+ if (!ng.addGraph(built_expr.expr, std::move(built_expr.g))) {
+ DEBUG_PRINTF("NFA addGraph failed on ID %u.\n", pe.expr.report);
throw CompileError("Error compiling expression.");
}
}
@@ -430,7 +430,7 @@ void addLitExpression(NG &ng, unsigned index, const char *expression,
}
static
-bytecode_ptr<RoseEngine> generateRoseEngine(NG &ng) {
+bytecode_ptr<RoseEngine> generateRoseEngine(NG &ng) {
const u32 minWidth =
ng.minWidth.is_finite() ? verify_u32(ng.minWidth) : ROSE_BOUND_INF;
auto rose = ng.rose->buildRose(minWidth);
@@ -455,54 +455,54 @@ platform_t target_to_platform(const target_t &target_info) {
if (!target_info.has_avx2()) {
p |= HS_PLATFORM_NOAVX2;
}
- if (!target_info.has_avx512()) {
- p |= HS_PLATFORM_NOAVX512;
- }
+ if (!target_info.has_avx512()) {
+ p |= HS_PLATFORM_NOAVX512;
+ }
if (!target_info.has_avx512vbmi()) {
p |= HS_PLATFORM_NOAVX512VBMI;
}
return p;
}
-/** \brief Encapsulate the given bytecode (RoseEngine) in a newly-allocated
- * \ref hs_database, ensuring that it is padded correctly to give cacheline
- * alignment. */
-static
-hs_database_t *dbCreate(const char *in_bytecode, size_t len, u64a platform) {
- size_t db_len = sizeof(struct hs_database) + len;
- DEBUG_PRINTF("db size %zu\n", db_len);
- DEBUG_PRINTF("db platform %llx\n", platform);
-
- struct hs_database *db = (struct hs_database *)hs_database_alloc(db_len);
- if (hs_check_alloc(db) != HS_SUCCESS) {
- hs_database_free(db);
- return nullptr;
- }
-
- // So that none of our database is uninitialized
- memset(db, 0, db_len);
-
- // we need to align things manually
- size_t shift = (uintptr_t)db->bytes & 0x3f;
- DEBUG_PRINTF("shift is %zu\n", shift);
-
- db->bytecode = offsetof(struct hs_database, bytes) - shift;
- char *bytecode = (char *)db + db->bytecode;
- assert(ISALIGNED_CL(bytecode));
-
- db->magic = HS_DB_MAGIC;
- db->version = HS_DB_VERSION;
- db->length = len;
- db->platform = platform;
-
- // Copy bytecode
- memcpy(bytecode, in_bytecode, len);
-
- db->crc32 = Crc32c_ComputeBuf(0, bytecode, db->length);
- return db;
-}
-
-
+/** \brief Encapsulate the given bytecode (RoseEngine) in a newly-allocated
+ * \ref hs_database, ensuring that it is padded correctly to give cacheline
+ * alignment. */
+static
+hs_database_t *dbCreate(const char *in_bytecode, size_t len, u64a platform) {
+ size_t db_len = sizeof(struct hs_database) + len;
+ DEBUG_PRINTF("db size %zu\n", db_len);
+ DEBUG_PRINTF("db platform %llx\n", platform);
+
+ struct hs_database *db = (struct hs_database *)hs_database_alloc(db_len);
+ if (hs_check_alloc(db) != HS_SUCCESS) {
+ hs_database_free(db);
+ return nullptr;
+ }
+
+ // So that none of our database is uninitialized
+ memset(db, 0, db_len);
+
+ // we need to align things manually
+ size_t shift = (uintptr_t)db->bytes & 0x3f;
+ DEBUG_PRINTF("shift is %zu\n", shift);
+
+ db->bytecode = offsetof(struct hs_database, bytes) - shift;
+ char *bytecode = (char *)db + db->bytecode;
+ assert(ISALIGNED_CL(bytecode));
+
+ db->magic = HS_DB_MAGIC;
+ db->version = HS_DB_VERSION;
+ db->length = len;
+ db->platform = platform;
+
+ // Copy bytecode
+ memcpy(bytecode, in_bytecode, len);
+
+ db->crc32 = Crc32c_ComputeBuf(0, bytecode, db->length);
+ return db;
+}
+
+
struct hs_database *build(NG &ng, unsigned int *length, u8 pureFlag) {
assert(length);
@@ -513,7 +513,7 @@ struct hs_database *build(NG &ng, unsigned int *length, u8 pureFlag) {
if (!rose) {
throw CompileError("Unable to generate bytecode.");
}
- *length = rose.size();
+ *length = rose.size();
if (!*length) {
DEBUG_PRINTF("RoseEngine has zero length\n");
assert(0);
@@ -594,42 +594,42 @@ bool isSupported(const Component &c) {
}
#endif
-BuiltExpression buildGraph(ReportManager &rm, const CompileContext &cc,
- const ParsedExpression &pe) {
- assert(isSupported(*pe.component));
+BuiltExpression buildGraph(ReportManager &rm, const CompileContext &cc,
+ const ParsedExpression &pe) {
+ assert(isSupported(*pe.component));
- const auto builder = makeNFABuilder(rm, cc, pe);
+ const auto builder = makeNFABuilder(rm, cc, pe);
assert(builder);
// Set up START and ACCEPT states; retrieve the special states
- const auto bs = makeGlushkovBuildState(*builder, pe.expr.prefilter);
+ const auto bs = makeGlushkovBuildState(*builder, pe.expr.prefilter);
// Map position IDs to characters/components
- pe.component->notePositions(*bs);
+ pe.component->notePositions(*bs);
// Wire the start dotstar state to the firsts
- connectInitialStates(*bs, pe);
+ connectInitialStates(*bs, pe);
DEBUG_PRINTF("wire up body of expr\n");
// Build the rest of the FOLLOW set
vector<PositionInfo> initials = {builder->getStartDotStar(),
builder->getStart()};
- pe.component->buildFollowSet(*bs, initials);
+ pe.component->buildFollowSet(*bs, initials);
// Wire the lasts to the accept state
- connectFinalStates(*bs, pe);
+ connectFinalStates(*bs, pe);
// Create our edges
bs->buildEdges();
- BuiltExpression built_expr = builder->getGraph();
- assert(built_expr.g);
+ BuiltExpression built_expr = builder->getGraph();
+ assert(built_expr.g);
- dumpDotWrapper(*built_expr.g, built_expr.expr, "00_before_asserts",
- cc.grey);
- removeAssertVertices(rm, *built_expr.g, built_expr.expr);
+ dumpDotWrapper(*built_expr.g, built_expr.expr, "00_before_asserts",
+ cc.grey);
+ removeAssertVertices(rm, *built_expr.g, built_expr.expr);
- return built_expr;
+ return built_expr;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/compiler/compiler.h b/contrib/libs/hyperscan/src/compiler/compiler.h
index 36986faaae0..b42cb1425b4 100644
--- a/contrib/libs/hyperscan/src/compiler/compiler.h
+++ b/contrib/libs/hyperscan/src/compiler/compiler.h
@@ -35,9 +35,9 @@
#include "ue2common.h"
#include "database.h"
-#include "compiler/expression_info.h"
+#include "compiler/expression_info.h"
#include "parser/Component.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include "util/ue2string.h"
#include <memory>
@@ -51,21 +51,21 @@ struct CompileContext;
struct Grey;
struct target_t;
class NG;
-class NGHolder;
+class NGHolder;
class ReportManager;
-/** \brief Class gathering together the pieces of a parsed expression. */
-class ParsedExpression : noncopyable {
+/** \brief Class gathering together the pieces of a parsed expression. */
+class ParsedExpression : noncopyable {
public:
ParsedExpression(unsigned index, const char *expression, unsigned flags,
- ReportID report, const hs_expr_ext *ext = nullptr);
+ ReportID report, const hs_expr_ext *ext = nullptr);
- /** \brief Expression information (from flags, extparam etc) */
- ExpressionInfo expr;
+ /** \brief Expression information (from flags, extparam etc) */
+ ExpressionInfo expr;
- /** \brief Root node of parsed component tree. */
- std::unique_ptr<Component> component;
-};
+ /** \brief Root node of parsed component tree. */
+ std::unique_ptr<Component> component;
+};
/** \brief Class gathering together the pieces of a parsed lit-expression. */
@@ -83,16 +83,16 @@ public:
ue2_literal lit;
};
-/**
- * \brief Class gathering together the pieces of an expression that has been
- * built into an NFA graph.
- */
-struct BuiltExpression {
- /** \brief Expression information (from flags, extparam etc) */
- ExpressionInfo expr;
+/**
+ * \brief Class gathering together the pieces of an expression that has been
+ * built into an NFA graph.
+ */
+struct BuiltExpression {
+ /** \brief Expression information (from flags, extparam etc) */
+ ExpressionInfo expr;
- /** \brief Built Glushkov NFA graph. */
- std::unique_ptr<NGHolder> g;
+ /** \brief Built Glushkov NFA graph. */
+ std::unique_ptr<NGHolder> g;
};
/**
@@ -109,12 +109,12 @@ struct BuiltExpression {
* @param ext
* Struct containing extra parameters for this expression, or NULL if
* none.
- * @param report
+ * @param report
* The identifier to associate with the expression; returned by engine on
* match.
*/
void addExpression(NG &ng, unsigned index, const char *expression,
- unsigned flags, const hs_expr_ext *ext, ReportID report);
+ unsigned flags, const hs_expr_ext *ext, ReportID report);
void addLitExpression(NG &ng, unsigned index, const char *expression,
unsigned flags, const hs_expr_ext *ext, ReportID id,
@@ -148,8 +148,8 @@ struct hs_database *build(NG &ng, unsigned int *length, u8 pureFlag);
* @return
* nullptr on error.
*/
-BuiltExpression buildGraph(ReportManager &rm, const CompileContext &cc,
- const ParsedExpression &expr);
+BuiltExpression buildGraph(ReportManager &rm, const CompileContext &cc,
+ const ParsedExpression &expr);
/**
* Build a platform_t out of a target_t.
diff --git a/contrib/libs/hyperscan/src/compiler/error.cpp b/contrib/libs/hyperscan/src/compiler/error.cpp
index 23ab45c6556..07db98192dc 100644
--- a/contrib/libs/hyperscan/src/compiler/error.cpp
+++ b/contrib/libs/hyperscan/src/compiler/error.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,7 +42,7 @@ using std::string;
static const char failureNoMemory[] = "Unable to allocate memory.";
static const char failureInternal[] = "Internal error.";
-static const char failureBadAlloc[] = "Allocator returned misaligned memory.";
+static const char failureBadAlloc[] = "Allocator returned misaligned memory.";
extern const hs_compile_error_t hs_enomem = {
const_cast<char *>(failureNoMemory), 0
@@ -50,9 +50,9 @@ extern const hs_compile_error_t hs_enomem = {
extern const hs_compile_error_t hs_einternal = {
const_cast<char *>(failureInternal), 0
};
-extern const hs_compile_error_t hs_badalloc = {
- const_cast<char *>(failureBadAlloc), 0
-};
+extern const hs_compile_error_t hs_badalloc = {
+ const_cast<char *>(failureBadAlloc), 0
+};
namespace ue2 {
@@ -60,18 +60,18 @@ hs_compile_error_t *generateCompileError(const string &err, int expression) {
hs_compile_error_t *ret =
(struct hs_compile_error *)hs_misc_alloc(sizeof(hs_compile_error_t));
if (ret) {
- hs_error_t e = hs_check_alloc(ret);
- if (e != HS_SUCCESS) {
- hs_misc_free(ret);
- return const_cast<hs_compile_error_t *>(&hs_badalloc);
- }
+ hs_error_t e = hs_check_alloc(ret);
+ if (e != HS_SUCCESS) {
+ hs_misc_free(ret);
+ return const_cast<hs_compile_error_t *>(&hs_badalloc);
+ }
char *msg = (char *)hs_misc_alloc(err.size() + 1);
if (msg) {
- e = hs_check_alloc(msg);
- if (e != HS_SUCCESS) {
- hs_misc_free(msg);
- return const_cast<hs_compile_error_t *>(&hs_badalloc);
- }
+ e = hs_check_alloc(msg);
+ if (e != HS_SUCCESS) {
+ hs_misc_free(msg);
+ return const_cast<hs_compile_error_t *>(&hs_badalloc);
+ }
memcpy(msg, err.c_str(), err.size() + 1);
ret->message = msg;
} else {
@@ -97,8 +97,8 @@ void freeCompileError(hs_compile_error_t *error) {
if (!error) {
return;
}
- if (error == &hs_enomem || error == &hs_einternal ||
- error == &hs_badalloc) {
+ if (error == &hs_enomem || error == &hs_einternal ||
+ error == &hs_badalloc) {
// These are not allocated.
return;
}
diff --git a/contrib/libs/hyperscan/src/compiler/expression_info.h b/contrib/libs/hyperscan/src/compiler/expression_info.h
index 99ee7403225..fefb3b58aff 100644
--- a/contrib/libs/hyperscan/src/compiler/expression_info.h
+++ b/contrib/libs/hyperscan/src/compiler/expression_info.h
@@ -1,108 +1,108 @@
-/*
+/*
* Copyright (c) 2017-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief ExpressionInfo class for storing the properties of an expression.
- */
-
-#ifndef COMPILER_EXPRESSION_INFO_H
-#define COMPILER_EXPRESSION_INFO_H
-
-#include "ue2common.h"
-#include "som/som.h"
-
-namespace ue2 {
-
-/** \brief Properties of an expression. */
-class ExpressionInfo {
-public:
- ExpressionInfo(unsigned int index_in, bool allow_vacuous_in,
- bool highlander_in, bool utf8_in, bool prefilter_in,
- som_type som_in, ReportID report_in, u64a min_offset_in,
- u64a max_offset_in, u64a min_length_in, u32 edit_distance_in,
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief ExpressionInfo class for storing the properties of an expression.
+ */
+
+#ifndef COMPILER_EXPRESSION_INFO_H
+#define COMPILER_EXPRESSION_INFO_H
+
+#include "ue2common.h"
+#include "som/som.h"
+
+namespace ue2 {
+
+/** \brief Properties of an expression. */
+class ExpressionInfo {
+public:
+ ExpressionInfo(unsigned int index_in, bool allow_vacuous_in,
+ bool highlander_in, bool utf8_in, bool prefilter_in,
+ som_type som_in, ReportID report_in, u64a min_offset_in,
+ u64a max_offset_in, u64a min_length_in, u32 edit_distance_in,
u32 hamm_distance_in, bool quiet_in)
- : index(index_in), report(report_in), allow_vacuous(allow_vacuous_in),
- highlander(highlander_in), utf8(utf8_in), prefilter(prefilter_in),
- som(som_in), min_offset(min_offset_in), max_offset(max_offset_in),
- min_length(min_length_in), edit_distance(edit_distance_in),
+ : index(index_in), report(report_in), allow_vacuous(allow_vacuous_in),
+ highlander(highlander_in), utf8(utf8_in), prefilter(prefilter_in),
+ som(som_in), min_offset(min_offset_in), max_offset(max_offset_in),
+ min_length(min_length_in), edit_distance(edit_distance_in),
hamm_distance(hamm_distance_in), quiet(quiet_in) {}
-
- /**
- * \brief Index of the expression represented by this graph.
- *
- * Used:
- * - down the track in error handling;
- * - for identifying parts of an expression in highlander mode.
- */
- unsigned int index;
-
- /** \brief Report ID specified by the user. */
- ReportID report;
-
- /** \brief Vacuous pattern is allowed. (HS_FLAG_ALLOWEMPTY) */
- bool allow_vacuous;
-
- /** \brief "Highlander" (single match) pattern. (HS_FLAG_SINGLEMATCH) */
- bool highlander;
-
- /** \brief UTF-8 pattern. (HS_FLAG_UTF8) */
- bool utf8;
-
- /** \brief Prefiltering pattern. (HS_FLAG_PREFILTER) */
- bool prefilter;
-
- /** \brief Start-of-match type requested, or SOM_NONE. */
- som_type som;
-
- /** \brief Minimum match offset extended parameter. 0 if not used. */
- u64a min_offset;
-
- /**
- * \brief Maximum match offset extended parameter.
- * MAX_OFFSET if not used.
- */
- u64a max_offset;
-
- /** \brief Minimum match length extended parameter. 0 if not used. */
- u64a min_length;
-
- /**
- * \brief Approximate matching edit distance extended parameter.
- * 0 if not used.
- */
- u32 edit_distance;
- u32 hamm_distance;
+
+ /**
+ * \brief Index of the expression represented by this graph.
+ *
+ * Used:
+ * - down the track in error handling;
+ * - for identifying parts of an expression in highlander mode.
+ */
+ unsigned int index;
+
+ /** \brief Report ID specified by the user. */
+ ReportID report;
+
+ /** \brief Vacuous pattern is allowed. (HS_FLAG_ALLOWEMPTY) */
+ bool allow_vacuous;
+
+ /** \brief "Highlander" (single match) pattern. (HS_FLAG_SINGLEMATCH) */
+ bool highlander;
+
+ /** \brief UTF-8 pattern. (HS_FLAG_UTF8) */
+ bool utf8;
+
+ /** \brief Prefiltering pattern. (HS_FLAG_PREFILTER) */
+ bool prefilter;
+
+ /** \brief Start-of-match type requested, or SOM_NONE. */
+ som_type som;
+
+ /** \brief Minimum match offset extended parameter. 0 if not used. */
+ u64a min_offset;
+
+ /**
+ * \brief Maximum match offset extended parameter.
+ * MAX_OFFSET if not used.
+ */
+ u64a max_offset;
+
+ /** \brief Minimum match length extended parameter. 0 if not used. */
+ u64a min_length;
+
+ /**
+ * \brief Approximate matching edit distance extended parameter.
+ * 0 if not used.
+ */
+ u32 edit_distance;
+ u32 hamm_distance;
/** \brief Quiet on match. */
bool quiet;
-};
-
-}
-
-#endif // COMPILER_EXPRESSION_INFO_H
+};
+
+}
+
+#endif // COMPILER_EXPRESSION_INFO_H
diff --git a/contrib/libs/hyperscan/src/crc32.c b/contrib/libs/hyperscan/src/crc32.c
index 7ecfeb855b9..1dae47b4e93 100644
--- a/contrib/libs/hyperscan/src/crc32.c
+++ b/contrib/libs/hyperscan/src/crc32.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,10 +29,10 @@
#include "crc32.h"
#include "config.h"
#include "ue2common.h"
-#include "util/arch.h"
-#include "util/intrinsics.h"
+#include "util/arch.h"
+#include "util/intrinsics.h"
-#if !defined(HAVE_SSE42)
+#if !defined(HAVE_SSE42)
/***
*** What follows is derived from Intel's Slicing-by-8 CRC32 impl, which is BSD
@@ -578,7 +578,7 @@ u32 crc32c_sb8_64_bit(u32 running_crc, const unsigned char* p_buf,
return crc;
}
-#else // HAVE_SSE42
+#else // HAVE_SSE42
#ifdef ARCH_64_BIT
#define CRC_WORD 8
@@ -634,7 +634,7 @@ u32 crc32c_sse42(u32 running_crc, const unsigned char* p_buf,
// Externally visible function
u32 Crc32c_ComputeBuf(u32 inCrc32, const void *buf, size_t bufLen) {
-#if defined(HAVE_SSE42)
+#if defined(HAVE_SSE42)
u32 crc = crc32c_sse42(inCrc32, (const unsigned char *)buf, bufLen);
#else
u32 crc = crc32c_sb8_64_bit(inCrc32, (const unsigned char *)buf, bufLen);
diff --git a/contrib/libs/hyperscan/src/database.c b/contrib/libs/hyperscan/src/database.c
index 54d9e6de030..6adf1419dde 100644
--- a/contrib/libs/hyperscan/src/database.c
+++ b/contrib/libs/hyperscan/src/database.c
@@ -49,7 +49,7 @@ int db_correctly_aligned(const void *db) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_free_database(hs_database_t *db) {
+hs_error_t HS_CDECL hs_free_database(hs_database_t *db) {
if (db && db->magic != HS_DB_MAGIC) {
return HS_INVALID;
}
@@ -59,8 +59,8 @@ hs_error_t HS_CDECL hs_free_database(hs_database_t *db) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_serialize_database(const hs_database_t *db, char **bytes,
- size_t *serialized_length) {
+hs_error_t HS_CDECL hs_serialize_database(const hs_database_t *db, char **bytes,
+ size_t *serialized_length) {
if (!db || !bytes || !serialized_length) {
return HS_INVALID;
}
@@ -197,9 +197,9 @@ void db_copy_bytecode(const char *serialized, hs_database_t *db) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
- const size_t length,
- hs_database_t *db) {
+hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
+ const size_t length,
+ hs_database_t *db) {
if (!bytes || !db) {
return HS_INVALID;
}
@@ -240,9 +240,9 @@ hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
- const size_t length,
- hs_database_t **db) {
+hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
+ const size_t length,
+ hs_database_t **db) {
if (!bytes || !db) {
return HS_INVALID;
}
@@ -290,7 +290,7 @@ hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_database_size(const hs_database_t *db, size_t *size) {
+hs_error_t HS_CDECL hs_database_size(const hs_database_t *db, size_t *size) {
if (!size) {
return HS_INVALID;
}
@@ -305,9 +305,9 @@ hs_error_t HS_CDECL hs_database_size(const hs_database_t *db, size_t *size) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_serialized_database_size(const char *bytes,
- const size_t length,
- size_t *size) {
+hs_error_t HS_CDECL hs_serialized_database_size(const char *bytes,
+ const size_t length,
+ size_t *size) {
// Decode and check the header
hs_database_t header;
hs_error_t ret = db_decode_header(&bytes, length, &header);
@@ -404,7 +404,7 @@ hs_error_t print_database_string(char **s, u32 version, const platform_t plat,
// that don't have snprintf but have a workalike.
int p_len = SNPRINTF_COMPAT(
buf, len, "Version: %u.%u.%u Features: %s Mode: %s",
- major, minor, release, features, mode);
+ major, minor, release, features, mode);
if (p_len < 0) {
DEBUG_PRINTF("snprintf output error, returned %d\n", p_len);
hs_misc_free(buf);
@@ -423,27 +423,27 @@ hs_error_t print_database_string(char **s, u32 version, const platform_t plat,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_serialized_database_info(const char *bytes,
- size_t length, char **info) {
+hs_error_t HS_CDECL hs_serialized_database_info(const char *bytes,
+ size_t length, char **info) {
if (!info) {
return HS_INVALID;
}
*info = NULL;
- // Decode and check the header
- hs_database_t header;
- hs_error_t ret = db_decode_header(&bytes, length, &header);
- if (ret != HS_SUCCESS) {
- return ret;
+ // Decode and check the header
+ hs_database_t header;
+ hs_error_t ret = db_decode_header(&bytes, length, &header);
+ if (ret != HS_SUCCESS) {
+ return ret;
}
- u32 mode = unaligned_load_u32(bytes + offsetof(struct RoseEngine, mode));
+ u32 mode = unaligned_load_u32(bytes + offsetof(struct RoseEngine, mode));
- return print_database_string(info, header.version, header.platform, mode);
+ return print_database_string(info, header.version, header.platform, mode);
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_database_info(const hs_database_t *db, char **info) {
+hs_error_t HS_CDECL hs_database_info(const hs_database_t *db, char **info) {
if (!info) {
return HS_INVALID;
}
diff --git a/contrib/libs/hyperscan/src/database.h b/contrib/libs/hyperscan/src/database.h
index 9f80bee461a..f122f97be7c 100644
--- a/contrib/libs/hyperscan/src/database.h
+++ b/contrib/libs/hyperscan/src/database.h
@@ -41,7 +41,7 @@ extern "C"
#include "hs_compile.h" // for HS_MODE_ flags
#include "hs_version.h"
#include "ue2common.h"
-#include "util/arch.h"
+#include "util/arch.h"
#define HS_DB_VERSION HS_VERSION_32BIT
#define HS_DB_MAGIC (0xdbdbdbdbU)
@@ -54,7 +54,7 @@ extern "C"
#define HS_PLATFORM_CPU_MASK 0x3F
#define HS_PLATFORM_NOAVX2 (4<<13)
-#define HS_PLATFORM_NOAVX512 (8<<13)
+#define HS_PLATFORM_NOAVX512 (8<<13)
#define HS_PLATFORM_NOAVX512VBMI (0x10<<13)
/** \brief Platform features bitmask. */
@@ -62,12 +62,12 @@ typedef u64a platform_t;
static UNUSED
const platform_t hs_current_platform = {
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
HS_PLATFORM_NOAVX2 |
#endif
-#if !defined(HAVE_AVX512)
- HS_PLATFORM_NOAVX512 |
-#endif
+#if !defined(HAVE_AVX512)
+ HS_PLATFORM_NOAVX512 |
+#endif
#if !defined(HAVE_AVX512VBMI)
HS_PLATFORM_NOAVX512VBMI |
#endif
@@ -77,18 +77,18 @@ const platform_t hs_current_platform = {
static UNUSED
const platform_t hs_current_platform_no_avx2 = {
HS_PLATFORM_NOAVX2 |
- HS_PLATFORM_NOAVX512 |
+ HS_PLATFORM_NOAVX512 |
HS_PLATFORM_NOAVX512VBMI |
0,
};
-static UNUSED
-const platform_t hs_current_platform_no_avx512 = {
- HS_PLATFORM_NOAVX512 |
+static UNUSED
+const platform_t hs_current_platform_no_avx512 = {
+ HS_PLATFORM_NOAVX512 |
HS_PLATFORM_NOAVX512VBMI |
- 0,
-};
-
+ 0,
+};
+
static UNUSED
const platform_t hs_current_platform_no_avx512vbmi = {
HS_PLATFORM_NOAVX512VBMI |
diff --git a/contrib/libs/hyperscan/src/fdr/engine_description.h b/contrib/libs/hyperscan/src/fdr/engine_description.h
index 0a05670ce8f..b545e6474e9 100644
--- a/contrib/libs/hyperscan/src/fdr/engine_description.h
+++ b/contrib/libs/hyperscan/src/fdr/engine_description.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -41,8 +41,8 @@ class EngineDescription {
public:
EngineDescription(u32 id_in, const target_t &code_target_in,
- u32 numBuckets_in)
- : id(id_in), code_target(code_target_in), numBuckets(numBuckets_in) {}
+ u32 numBuckets_in)
+ : id(id_in), code_target(code_target_in), numBuckets(numBuckets_in) {}
virtual ~EngineDescription();
diff --git a/contrib/libs/hyperscan/src/fdr/fdr.c b/contrib/libs/hyperscan/src/fdr/fdr.c
index 8fd5bcb6fd6..d33756d3588 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr.c
+++ b/contrib/libs/hyperscan/src/fdr/fdr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,818 +27,818 @@
*/
#include "fdr.h"
-#include "fdr_confirm.h"
-#include "fdr_confirm_runtime.h"
+#include "fdr_confirm.h"
+#include "fdr_confirm_runtime.h"
#include "fdr_internal.h"
-#include "fdr_loadval.h"
-#include "flood_runtime.h"
-#include "scratch.h"
-#include "teddy.h"
+#include "fdr_loadval.h"
+#include "flood_runtime.h"
+#include "scratch.h"
+#include "teddy.h"
#include "teddy_internal.h"
-#include "util/arch.h"
-#include "util/simd_utils.h"
-#include "util/uniform_ops.h"
-
-/** \brief number of bytes processed in each iteration */
-#define ITER_BYTES 16
-
-/** \brief total zone buffer size */
-#define ZONE_TOTAL_SIZE 64
-
-/** \brief maximum number of allowed zones */
-#define ZONE_MAX 3
-
-/** \brief zone information.
- *
- * Zone represents a region of data to scan in FDR.
- *
- * The incoming buffer is to split in multiple zones to ensure two properties:
- * 1: that we can read 8? bytes behind to generate a hash safely
- * 2: that we can read the 3 byte after the current byte (domain > 8)
- */
-struct zone {
- /** \brief copied buffer, used only when it is a boundary zone. */
- u8 ALIGN_CL_DIRECTIVE buf[ZONE_TOTAL_SIZE];
-
- /** \brief shift amount for fdr state to avoid unwanted match. */
- u8 shift;
-
- /** \brief if boundary zone, start points into the zone buffer after the
- * pre-padding. Otherwise, points to the main buffer, appropriately. */
- const u8 *start;
-
- /** \brief if boundary zone, end points to the end of zone. Otherwise,
- * pointer to the main buffer, appropriately. */
- const u8 *end;
-
- /** \brief the amount to adjust to go from a pointer in the zones region
- * (between start and end) to a pointer in the original data buffer. */
- ptrdiff_t zone_pointer_adjust;
-
- /** \brief firstFloodDetect from FDR_Runtime_Args for non-boundary zones,
- * otherwise end of the zone buf. floodPtr always points inside the same
- * buffer as the start pointe. */
- const u8 *floodPtr;
-};
-
-static
-const ALIGN_CL_DIRECTIVE u8 zone_or_mask[ITER_BYTES+1][ITER_BYTES] = {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 },
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-};
-
-/* compilers don't reliably synthesize the 32-bit ANDN instruction here,
- * so we force its generation.
- */
-static really_inline
-u64a andn(const u32 a, const u8 *b) {
- u64a r;
-#if defined(HAVE_BMI) && !defined(NO_ASM)
- __asm__ ("andn\t%2,%1,%k0" : "=r"(r) : "r"(a), "m"(*(const u32 *)b));
-#else
- r = unaligned_load_u32(b) & ~a;
-#endif
- return r;
-}
-
-/* generates an initial state mask based on the last byte-ish of history rather
- * than being all accepting. If there is no history to consider, the state is
- * generated based on the minimum length of each bucket in order to prevent
- * confirms.
- */
-static really_inline
-m128 getInitState(const struct FDR *fdr, u8 len_history, const u64a *ft,
- const struct zone *z) {
- m128 s;
- if (len_history) {
- /* +1: the zones ensure that we can read the byte at z->end */
- u32 tmp = lv_u16(z->start + z->shift - 1, z->buf, z->end + 1);
- tmp &= fdr->domainMask;
- s = load_m128_from_u64a(ft + tmp);
- s = rshiftbyte_m128(s, 1);
- } else {
- s = fdr->start;
- }
- return s;
-}
-
-static really_inline
-void get_conf_stride_1(const u8 *itPtr, UNUSED const u8 *start_ptr,
- UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
- const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
- /* +1: the zones ensure that we can read the byte at z->end */
- assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
- u64a reach0 = andn(domain_mask_flipped, itPtr);
- u64a reach1 = andn(domain_mask_flipped, itPtr + 1);
- u64a reach2 = andn(domain_mask_flipped, itPtr + 2);
- u64a reach3 = andn(domain_mask_flipped, itPtr + 3);
-
- m128 st0 = load_m128_from_u64a(ft + reach0);
- m128 st1 = load_m128_from_u64a(ft + reach1);
- m128 st2 = load_m128_from_u64a(ft + reach2);
- m128 st3 = load_m128_from_u64a(ft + reach3);
-
- u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
- u64a reach5 = andn(domain_mask_flipped, itPtr + 5);
- u64a reach6 = andn(domain_mask_flipped, itPtr + 6);
- u64a reach7 = andn(domain_mask_flipped, itPtr + 7);
-
- m128 st4 = load_m128_from_u64a(ft + reach4);
- m128 st5 = load_m128_from_u64a(ft + reach5);
- m128 st6 = load_m128_from_u64a(ft + reach6);
- m128 st7 = load_m128_from_u64a(ft + reach7);
-
- st1 = lshiftbyte_m128(st1, 1);
- st2 = lshiftbyte_m128(st2, 2);
- st3 = lshiftbyte_m128(st3, 3);
- st4 = lshiftbyte_m128(st4, 4);
- st5 = lshiftbyte_m128(st5, 5);
- st6 = lshiftbyte_m128(st6, 6);
- st7 = lshiftbyte_m128(st7, 7);
-
- st0 = or128(st0, st1);
- st2 = or128(st2, st3);
- st4 = or128(st4, st5);
- st6 = or128(st6, st7);
- st0 = or128(st0, st2);
- st4 = or128(st4, st6);
- st0 = or128(st0, st4);
- *s = or128(*s, st0);
-
- *conf0 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf0 ^= ~0ULL;
-
- u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
- u64a reach9 = andn(domain_mask_flipped, itPtr + 9);
- u64a reach10 = andn(domain_mask_flipped, itPtr + 10);
- u64a reach11 = andn(domain_mask_flipped, itPtr + 11);
-
- m128 st8 = load_m128_from_u64a(ft + reach8);
- m128 st9 = load_m128_from_u64a(ft + reach9);
- m128 st10 = load_m128_from_u64a(ft + reach10);
- m128 st11 = load_m128_from_u64a(ft + reach11);
-
- u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
- u64a reach13 = andn(domain_mask_flipped, itPtr + 13);
- u64a reach14 = andn(domain_mask_flipped, itPtr + 14);
- u64a reach15 = andn(domain_mask_flipped, itPtr + 15);
-
- m128 st12 = load_m128_from_u64a(ft + reach12);
- m128 st13 = load_m128_from_u64a(ft + reach13);
- m128 st14 = load_m128_from_u64a(ft + reach14);
- m128 st15 = load_m128_from_u64a(ft + reach15);
-
- st9 = lshiftbyte_m128(st9, 1);
- st10 = lshiftbyte_m128(st10, 2);
- st11 = lshiftbyte_m128(st11, 3);
- st12 = lshiftbyte_m128(st12, 4);
- st13 = lshiftbyte_m128(st13, 5);
- st14 = lshiftbyte_m128(st14, 6);
- st15 = lshiftbyte_m128(st15, 7);
-
- st8 = or128(st8, st9);
- st10 = or128(st10, st11);
- st12 = or128(st12, st13);
- st14 = or128(st14, st15);
- st8 = or128(st8, st10);
- st12 = or128(st12, st14);
- st8 = or128(st8, st12);
- *s = or128(*s, st8);
-
- *conf8 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf8 ^= ~0ULL;
-}
-
-static really_inline
-void get_conf_stride_2(const u8 *itPtr, UNUSED const u8 *start_ptr,
- UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
- const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
- assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
- u64a reach0 = andn(domain_mask_flipped, itPtr);
- u64a reach2 = andn(domain_mask_flipped, itPtr + 2);
- u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
- u64a reach6 = andn(domain_mask_flipped, itPtr + 6);
-
- m128 st0 = load_m128_from_u64a(ft + reach0);
- m128 st2 = load_m128_from_u64a(ft + reach2);
- m128 st4 = load_m128_from_u64a(ft + reach4);
- m128 st6 = load_m128_from_u64a(ft + reach6);
-
- u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
- u64a reach10 = andn(domain_mask_flipped, itPtr + 10);
- u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
- u64a reach14 = andn(domain_mask_flipped, itPtr + 14);
-
- m128 st8 = load_m128_from_u64a(ft + reach8);
- m128 st10 = load_m128_from_u64a(ft + reach10);
- m128 st12 = load_m128_from_u64a(ft + reach12);
- m128 st14 = load_m128_from_u64a(ft + reach14);
-
- st2 = lshiftbyte_m128(st2, 2);
- st4 = lshiftbyte_m128(st4, 4);
- st6 = lshiftbyte_m128(st6, 6);
-
- *s = or128(*s, st0);
- *s = or128(*s, st2);
- *s = or128(*s, st4);
- *s = or128(*s, st6);
-
- *conf0 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf0 ^= ~0ULL;
-
- st10 = lshiftbyte_m128(st10, 2);
- st12 = lshiftbyte_m128(st12, 4);
- st14 = lshiftbyte_m128(st14, 6);
-
- *s = or128(*s, st8);
- *s = or128(*s, st10);
- *s = or128(*s, st12);
- *s = or128(*s, st14);
-
- *conf8 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf8 ^= ~0ULL;
-}
-
-static really_inline
-void get_conf_stride_4(const u8 *itPtr, UNUSED const u8 *start_ptr,
- UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
- const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
- assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
- u64a reach0 = andn(domain_mask_flipped, itPtr);
- u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
- u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
- u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
-
- m128 st0 = load_m128_from_u64a(ft + reach0);
- m128 st4 = load_m128_from_u64a(ft + reach4);
- m128 st8 = load_m128_from_u64a(ft + reach8);
- m128 st12 = load_m128_from_u64a(ft + reach12);
-
- st4 = lshiftbyte_m128(st4, 4);
- st12 = lshiftbyte_m128(st12, 4);
-
- *s = or128(*s, st0);
- *s = or128(*s, st4);
- *conf0 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf0 ^= ~0ULL;
-
- *s = or128(*s, st8);
- *s = or128(*s, st12);
- *conf8 = movq(*s);
- *s = rshiftbyte_m128(*s, 8);
- *conf8 ^= ~0ULL;
-}
-
-static really_inline
-void do_confirm_fdr(u64a *conf, u8 offset, hwlmcb_rv_t *control,
- const u32 *confBase, const struct FDR_Runtime_Args *a,
- const u8 *ptr, u32 *last_match_id, struct zone *z) {
- const u8 bucket = 8;
-
- if (likely(!*conf)) {
- return;
- }
-
- /* ptr is currently referring to a location in the zone's buffer, we also
- * need a pointer in the original, main buffer for the final string compare.
- */
- const u8 *ptr_main = (const u8 *)((uintptr_t)ptr + z->zone_pointer_adjust);
-
- const u8 *confLoc = ptr;
-
- do {
- u32 bit = findAndClearLSB_64(conf);
- u32 byte = bit / bucket + offset;
- u32 bitRem = bit % bucket;
- u32 idx = bitRem;
- u32 cf = confBase[idx];
- if (!cf) {
- continue;
- }
- const struct FDRConfirm *fdrc = (const struct FDRConfirm *)
- ((const u8 *)confBase + cf);
- if (!(fdrc->groups & *control)) {
- continue;
- }
- u64a confVal = unaligned_load_u64a(confLoc + byte - sizeof(u64a) + 1);
- confWithBit(fdrc, a, ptr_main - a->buf + byte, control,
- last_match_id, confVal, conf, bit);
- } while (unlikely(!!*conf));
-}
-
-static really_inline
-void dumpZoneInfo(UNUSED struct zone *z, UNUSED size_t zone_id) {
-#ifdef DEBUG
- DEBUG_PRINTF("zone: zone=%zu, bufPtr=%p\n", zone_id, z->buf);
- DEBUG_PRINTF("zone: startPtr=%p, endPtr=%p, shift=%u\n",
- z->start, z->end, z->shift);
- DEBUG_PRINTF("zone: zone_pointer_adjust=%zd, floodPtr=%p\n",
- z->zone_pointer_adjust, z->floodPtr);
- DEBUG_PRINTF("zone buf:");
- for (size_t i = 0; i < ZONE_TOTAL_SIZE; i++) {
- if (i % 8 == 0) {
- printf("_");
- }
- if (z->buf[i]) {
- printf("%02x", z->buf[i]);
- } else {
- printf("..");
- }
- }
- printf("\n");
-#endif
-};
-
-/**
- * \brief Updates attributes for non-boundary region zone.
- */
-static really_inline
-void createMainZone(const u8 *flood, const u8 *begin, const u8 *end,
- struct zone *z) {
- z->zone_pointer_adjust = 0; /* zone buffer is the main buffer */
- z->start = begin;
- z->end = end;
- z->floodPtr = flood;
- z->shift = 0;
-}
-
-/**
- * \brief Create zone for short cases (<= ITER_BYTES).
- *
- * For this case we need to copy everything into the zone's internal buffer.
- *
- * We need to ensure that we run over real data if it exists (in history or
- * before zone begin). We also need to ensure 8 bytes before any data being
- * matched can be read (to perform a conf hash).
- *
- * We also need to ensure that the data at z->end can be read.
- *
- * Hence, the zone consists of:
- * 16 bytes of history,
- * 1 - 24 bytes of data form the buffer (ending at end),
- * 1 byte of final padding
- */
-static really_inline
-void createShortZone(const u8 *buf, const u8 *hend, const u8 *begin,
- const u8 *end, struct zone *z) {
- /* the floodPtr for BOUNDARY zones are maximum of end of zone buf to avoid
- * the checks in boundary zone. */
- z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
-
- ptrdiff_t z_len = end - begin;
- assert(z_len > 0);
- assert(z_len <= ITER_BYTES);
-
- z->shift = ITER_BYTES - z_len; /* ignore bytes outside region specified */
-
- static const size_t ZONE_SHORT_DATA_OFFSET = 16; /* after history */
-
- /* we are guaranteed to always have 16 initialised bytes at the end of
- * the history buffer (they may be garbage coming from the stream state
- * preceding hbuf, but bytes that don't correspond to actual history
- * shouldn't affect computations). */
- *(m128 *)z->buf = loadu128(hend - sizeof(m128));
-
- /* The amount of data we have to copy from main buffer. */
- size_t copy_len = MIN((size_t)(end - buf),
- ITER_BYTES + sizeof(CONF_TYPE));
-
- u8 *zone_data = z->buf + ZONE_SHORT_DATA_OFFSET;
- switch (copy_len) {
- case 1:
- *zone_data = *(end - 1);
- break;
- case 2:
- *(u16 *)zone_data = unaligned_load_u16(end - 2);
- break;
- case 3:
- *(u16 *)zone_data = unaligned_load_u16(end - 3);
- *(zone_data + 2) = *(end - 1);
- break;
- case 4:
- *(u32 *)zone_data = unaligned_load_u32(end - 4);
- break;
- case 5:
- case 6:
- case 7:
- /* perform copy with 2 overlapping 4-byte chunks from buf. */
- *(u32 *)zone_data = unaligned_load_u32(end - copy_len);
- unaligned_store_u32(zone_data + copy_len - sizeof(u32),
- unaligned_load_u32(end - sizeof(u32)));
- break;
- case 8:
- *(u64a *)zone_data = unaligned_load_u64a(end - 8);
- break;
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- /* perform copy with 2 overlapping 8-byte chunks from buf. */
- *(u64a *)zone_data = unaligned_load_u64a(end - copy_len);
- unaligned_store_u64a(zone_data + copy_len - sizeof(u64a),
- unaligned_load_u64a(end - sizeof(u64a)));
- break;
- case 16:
- /* copy 16-bytes from buf. */
- *(m128 *)zone_data = loadu128(end - 16);
- break;
- default:
- assert(copy_len <= sizeof(m128) + sizeof(u64a));
-
- /* perform copy with (potentially overlapping) 8-byte and 16-byte chunks.
- */
- *(u64a *)zone_data = unaligned_load_u64a(end - copy_len);
- storeu128(zone_data + copy_len - sizeof(m128),
- loadu128(end - sizeof(m128)));
- break;
- }
-
- /* set the start and end location of the zone buf
- * to be scanned */
- u8 *z_end = z->buf + ZONE_SHORT_DATA_OFFSET + copy_len;
- assert(ZONE_SHORT_DATA_OFFSET + copy_len >= ITER_BYTES);
-
- /* copy the post-padding byte; this is required for domain > 8 due to
- * overhang */
- assert(ZONE_SHORT_DATA_OFFSET + copy_len + 3 < 64);
- *z_end = 0;
-
- z->end = z_end;
- z->start = z_end - ITER_BYTES;
- z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
- assert(z->start + z->shift == z_end - z_len);
-}
-
-/**
- * \brief Create a zone for the start region.
- *
- * This function requires that there is > ITER_BYTES of data in the buffer to
- * scan. The start zone itself is always responsible for scanning exactly
- * ITER_BYTES of data - there are no warmup/junk bytes scanned.
- *
- * This zone ensures that the byte at z->end can be read and corresponds to
- * the next byte of data.
- *
- * 8 bytes of history data are provided before z->start to allow proper hash
- * generation in streaming mode. If buf != begin, upto 8 bytes of data
- * prior to begin is also provided.
- *
- * Although we are not interested in bare literals which start before begin
- * if buf != begin, lookarounds associated with the literal may require
- * the data prior to begin for hash purposes.
- */
-static really_inline
-void createStartZone(const u8 *buf, const u8 *hend, const u8 *begin,
- struct zone *z) {
- assert(ITER_BYTES == sizeof(m128));
- assert(sizeof(CONF_TYPE) == 8);
- static const size_t ZONE_START_BEGIN = sizeof(CONF_TYPE);
-
- const u8 *end = begin + ITER_BYTES;
-
- /* set floodPtr to the end of zone buf to avoid checks in start zone */
- z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
-
- z->shift = 0; /* we are processing ITER_BYTES of real data */
-
- /* we are guaranteed to always have 16 initialised bytes at the end of the
- * history buffer (they may be garbage coming from the stream state
- * preceding hbuf, but bytes that don't correspond to actual history
- * shouldn't affect computations). However, for start zones, history is only
- * required for conf hash purposes so we only need 8 bytes */
- unaligned_store_u64a(z->buf, unaligned_load_u64a(hend - sizeof(u64a)));
-
- /* The amount of data we have to copy from main buffer. */
- size_t copy_len = MIN((size_t)(end - buf),
- ITER_BYTES + sizeof(CONF_TYPE));
- assert(copy_len >= 16);
-
- /* copy the post-padding byte; this is required for domain > 8 due to
- * overhang. The start requires that there is data after the zone so it
- * it safe to dereference end */
- z->buf[ZONE_START_BEGIN + copy_len] = *end;
-
- /* set the start and end location of the zone buf to be scanned */
- u8 *z_end = z->buf + ZONE_START_BEGIN + copy_len;
- z->end = z_end;
- z->start = z_end - ITER_BYTES;
-
- /* copy the first 8 bytes of the valid region */
- unaligned_store_u64a(z->buf + ZONE_START_BEGIN,
- unaligned_load_u64a(end - copy_len));
-
- /* copy the last 16 bytes, may overlap with the previous 8 byte write */
- storeu128(z_end - sizeof(m128), loadu128(end - sizeof(m128)));
-
- z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
-
- assert(ZONE_START_BEGIN + copy_len + 3 < 64);
-}
-
-/**
- * \brief Create a zone for the end region.
- *
- * This function requires that there is > ITER_BYTES of data in the buffer to
- * scan. The end zone is responsible for a scanning the <= ITER_BYTES rump of
- * data and optional ITER_BYTES. The main zone cannot handle the last 3 bytes
- * of the buffer. The end zone is required to handle an optional full
- * ITER_BYTES from main zone when there are less than 3 bytes to scan. The
- * main zone size is reduced by ITER_BYTES in this case.
- *
- * This zone ensures that the byte at z->end can be read by filling it with a
- * padding character.
- *
- * Upto 8 bytes of data prior to begin is also provided for the purposes of
- * generating hashes. History is not copied, as all locations which require
- * history for generating a hash are the responsiblity of the start zone.
- */
-static really_inline
-void createEndZone(const u8 *buf, const u8 *begin, const u8 *end,
- struct zone *z) {
- /* the floodPtr for BOUNDARY zones are maximum of end of zone buf to avoid
- * the checks in boundary zone. */
- z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
-
- ptrdiff_t z_len = end - begin;
- assert(z_len > 0);
- size_t iter_bytes_second = 0;
- size_t z_len_first = z_len;
- if (z_len > ITER_BYTES) {
- z_len_first = z_len - ITER_BYTES;
- iter_bytes_second = ITER_BYTES;
- }
- z->shift = ITER_BYTES - z_len_first;
-
- const u8 *end_first = end - iter_bytes_second;
- /* The amount of data we have to copy from main buffer for the
- * first iteration. */
- size_t copy_len_first = MIN((size_t)(end_first - buf),
- ITER_BYTES + sizeof(CONF_TYPE));
- assert(copy_len_first >= 16);
-
- size_t total_copy_len = copy_len_first + iter_bytes_second;
- assert(total_copy_len + 3 < 64);
-
- /* copy the post-padding byte; this is required for domain > 8 due to
- * overhang */
- z->buf[total_copy_len] = 0;
-
- /* set the start and end location of the zone buf
- * to be scanned */
- u8 *z_end = z->buf + total_copy_len;
- z->end = z_end;
- z->start = z_end - ITER_BYTES - iter_bytes_second;
- assert(z->start + z->shift == z_end - z_len);
-
- u8 *z_end_first = z_end - iter_bytes_second;
- /* copy the first 8 bytes of the valid region */
- unaligned_store_u64a(z->buf,
- unaligned_load_u64a(end_first - copy_len_first));
-
- /* copy the last 16 bytes, may overlap with the previous 8 byte write */
- storeu128(z_end_first - sizeof(m128), loadu128(end_first - sizeof(m128)));
- if (iter_bytes_second) {
- storeu128(z_end - sizeof(m128), loadu128(end - sizeof(m128)));
- }
-
- z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
-}
-
-/**
- * \brief Prepare zones.
- *
- * This function prepares zones with actual buffer and some padded bytes.
- * The actual ITER_BYTES bytes in zone is preceded by main buf and/or
- * history buf and succeeded by padded bytes possibly from main buf,
- * if available.
- */
-static really_inline
-size_t prepareZones(const u8 *buf, size_t len, const u8 *hend,
- size_t start, const u8 *flood, struct zone *zoneArr) {
- const u8 *ptr = buf + start;
- size_t remaining = len - start;
-
- if (remaining <= ITER_BYTES) {
- /* enough bytes to make only one zone */
- createShortZone(buf, hend, ptr, buf + len, &zoneArr[0]);
- return 1;
- }
-
- /* enough bytes to make more than one zone */
-
- size_t numZone = 0;
- createStartZone(buf, hend, ptr, &zoneArr[numZone++]);
- ptr += ITER_BYTES;
-
- assert(ptr < buf + len);
-
- /* find maximum buffer location that the main zone can scan
- * - must be a multiple of ITER_BYTES, and
- * - cannot contain the last 3 bytes (due to 3 bytes read behind the
- end of buffer in FDR main loop)
- */
- const u8 *main_end = buf + start + ROUNDDOWN_N(len - start - 3, ITER_BYTES);
-
- /* create a zone if multiple of ITER_BYTES are found */
- if (main_end > ptr) {
- createMainZone(flood, ptr, main_end, &zoneArr[numZone++]);
- ptr = main_end;
- }
- /* create a zone with rest of the data from the main buffer */
- createEndZone(buf, ptr, buf + len, &zoneArr[numZone++]);
- return numZone;
-}
-
-#define INVALID_MATCH_ID (~0U)
-
-#define FDR_MAIN_LOOP(zz, s, get_conf_fn) \
- do { \
- const u8 *tryFloodDetect = zz->floodPtr; \
- const u8 *start_ptr = zz->start; \
- const u8 *end_ptr = zz->end; \
- \
- for (const u8 *itPtr = start_ptr; itPtr + ITER_BYTES <= end_ptr; \
- itPtr += ITER_BYTES) { \
- if (unlikely(itPtr > tryFloodDetect)) { \
- tryFloodDetect = floodDetect(fdr, a, &itPtr, tryFloodDetect,\
- &floodBackoff, &control, \
- ITER_BYTES); \
- if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
- return HWLM_TERMINATED; \
- } \
- } \
- __builtin_prefetch(itPtr + ITER_BYTES); \
- u64a conf0; \
- u64a conf8; \
- get_conf_fn(itPtr, start_ptr, end_ptr, domain_mask_flipped, \
- ft, &conf0, &conf8, &s); \
- do_confirm_fdr(&conf0, 0, &control, confBase, a, itPtr, \
- &last_match_id, zz); \
- do_confirm_fdr(&conf8, 8, &control, confBase, a, itPtr, \
- &last_match_id, zz); \
- if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
- return HWLM_TERMINATED; \
- } \
- } /* end for loop */ \
- } while (0) \
-
-static never_inline
-hwlm_error_t fdr_engine_exec(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- assert(ISALIGNED_CL(fdr));
-
- u32 floodBackoff = FLOOD_BACKOFF_START;
- u32 last_match_id = INVALID_MATCH_ID;
- u32 domain_mask_flipped = ~fdr->domainMask;
- u8 stride = fdr->stride;
- const u64a *ft =
- (const u64a *)((const u8 *)fdr + ROUNDUP_CL(sizeof(struct FDR)));
- assert(ISALIGNED_CL(ft));
- const u32 *confBase = (const u32 *)((const u8 *)fdr + fdr->confOffset);
- assert(ISALIGNED_CL(confBase));
- struct zone zones[ZONE_MAX];
- assert(fdr->domain > 8 && fdr->domain < 16);
-
- size_t numZone = prepareZones(a->buf, a->len,
- a->buf_history + a->len_history,
- a->start_offset, a->firstFloodDetect, zones);
- assert(numZone <= ZONE_MAX);
- m128 state = getInitState(fdr, a->len_history, ft, &zones[0]);
-
- for (size_t curZone = 0; curZone < numZone; curZone++) {
- struct zone *z = &zones[curZone];
- dumpZoneInfo(z, curZone);
-
- /* When a zone contains less data than is processed in an iteration
- * of FDR_MAIN_LOOP(), we need to scan over some extra data.
- *
- * We have chosen to scan this extra data at the start of the
- * iteration. The extra data is either data we have already scanned or
- * garbage (if it is earlier than offset 0),
- *
- * As a result we need to shift the incoming state back so that it will
- * properly line up with the data being scanned.
- *
- * We also need to forbid reporting any matches in the data being
- * rescanned as they have already been reported (or are over garbage but
- * later stages should also provide that safety guarantee).
- */
-
- u8 shift = z->shift;
-
- state = variable_byte_shift_m128(state, shift);
-
- state = or128(state, load128(zone_or_mask[shift]));
-
- switch (stride) {
- case 1:
- FDR_MAIN_LOOP(z, state, get_conf_stride_1);
- break;
- case 2:
- FDR_MAIN_LOOP(z, state, get_conf_stride_2);
- break;
- case 4:
- FDR_MAIN_LOOP(z, state, get_conf_stride_4);
- break;
- default:
- break;
- }
- }
-
- return HWLM_SUCCESS;
-}
-
-#if defined(HAVE_AVX2)
-#define ONLY_AVX2(func) func
-#else
-#define ONLY_AVX2(func) NULL
-#endif
-
-typedef hwlm_error_t (*FDRFUNCTYPE)(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-static const FDRFUNCTYPE funcs[] = {
- fdr_engine_exec,
- NULL, /* old: fast teddy */
- NULL, /* old: fast teddy */
- ONLY_AVX2(fdr_exec_fat_teddy_msks1),
- ONLY_AVX2(fdr_exec_fat_teddy_msks1_pck),
- ONLY_AVX2(fdr_exec_fat_teddy_msks2),
- ONLY_AVX2(fdr_exec_fat_teddy_msks2_pck),
- ONLY_AVX2(fdr_exec_fat_teddy_msks3),
- ONLY_AVX2(fdr_exec_fat_teddy_msks3_pck),
- ONLY_AVX2(fdr_exec_fat_teddy_msks4),
- ONLY_AVX2(fdr_exec_fat_teddy_msks4_pck),
- fdr_exec_teddy_msks1,
- fdr_exec_teddy_msks1_pck,
- fdr_exec_teddy_msks2,
- fdr_exec_teddy_msks2_pck,
- fdr_exec_teddy_msks3,
- fdr_exec_teddy_msks3_pck,
- fdr_exec_teddy_msks4,
- fdr_exec_teddy_msks4_pck,
-};
-
+#include "util/arch.h"
+#include "util/simd_utils.h"
+#include "util/uniform_ops.h"
+
+/** \brief number of bytes processed in each iteration */
+#define ITER_BYTES 16
+
+/** \brief total zone buffer size */
+#define ZONE_TOTAL_SIZE 64
+
+/** \brief maximum number of allowed zones */
+#define ZONE_MAX 3
+
+/** \brief zone information.
+ *
+ * Zone represents a region of data to scan in FDR.
+ *
+ * The incoming buffer is to split in multiple zones to ensure two properties:
+ * 1: that we can read 8? bytes behind to generate a hash safely
+ * 2: that we can read the 3 byte after the current byte (domain > 8)
+ */
+struct zone {
+ /** \brief copied buffer, used only when it is a boundary zone. */
+ u8 ALIGN_CL_DIRECTIVE buf[ZONE_TOTAL_SIZE];
+
+ /** \brief shift amount for fdr state to avoid unwanted match. */
+ u8 shift;
+
+ /** \brief if boundary zone, start points into the zone buffer after the
+ * pre-padding. Otherwise, points to the main buffer, appropriately. */
+ const u8 *start;
+
+ /** \brief if boundary zone, end points to the end of zone. Otherwise,
+ * pointer to the main buffer, appropriately. */
+ const u8 *end;
+
+ /** \brief the amount to adjust to go from a pointer in the zones region
+ * (between start and end) to a pointer in the original data buffer. */
+ ptrdiff_t zone_pointer_adjust;
+
+ /** \brief firstFloodDetect from FDR_Runtime_Args for non-boundary zones,
+ * otherwise end of the zone buf. floodPtr always points inside the same
+ * buffer as the start pointe. */
+ const u8 *floodPtr;
+};
+
+static
+const ALIGN_CL_DIRECTIVE u8 zone_or_mask[ITER_BYTES+1][ITER_BYTES] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+/* compilers don't reliably synthesize the 32-bit ANDN instruction here,
+ * so we force its generation.
+ */
+static really_inline
+u64a andn(const u32 a, const u8 *b) {
+ u64a r;
+#if defined(HAVE_BMI) && !defined(NO_ASM)
+ __asm__ ("andn\t%2,%1,%k0" : "=r"(r) : "r"(a), "m"(*(const u32 *)b));
+#else
+ r = unaligned_load_u32(b) & ~a;
+#endif
+ return r;
+}
+
+/* generates an initial state mask based on the last byte-ish of history rather
+ * than being all accepting. If there is no history to consider, the state is
+ * generated based on the minimum length of each bucket in order to prevent
+ * confirms.
+ */
+static really_inline
+m128 getInitState(const struct FDR *fdr, u8 len_history, const u64a *ft,
+ const struct zone *z) {
+ m128 s;
+ if (len_history) {
+ /* +1: the zones ensure that we can read the byte at z->end */
+ u32 tmp = lv_u16(z->start + z->shift - 1, z->buf, z->end + 1);
+ tmp &= fdr->domainMask;
+ s = load_m128_from_u64a(ft + tmp);
+ s = rshiftbyte_m128(s, 1);
+ } else {
+ s = fdr->start;
+ }
+ return s;
+}
+
+static really_inline
+void get_conf_stride_1(const u8 *itPtr, UNUSED const u8 *start_ptr,
+ UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
+ const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
+ /* +1: the zones ensure that we can read the byte at z->end */
+ assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
+ u64a reach0 = andn(domain_mask_flipped, itPtr);
+ u64a reach1 = andn(domain_mask_flipped, itPtr + 1);
+ u64a reach2 = andn(domain_mask_flipped, itPtr + 2);
+ u64a reach3 = andn(domain_mask_flipped, itPtr + 3);
+
+ m128 st0 = load_m128_from_u64a(ft + reach0);
+ m128 st1 = load_m128_from_u64a(ft + reach1);
+ m128 st2 = load_m128_from_u64a(ft + reach2);
+ m128 st3 = load_m128_from_u64a(ft + reach3);
+
+ u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
+ u64a reach5 = andn(domain_mask_flipped, itPtr + 5);
+ u64a reach6 = andn(domain_mask_flipped, itPtr + 6);
+ u64a reach7 = andn(domain_mask_flipped, itPtr + 7);
+
+ m128 st4 = load_m128_from_u64a(ft + reach4);
+ m128 st5 = load_m128_from_u64a(ft + reach5);
+ m128 st6 = load_m128_from_u64a(ft + reach6);
+ m128 st7 = load_m128_from_u64a(ft + reach7);
+
+ st1 = lshiftbyte_m128(st1, 1);
+ st2 = lshiftbyte_m128(st2, 2);
+ st3 = lshiftbyte_m128(st3, 3);
+ st4 = lshiftbyte_m128(st4, 4);
+ st5 = lshiftbyte_m128(st5, 5);
+ st6 = lshiftbyte_m128(st6, 6);
+ st7 = lshiftbyte_m128(st7, 7);
+
+ st0 = or128(st0, st1);
+ st2 = or128(st2, st3);
+ st4 = or128(st4, st5);
+ st6 = or128(st6, st7);
+ st0 = or128(st0, st2);
+ st4 = or128(st4, st6);
+ st0 = or128(st0, st4);
+ *s = or128(*s, st0);
+
+ *conf0 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf0 ^= ~0ULL;
+
+ u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
+ u64a reach9 = andn(domain_mask_flipped, itPtr + 9);
+ u64a reach10 = andn(domain_mask_flipped, itPtr + 10);
+ u64a reach11 = andn(domain_mask_flipped, itPtr + 11);
+
+ m128 st8 = load_m128_from_u64a(ft + reach8);
+ m128 st9 = load_m128_from_u64a(ft + reach9);
+ m128 st10 = load_m128_from_u64a(ft + reach10);
+ m128 st11 = load_m128_from_u64a(ft + reach11);
+
+ u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
+ u64a reach13 = andn(domain_mask_flipped, itPtr + 13);
+ u64a reach14 = andn(domain_mask_flipped, itPtr + 14);
+ u64a reach15 = andn(domain_mask_flipped, itPtr + 15);
+
+ m128 st12 = load_m128_from_u64a(ft + reach12);
+ m128 st13 = load_m128_from_u64a(ft + reach13);
+ m128 st14 = load_m128_from_u64a(ft + reach14);
+ m128 st15 = load_m128_from_u64a(ft + reach15);
+
+ st9 = lshiftbyte_m128(st9, 1);
+ st10 = lshiftbyte_m128(st10, 2);
+ st11 = lshiftbyte_m128(st11, 3);
+ st12 = lshiftbyte_m128(st12, 4);
+ st13 = lshiftbyte_m128(st13, 5);
+ st14 = lshiftbyte_m128(st14, 6);
+ st15 = lshiftbyte_m128(st15, 7);
+
+ st8 = or128(st8, st9);
+ st10 = or128(st10, st11);
+ st12 = or128(st12, st13);
+ st14 = or128(st14, st15);
+ st8 = or128(st8, st10);
+ st12 = or128(st12, st14);
+ st8 = or128(st8, st12);
+ *s = or128(*s, st8);
+
+ *conf8 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf8 ^= ~0ULL;
+}
+
+static really_inline
+void get_conf_stride_2(const u8 *itPtr, UNUSED const u8 *start_ptr,
+ UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
+ const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
+ assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
+ u64a reach0 = andn(domain_mask_flipped, itPtr);
+ u64a reach2 = andn(domain_mask_flipped, itPtr + 2);
+ u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
+ u64a reach6 = andn(domain_mask_flipped, itPtr + 6);
+
+ m128 st0 = load_m128_from_u64a(ft + reach0);
+ m128 st2 = load_m128_from_u64a(ft + reach2);
+ m128 st4 = load_m128_from_u64a(ft + reach4);
+ m128 st6 = load_m128_from_u64a(ft + reach6);
+
+ u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
+ u64a reach10 = andn(domain_mask_flipped, itPtr + 10);
+ u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
+ u64a reach14 = andn(domain_mask_flipped, itPtr + 14);
+
+ m128 st8 = load_m128_from_u64a(ft + reach8);
+ m128 st10 = load_m128_from_u64a(ft + reach10);
+ m128 st12 = load_m128_from_u64a(ft + reach12);
+ m128 st14 = load_m128_from_u64a(ft + reach14);
+
+ st2 = lshiftbyte_m128(st2, 2);
+ st4 = lshiftbyte_m128(st4, 4);
+ st6 = lshiftbyte_m128(st6, 6);
+
+ *s = or128(*s, st0);
+ *s = or128(*s, st2);
+ *s = or128(*s, st4);
+ *s = or128(*s, st6);
+
+ *conf0 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf0 ^= ~0ULL;
+
+ st10 = lshiftbyte_m128(st10, 2);
+ st12 = lshiftbyte_m128(st12, 4);
+ st14 = lshiftbyte_m128(st14, 6);
+
+ *s = or128(*s, st8);
+ *s = or128(*s, st10);
+ *s = or128(*s, st12);
+ *s = or128(*s, st14);
+
+ *conf8 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf8 ^= ~0ULL;
+}
+
+static really_inline
+void get_conf_stride_4(const u8 *itPtr, UNUSED const u8 *start_ptr,
+ UNUSED const u8 *end_ptr, u32 domain_mask_flipped,
+ const u64a *ft, u64a *conf0, u64a *conf8, m128 *s) {
+ assert(itPtr >= start_ptr && itPtr + ITER_BYTES <= end_ptr);
+ u64a reach0 = andn(domain_mask_flipped, itPtr);
+ u64a reach4 = andn(domain_mask_flipped, itPtr + 4);
+ u64a reach8 = andn(domain_mask_flipped, itPtr + 8);
+ u64a reach12 = andn(domain_mask_flipped, itPtr + 12);
+
+ m128 st0 = load_m128_from_u64a(ft + reach0);
+ m128 st4 = load_m128_from_u64a(ft + reach4);
+ m128 st8 = load_m128_from_u64a(ft + reach8);
+ m128 st12 = load_m128_from_u64a(ft + reach12);
+
+ st4 = lshiftbyte_m128(st4, 4);
+ st12 = lshiftbyte_m128(st12, 4);
+
+ *s = or128(*s, st0);
+ *s = or128(*s, st4);
+ *conf0 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf0 ^= ~0ULL;
+
+ *s = or128(*s, st8);
+ *s = or128(*s, st12);
+ *conf8 = movq(*s);
+ *s = rshiftbyte_m128(*s, 8);
+ *conf8 ^= ~0ULL;
+}
+
+static really_inline
+void do_confirm_fdr(u64a *conf, u8 offset, hwlmcb_rv_t *control,
+ const u32 *confBase, const struct FDR_Runtime_Args *a,
+ const u8 *ptr, u32 *last_match_id, struct zone *z) {
+ const u8 bucket = 8;
+
+ if (likely(!*conf)) {
+ return;
+ }
+
+ /* ptr is currently referring to a location in the zone's buffer, we also
+ * need a pointer in the original, main buffer for the final string compare.
+ */
+ const u8 *ptr_main = (const u8 *)((uintptr_t)ptr + z->zone_pointer_adjust);
+
+ const u8 *confLoc = ptr;
+
+ do {
+ u32 bit = findAndClearLSB_64(conf);
+ u32 byte = bit / bucket + offset;
+ u32 bitRem = bit % bucket;
+ u32 idx = bitRem;
+ u32 cf = confBase[idx];
+ if (!cf) {
+ continue;
+ }
+ const struct FDRConfirm *fdrc = (const struct FDRConfirm *)
+ ((const u8 *)confBase + cf);
+ if (!(fdrc->groups & *control)) {
+ continue;
+ }
+ u64a confVal = unaligned_load_u64a(confLoc + byte - sizeof(u64a) + 1);
+ confWithBit(fdrc, a, ptr_main - a->buf + byte, control,
+ last_match_id, confVal, conf, bit);
+ } while (unlikely(!!*conf));
+}
+
+static really_inline
+void dumpZoneInfo(UNUSED struct zone *z, UNUSED size_t zone_id) {
+#ifdef DEBUG
+ DEBUG_PRINTF("zone: zone=%zu, bufPtr=%p\n", zone_id, z->buf);
+ DEBUG_PRINTF("zone: startPtr=%p, endPtr=%p, shift=%u\n",
+ z->start, z->end, z->shift);
+ DEBUG_PRINTF("zone: zone_pointer_adjust=%zd, floodPtr=%p\n",
+ z->zone_pointer_adjust, z->floodPtr);
+ DEBUG_PRINTF("zone buf:");
+ for (size_t i = 0; i < ZONE_TOTAL_SIZE; i++) {
+ if (i % 8 == 0) {
+ printf("_");
+ }
+ if (z->buf[i]) {
+ printf("%02x", z->buf[i]);
+ } else {
+ printf("..");
+ }
+ }
+ printf("\n");
+#endif
+};
+
+/**
+ * \brief Updates attributes for non-boundary region zone.
+ */
+static really_inline
+void createMainZone(const u8 *flood, const u8 *begin, const u8 *end,
+ struct zone *z) {
+ z->zone_pointer_adjust = 0; /* zone buffer is the main buffer */
+ z->start = begin;
+ z->end = end;
+ z->floodPtr = flood;
+ z->shift = 0;
+}
+
+/**
+ * \brief Create zone for short cases (<= ITER_BYTES).
+ *
+ * For this case we need to copy everything into the zone's internal buffer.
+ *
+ * We need to ensure that we run over real data if it exists (in history or
+ * before zone begin). We also need to ensure 8 bytes before any data being
+ * matched can be read (to perform a conf hash).
+ *
+ * We also need to ensure that the data at z->end can be read.
+ *
+ * Hence, the zone consists of:
+ * 16 bytes of history,
+ * 1 - 24 bytes of data form the buffer (ending at end),
+ * 1 byte of final padding
+ */
+static really_inline
+void createShortZone(const u8 *buf, const u8 *hend, const u8 *begin,
+ const u8 *end, struct zone *z) {
+ /* the floodPtr for BOUNDARY zones are maximum of end of zone buf to avoid
+ * the checks in boundary zone. */
+ z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
+
+ ptrdiff_t z_len = end - begin;
+ assert(z_len > 0);
+ assert(z_len <= ITER_BYTES);
+
+ z->shift = ITER_BYTES - z_len; /* ignore bytes outside region specified */
+
+ static const size_t ZONE_SHORT_DATA_OFFSET = 16; /* after history */
+
+ /* we are guaranteed to always have 16 initialised bytes at the end of
+ * the history buffer (they may be garbage coming from the stream state
+ * preceding hbuf, but bytes that don't correspond to actual history
+ * shouldn't affect computations). */
+ *(m128 *)z->buf = loadu128(hend - sizeof(m128));
+
+ /* The amount of data we have to copy from main buffer. */
+ size_t copy_len = MIN((size_t)(end - buf),
+ ITER_BYTES + sizeof(CONF_TYPE));
+
+ u8 *zone_data = z->buf + ZONE_SHORT_DATA_OFFSET;
+ switch (copy_len) {
+ case 1:
+ *zone_data = *(end - 1);
+ break;
+ case 2:
+ *(u16 *)zone_data = unaligned_load_u16(end - 2);
+ break;
+ case 3:
+ *(u16 *)zone_data = unaligned_load_u16(end - 3);
+ *(zone_data + 2) = *(end - 1);
+ break;
+ case 4:
+ *(u32 *)zone_data = unaligned_load_u32(end - 4);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ /* perform copy with 2 overlapping 4-byte chunks from buf. */
+ *(u32 *)zone_data = unaligned_load_u32(end - copy_len);
+ unaligned_store_u32(zone_data + copy_len - sizeof(u32),
+ unaligned_load_u32(end - sizeof(u32)));
+ break;
+ case 8:
+ *(u64a *)zone_data = unaligned_load_u64a(end - 8);
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* perform copy with 2 overlapping 8-byte chunks from buf. */
+ *(u64a *)zone_data = unaligned_load_u64a(end - copy_len);
+ unaligned_store_u64a(zone_data + copy_len - sizeof(u64a),
+ unaligned_load_u64a(end - sizeof(u64a)));
+ break;
+ case 16:
+ /* copy 16-bytes from buf. */
+ *(m128 *)zone_data = loadu128(end - 16);
+ break;
+ default:
+ assert(copy_len <= sizeof(m128) + sizeof(u64a));
+
+ /* perform copy with (potentially overlapping) 8-byte and 16-byte chunks.
+ */
+ *(u64a *)zone_data = unaligned_load_u64a(end - copy_len);
+ storeu128(zone_data + copy_len - sizeof(m128),
+ loadu128(end - sizeof(m128)));
+ break;
+ }
+
+ /* set the start and end location of the zone buf
+ * to be scanned */
+ u8 *z_end = z->buf + ZONE_SHORT_DATA_OFFSET + copy_len;
+ assert(ZONE_SHORT_DATA_OFFSET + copy_len >= ITER_BYTES);
+
+ /* copy the post-padding byte; this is required for domain > 8 due to
+ * overhang */
+ assert(ZONE_SHORT_DATA_OFFSET + copy_len + 3 < 64);
+ *z_end = 0;
+
+ z->end = z_end;
+ z->start = z_end - ITER_BYTES;
+ z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
+ assert(z->start + z->shift == z_end - z_len);
+}
+
+/**
+ * \brief Create a zone for the start region.
+ *
+ * This function requires that there is > ITER_BYTES of data in the buffer to
+ * scan. The start zone itself is always responsible for scanning exactly
+ * ITER_BYTES of data - there are no warmup/junk bytes scanned.
+ *
+ * This zone ensures that the byte at z->end can be read and corresponds to
+ * the next byte of data.
+ *
+ * 8 bytes of history data are provided before z->start to allow proper hash
+ * generation in streaming mode. If buf != begin, upto 8 bytes of data
+ * prior to begin is also provided.
+ *
+ * Although we are not interested in bare literals which start before begin
+ * if buf != begin, lookarounds associated with the literal may require
+ * the data prior to begin for hash purposes.
+ */
+static really_inline
+void createStartZone(const u8 *buf, const u8 *hend, const u8 *begin,
+ struct zone *z) {
+ assert(ITER_BYTES == sizeof(m128));
+ assert(sizeof(CONF_TYPE) == 8);
+ static const size_t ZONE_START_BEGIN = sizeof(CONF_TYPE);
+
+ const u8 *end = begin + ITER_BYTES;
+
+ /* set floodPtr to the end of zone buf to avoid checks in start zone */
+ z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
+
+ z->shift = 0; /* we are processing ITER_BYTES of real data */
+
+ /* we are guaranteed to always have 16 initialised bytes at the end of the
+ * history buffer (they may be garbage coming from the stream state
+ * preceding hbuf, but bytes that don't correspond to actual history
+ * shouldn't affect computations). However, for start zones, history is only
+ * required for conf hash purposes so we only need 8 bytes */
+ unaligned_store_u64a(z->buf, unaligned_load_u64a(hend - sizeof(u64a)));
+
+ /* The amount of data we have to copy from main buffer. */
+ size_t copy_len = MIN((size_t)(end - buf),
+ ITER_BYTES + sizeof(CONF_TYPE));
+ assert(copy_len >= 16);
+
+ /* copy the post-padding byte; this is required for domain > 8 due to
+ * overhang. The start requires that there is data after the zone so it
+ * it safe to dereference end */
+ z->buf[ZONE_START_BEGIN + copy_len] = *end;
+
+ /* set the start and end location of the zone buf to be scanned */
+ u8 *z_end = z->buf + ZONE_START_BEGIN + copy_len;
+ z->end = z_end;
+ z->start = z_end - ITER_BYTES;
+
+ /* copy the first 8 bytes of the valid region */
+ unaligned_store_u64a(z->buf + ZONE_START_BEGIN,
+ unaligned_load_u64a(end - copy_len));
+
+ /* copy the last 16 bytes, may overlap with the previous 8 byte write */
+ storeu128(z_end - sizeof(m128), loadu128(end - sizeof(m128)));
+
+ z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
+
+ assert(ZONE_START_BEGIN + copy_len + 3 < 64);
+}
+
+/**
+ * \brief Create a zone for the end region.
+ *
+ * This function requires that there is > ITER_BYTES of data in the buffer to
+ * scan. The end zone is responsible for a scanning the <= ITER_BYTES rump of
+ * data and optional ITER_BYTES. The main zone cannot handle the last 3 bytes
+ * of the buffer. The end zone is required to handle an optional full
+ * ITER_BYTES from main zone when there are less than 3 bytes to scan. The
+ * main zone size is reduced by ITER_BYTES in this case.
+ *
+ * This zone ensures that the byte at z->end can be read by filling it with a
+ * padding character.
+ *
+ * Upto 8 bytes of data prior to begin is also provided for the purposes of
+ * generating hashes. History is not copied, as all locations which require
+ * history for generating a hash are the responsiblity of the start zone.
+ */
+static really_inline
+void createEndZone(const u8 *buf, const u8 *begin, const u8 *end,
+ struct zone *z) {
+ /* the floodPtr for BOUNDARY zones are maximum of end of zone buf to avoid
+ * the checks in boundary zone. */
+ z->floodPtr = z->buf + ZONE_TOTAL_SIZE;
+
+ ptrdiff_t z_len = end - begin;
+ assert(z_len > 0);
+ size_t iter_bytes_second = 0;
+ size_t z_len_first = z_len;
+ if (z_len > ITER_BYTES) {
+ z_len_first = z_len - ITER_BYTES;
+ iter_bytes_second = ITER_BYTES;
+ }
+ z->shift = ITER_BYTES - z_len_first;
+
+ const u8 *end_first = end - iter_bytes_second;
+ /* The amount of data we have to copy from main buffer for the
+ * first iteration. */
+ size_t copy_len_first = MIN((size_t)(end_first - buf),
+ ITER_BYTES + sizeof(CONF_TYPE));
+ assert(copy_len_first >= 16);
+
+ size_t total_copy_len = copy_len_first + iter_bytes_second;
+ assert(total_copy_len + 3 < 64);
+
+ /* copy the post-padding byte; this is required for domain > 8 due to
+ * overhang */
+ z->buf[total_copy_len] = 0;
+
+ /* set the start and end location of the zone buf
+ * to be scanned */
+ u8 *z_end = z->buf + total_copy_len;
+ z->end = z_end;
+ z->start = z_end - ITER_BYTES - iter_bytes_second;
+ assert(z->start + z->shift == z_end - z_len);
+
+ u8 *z_end_first = z_end - iter_bytes_second;
+ /* copy the first 8 bytes of the valid region */
+ unaligned_store_u64a(z->buf,
+ unaligned_load_u64a(end_first - copy_len_first));
+
+ /* copy the last 16 bytes, may overlap with the previous 8 byte write */
+ storeu128(z_end_first - sizeof(m128), loadu128(end_first - sizeof(m128)));
+ if (iter_bytes_second) {
+ storeu128(z_end - sizeof(m128), loadu128(end - sizeof(m128)));
+ }
+
+ z->zone_pointer_adjust = (ptrdiff_t)((uintptr_t)end - (uintptr_t)z_end);
+}
+
+/**
+ * \brief Prepare zones.
+ *
+ * This function prepares zones with actual buffer and some padded bytes.
+ * The actual ITER_BYTES bytes in zone is preceded by main buf and/or
+ * history buf and succeeded by padded bytes possibly from main buf,
+ * if available.
+ */
+static really_inline
+size_t prepareZones(const u8 *buf, size_t len, const u8 *hend,
+ size_t start, const u8 *flood, struct zone *zoneArr) {
+ const u8 *ptr = buf + start;
+ size_t remaining = len - start;
+
+ if (remaining <= ITER_BYTES) {
+ /* enough bytes to make only one zone */
+ createShortZone(buf, hend, ptr, buf + len, &zoneArr[0]);
+ return 1;
+ }
+
+ /* enough bytes to make more than one zone */
+
+ size_t numZone = 0;
+ createStartZone(buf, hend, ptr, &zoneArr[numZone++]);
+ ptr += ITER_BYTES;
+
+ assert(ptr < buf + len);
+
+ /* find maximum buffer location that the main zone can scan
+ * - must be a multiple of ITER_BYTES, and
+ * - cannot contain the last 3 bytes (due to 3 bytes read behind the
+ end of buffer in FDR main loop)
+ */
+ const u8 *main_end = buf + start + ROUNDDOWN_N(len - start - 3, ITER_BYTES);
+
+ /* create a zone if multiple of ITER_BYTES are found */
+ if (main_end > ptr) {
+ createMainZone(flood, ptr, main_end, &zoneArr[numZone++]);
+ ptr = main_end;
+ }
+ /* create a zone with rest of the data from the main buffer */
+ createEndZone(buf, ptr, buf + len, &zoneArr[numZone++]);
+ return numZone;
+}
+
+#define INVALID_MATCH_ID (~0U)
+
+#define FDR_MAIN_LOOP(zz, s, get_conf_fn) \
+ do { \
+ const u8 *tryFloodDetect = zz->floodPtr; \
+ const u8 *start_ptr = zz->start; \
+ const u8 *end_ptr = zz->end; \
+ \
+ for (const u8 *itPtr = start_ptr; itPtr + ITER_BYTES <= end_ptr; \
+ itPtr += ITER_BYTES) { \
+ if (unlikely(itPtr > tryFloodDetect)) { \
+ tryFloodDetect = floodDetect(fdr, a, &itPtr, tryFloodDetect,\
+ &floodBackoff, &control, \
+ ITER_BYTES); \
+ if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
+ return HWLM_TERMINATED; \
+ } \
+ } \
+ __builtin_prefetch(itPtr + ITER_BYTES); \
+ u64a conf0; \
+ u64a conf8; \
+ get_conf_fn(itPtr, start_ptr, end_ptr, domain_mask_flipped, \
+ ft, &conf0, &conf8, &s); \
+ do_confirm_fdr(&conf0, 0, &control, confBase, a, itPtr, \
+ &last_match_id, zz); \
+ do_confirm_fdr(&conf8, 8, &control, confBase, a, itPtr, \
+ &last_match_id, zz); \
+ if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
+ return HWLM_TERMINATED; \
+ } \
+ } /* end for loop */ \
+ } while (0) \
+
+static never_inline
+hwlm_error_t fdr_engine_exec(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ assert(ISALIGNED_CL(fdr));
+
+ u32 floodBackoff = FLOOD_BACKOFF_START;
+ u32 last_match_id = INVALID_MATCH_ID;
+ u32 domain_mask_flipped = ~fdr->domainMask;
+ u8 stride = fdr->stride;
+ const u64a *ft =
+ (const u64a *)((const u8 *)fdr + ROUNDUP_CL(sizeof(struct FDR)));
+ assert(ISALIGNED_CL(ft));
+ const u32 *confBase = (const u32 *)((const u8 *)fdr + fdr->confOffset);
+ assert(ISALIGNED_CL(confBase));
+ struct zone zones[ZONE_MAX];
+ assert(fdr->domain > 8 && fdr->domain < 16);
+
+ size_t numZone = prepareZones(a->buf, a->len,
+ a->buf_history + a->len_history,
+ a->start_offset, a->firstFloodDetect, zones);
+ assert(numZone <= ZONE_MAX);
+ m128 state = getInitState(fdr, a->len_history, ft, &zones[0]);
+
+ for (size_t curZone = 0; curZone < numZone; curZone++) {
+ struct zone *z = &zones[curZone];
+ dumpZoneInfo(z, curZone);
+
+ /* When a zone contains less data than is processed in an iteration
+ * of FDR_MAIN_LOOP(), we need to scan over some extra data.
+ *
+ * We have chosen to scan this extra data at the start of the
+ * iteration. The extra data is either data we have already scanned or
+ * garbage (if it is earlier than offset 0),
+ *
+ * As a result we need to shift the incoming state back so that it will
+ * properly line up with the data being scanned.
+ *
+ * We also need to forbid reporting any matches in the data being
+ * rescanned as they have already been reported (or are over garbage but
+ * later stages should also provide that safety guarantee).
+ */
+
+ u8 shift = z->shift;
+
+ state = variable_byte_shift_m128(state, shift);
+
+ state = or128(state, load128(zone_or_mask[shift]));
+
+ switch (stride) {
+ case 1:
+ FDR_MAIN_LOOP(z, state, get_conf_stride_1);
+ break;
+ case 2:
+ FDR_MAIN_LOOP(z, state, get_conf_stride_2);
+ break;
+ case 4:
+ FDR_MAIN_LOOP(z, state, get_conf_stride_4);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return HWLM_SUCCESS;
+}
+
+#if defined(HAVE_AVX2)
+#define ONLY_AVX2(func) func
+#else
+#define ONLY_AVX2(func) NULL
+#endif
+
+typedef hwlm_error_t (*FDRFUNCTYPE)(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+static const FDRFUNCTYPE funcs[] = {
+ fdr_engine_exec,
+ NULL, /* old: fast teddy */
+ NULL, /* old: fast teddy */
+ ONLY_AVX2(fdr_exec_fat_teddy_msks1),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks1_pck),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks2),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks2_pck),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks3),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks3_pck),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks4),
+ ONLY_AVX2(fdr_exec_fat_teddy_msks4_pck),
+ fdr_exec_teddy_msks1,
+ fdr_exec_teddy_msks1_pck,
+ fdr_exec_teddy_msks2,
+ fdr_exec_teddy_msks2_pck,
+ fdr_exec_teddy_msks3,
+ fdr_exec_teddy_msks3_pck,
+ fdr_exec_teddy_msks4,
+ fdr_exec_teddy_msks4_pck,
+};
+
#define FAKE_HISTORY_SIZE 16
static const u8 fake_history[FAKE_HISTORY_SIZE];
-hwlm_error_t fdrExec(const struct FDR *fdr, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb,
- struct hs_scratch *scratch, hwlm_group_t groups) {
- // We guarantee (for safezone construction) that it is safe to read 16
- // bytes before the end of the history buffer.
- const u8 *hbuf = fake_history + FAKE_HISTORY_SIZE;
+hwlm_error_t fdrExec(const struct FDR *fdr, const u8 *buf, size_t len,
+ size_t start, HWLMCallback cb,
+ struct hs_scratch *scratch, hwlm_group_t groups) {
+ // We guarantee (for safezone construction) that it is safe to read 16
+ // bytes before the end of the history buffer.
+ const u8 *hbuf = fake_history + FAKE_HISTORY_SIZE;
const struct FDR_Runtime_Args a = {
buf,
len,
- hbuf,
+ hbuf,
0,
start,
cb,
- scratch,
+ scratch,
nextFloodDetect(buf, len, FLOOD_BACKOFF_START),
0
};
@@ -846,15 +846,15 @@ hwlm_error_t fdrExec(const struct FDR *fdr, const u8 *buf, size_t len,
return HWLM_SUCCESS;
} else {
assert(funcs[fdr->engineID]);
- return funcs[fdr->engineID](fdr, &a, groups);
+ return funcs[fdr->engineID](fdr, &a, groups);
}
}
hwlm_error_t fdrExecStreaming(const struct FDR *fdr, const u8 *hbuf,
size_t hlen, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb,
- struct hs_scratch *scratch,
- hwlm_group_t groups) {
+ size_t start, HWLMCallback cb,
+ struct hs_scratch *scratch,
+ hwlm_group_t groups) {
struct FDR_Runtime_Args a = {
buf,
len,
@@ -862,11 +862,11 @@ hwlm_error_t fdrExecStreaming(const struct FDR *fdr, const u8 *hbuf,
hlen,
start,
cb,
- scratch,
+ scratch,
nextFloodDetect(buf, len, FLOOD_BACKOFF_START),
- /* we are guaranteed to always have 16 initialised bytes at the end of
- * the history buffer (they may be garbage). */
- hbuf ? unaligned_load_u64a(hbuf + hlen - sizeof(u64a)) : (u64a)0
+ /* we are guaranteed to always have 16 initialised bytes at the end of
+ * the history buffer (they may be garbage). */
+ hbuf ? unaligned_load_u64a(hbuf + hlen - sizeof(u64a)) : (u64a)0
};
hwlm_error_t ret;
@@ -874,7 +874,7 @@ hwlm_error_t fdrExecStreaming(const struct FDR *fdr, const u8 *hbuf,
ret = HWLM_SUCCESS;
} else {
assert(funcs[fdr->engineID]);
- ret = funcs[fdr->engineID](fdr, &a, groups);
+ ret = funcs[fdr->engineID](fdr, &a, groups);
}
return ret;
diff --git a/contrib/libs/hyperscan/src/fdr/fdr.h b/contrib/libs/hyperscan/src/fdr/fdr.h
index 30ee1460967..4dcef851d62 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,7 +42,7 @@ extern "C" {
#endif
struct FDR;
-struct hs_scratch;
+struct hs_scratch;
/**
* \brief Block-mode scan.
@@ -50,13 +50,13 @@ struct hs_scratch;
* \param fdr FDR matcher engine.
* \param buf Buffer to scan.
* \param len Length of buffer to scan.
- * \param start First offset in buf at which a match may start.
+ * \param start First offset in buf at which a match may start.
* \param cb Callback to call when a match is found.
- * \param scratch Scratch supplied to callback on match.
+ * \param scratch Scratch supplied to callback on match.
* \param groups Initial groups mask.
*/
hwlm_error_t fdrExec(const struct FDR *fdr, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb, struct hs_scratch *scratch,
+ size_t start, HWLMCallback cb, struct hs_scratch *scratch,
hwlm_group_t groups);
/**
@@ -67,16 +67,16 @@ hwlm_error_t fdrExec(const struct FDR *fdr, const u8 *buf, size_t len,
* \param hlen Length of history buffer (hbuf).
* \param buf Buffer to scan.
* \param len Length of buffer to scan (buf).
- * \param start First offset in buf at which a match may start.
+ * \param start First offset in buf at which a match may start.
* \param cb Callback to call when a match is found.
- * \param scratch Scratch supplied to callback on match.
+ * \param scratch Scratch supplied to callback on match.
* \param groups Initial groups mask.
*/
hwlm_error_t fdrExecStreaming(const struct FDR *fdr, const u8 *hbuf,
size_t hlen, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb,
- struct hs_scratch *scratch,
- hwlm_group_t groups);
+ size_t start, HWLMCallback cb,
+ struct hs_scratch *scratch,
+ hwlm_group_t groups);
#ifdef __cplusplus
}
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_compile.cpp b/contrib/libs/hyperscan/src/fdr/fdr_compile.cpp
index 5e0d16ada6e..fcfc08638e8 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_compile.cpp
+++ b/contrib/libs/hyperscan/src/fdr/fdr_compile.cpp
@@ -29,9 +29,9 @@
/** \file
* \brief FDR literal matcher: build API.
*/
-
-#include "fdr_compile.h"
-
+
+#include "fdr_compile.h"
+
#include "fdr_internal.h"
#include "fdr_confirm.h"
#include "fdr_compile_internal.h"
@@ -40,35 +40,35 @@
#include "teddy_engine_description.h"
#include "grey.h"
#include "ue2common.h"
-#include "hwlm/hwlm_build.h"
+#include "hwlm/hwlm_build.h"
#include "util/compare.h"
-#include "util/container.h"
+#include "util/container.h"
#include "util/dump_mask.h"
-#include "util/make_unique.h"
-#include "util/math.h"
-#include "util/noncopyable.h"
+#include "util/make_unique.h"
+#include "util/math.h"
+#include "util/noncopyable.h"
#include "util/target_info.h"
#include "util/ue2string.h"
#include "util/verify_types.h"
#include <algorithm>
-#include <array>
+#include <array>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <limits>
+#include <limits>
#include <map>
#include <memory>
-#include <numeric>
+#include <numeric>
#include <set>
#include <string>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
-#include <boost/multi_array.hpp>
+#include <boost/multi_array.hpp>
using namespace std;
@@ -76,12 +76,12 @@ namespace ue2 {
namespace {
-class FDRCompiler : noncopyable {
+class FDRCompiler : noncopyable {
private:
const FDREngineDescription &eng;
- const Grey &grey;
+ const Grey &grey;
vector<u8> tab;
- vector<hwlmLiteral> lits;
+ vector<hwlmLiteral> lits;
map<BucketIndex, std::vector<LiteralIndex> > bucketToLits;
bool make_small;
@@ -90,19 +90,19 @@ private:
void dumpMasks(const u8 *defaultMask);
#endif
void setupTab();
- bytecode_ptr<FDR> setupFDR();
+ bytecode_ptr<FDR> setupFDR();
void createInitialState(FDR *fdr);
public:
- FDRCompiler(vector<hwlmLiteral> lits_in,
- map<BucketIndex, std::vector<LiteralIndex>> bucketToLits_in,
- const FDREngineDescription &eng_in,
- bool make_small_in, const Grey &grey_in)
- : eng(eng_in), grey(grey_in), tab(eng_in.getTabSizeBytes()),
- lits(move(lits_in)), bucketToLits(move(bucketToLits_in)),
+ FDRCompiler(vector<hwlmLiteral> lits_in,
+ map<BucketIndex, std::vector<LiteralIndex>> bucketToLits_in,
+ const FDREngineDescription &eng_in,
+ bool make_small_in, const Grey &grey_in)
+ : eng(eng_in), grey(grey_in), tab(eng_in.getTabSizeBytes()),
+ lits(move(lits_in)), bucketToLits(move(bucketToLits_in)),
make_small(make_small_in) {}
- bytecode_ptr<FDR> build();
+ bytecode_ptr<FDR> build();
};
u8 *FDRCompiler::tabIndexToMask(u32 indexInTable) {
@@ -136,8 +136,8 @@ void FDRCompiler::createInitialState(FDR *fdr) {
// Find the minimum length for the literals in this bucket.
const vector<LiteralIndex> &bucket_lits = bucketToLits[b];
u32 min_len = ~0U;
- for (const LiteralIndex &lit_idx : bucket_lits) {
- min_len = min(min_len, verify_u32(lits[lit_idx].s.length()));
+ for (const LiteralIndex &lit_idx : bucket_lits) {
+ min_len = min(min_len, verify_u32(lits[lit_idx].s.length()));
}
DEBUG_PRINTF("bucket %u has min_len=%u\n", b, min_len);
@@ -151,364 +151,364 @@ void FDRCompiler::createInitialState(FDR *fdr) {
}
}
-/**
- * \brief Lay out FDR structures in bytecode.
- *
- * Note that each major structure (header, table, confirm, flood control) is
- * cacheline-aligned.
- */
-bytecode_ptr<FDR> FDRCompiler::setupFDR() {
- auto floodTable = setupFDRFloodControl(lits, eng, grey);
- auto confirmTable = setupFullConfs(lits, eng, bucketToLits, make_small);
-
- size_t headerSize = sizeof(FDR);
+/**
+ * \brief Lay out FDR structures in bytecode.
+ *
+ * Note that each major structure (header, table, confirm, flood control) is
+ * cacheline-aligned.
+ */
+bytecode_ptr<FDR> FDRCompiler::setupFDR() {
+ auto floodTable = setupFDRFloodControl(lits, eng, grey);
+ auto confirmTable = setupFullConfs(lits, eng, bucketToLits, make_small);
+
+ size_t headerSize = sizeof(FDR);
size_t tabSize = eng.getTabSizeBytes();
- // Note: we place each major structure here on a cacheline boundary.
- size_t size = ROUNDUP_CL(headerSize) + ROUNDUP_CL(tabSize) +
- ROUNDUP_CL(confirmTable.size()) + floodTable.size();
+ // Note: we place each major structure here on a cacheline boundary.
+ size_t size = ROUNDUP_CL(headerSize) + ROUNDUP_CL(tabSize) +
+ ROUNDUP_CL(confirmTable.size()) + floodTable.size();
DEBUG_PRINTF("sizes base=%zu tabSize=%zu confirm=%zu floodControl=%zu "
"total=%zu\n",
- headerSize, tabSize, confirmTable.size(), floodTable.size(),
+ headerSize, tabSize, confirmTable.size(), floodTable.size(),
size);
- auto fdr = make_zeroed_bytecode_ptr<FDR>(size, 64);
+ auto fdr = make_zeroed_bytecode_ptr<FDR>(size, 64);
assert(fdr); // otherwise would have thrown std::bad_alloc
- u8 *fdr_base = (u8 *)fdr.get();
-
- // Write header.
+ u8 *fdr_base = (u8 *)fdr.get();
+
+ // Write header.
fdr->size = size;
fdr->engineID = eng.getID();
fdr->maxStringLen = verify_u32(maxLen(lits));
- fdr->numStrings = verify_u32(lits.size());
- assert(eng.bits > 8 && eng.bits < 16); // we allow domains 9 to 15 only
- fdr->domain = eng.bits;
- fdr->domainMask = (1 << eng.bits) - 1;
- fdr->tabSize = tabSize;
- fdr->stride = eng.stride;
+ fdr->numStrings = verify_u32(lits.size());
+ assert(eng.bits > 8 && eng.bits < 16); // we allow domains 9 to 15 only
+ fdr->domain = eng.bits;
+ fdr->domainMask = (1 << eng.bits) - 1;
+ fdr->tabSize = tabSize;
+ fdr->stride = eng.stride;
createInitialState(fdr.get());
- // Write table.
- u8 *ptr = fdr_base + ROUNDUP_CL(sizeof(FDR));
- assert(ISALIGNED_CL(ptr));
+ // Write table.
+ u8 *ptr = fdr_base + ROUNDUP_CL(sizeof(FDR));
+ assert(ISALIGNED_CL(ptr));
copy(tab.begin(), tab.end(), ptr);
- ptr += ROUNDUP_CL(tabSize);
+ ptr += ROUNDUP_CL(tabSize);
- // Write confirm structures.
- assert(ISALIGNED_CL(ptr));
- fdr->confOffset = verify_u32(ptr - fdr_base);
- memcpy(ptr, confirmTable.get(), confirmTable.size());
- ptr += ROUNDUP_CL(confirmTable.size());
+ // Write confirm structures.
+ assert(ISALIGNED_CL(ptr));
+ fdr->confOffset = verify_u32(ptr - fdr_base);
+ memcpy(ptr, confirmTable.get(), confirmTable.size());
+ ptr += ROUNDUP_CL(confirmTable.size());
- // Write flood control structures.
- assert(ISALIGNED_CL(ptr));
+ // Write flood control structures.
+ assert(ISALIGNED_CL(ptr));
fdr->floodOffset = verify_u32(ptr - fdr_base);
- memcpy(ptr, floodTable.get(), floodTable.size());
- ptr += floodTable.size(); // last write, no need to round up
+ memcpy(ptr, floodTable.get(), floodTable.size());
+ ptr += floodTable.size(); // last write, no need to round up
return fdr;
}
-//#define DEBUG_ASSIGNMENT
-
-/**
- * Utility class for computing:
- *
- * score(count, len) = pow(count, 1.05) * pow(len, -3)
- *
- * Calling pow() is expensive. This is mitigated by using pre-computed LUTs for
- * small inputs and a cache for larger ones.
- */
-class Scorer {
- unordered_map<u32, double> count_factor_cache;
-
- // LUT: pow(count, 1.05) for small values of count.
- static const array<double, 100> count_lut;
-
- double count_factor(u32 count) {
- if (count < count_lut.size()) {
- return count_lut[count];
+//#define DEBUG_ASSIGNMENT
+
+/**
+ * Utility class for computing:
+ *
+ * score(count, len) = pow(count, 1.05) * pow(len, -3)
+ *
+ * Calling pow() is expensive. This is mitigated by using pre-computed LUTs for
+ * small inputs and a cache for larger ones.
+ */
+class Scorer {
+ unordered_map<u32, double> count_factor_cache;
+
+ // LUT: pow(count, 1.05) for small values of count.
+ static const array<double, 100> count_lut;
+
+ double count_factor(u32 count) {
+ if (count < count_lut.size()) {
+ return count_lut[count];
+ }
+
+ auto it = count_factor_cache.find(count);
+ if (it != count_factor_cache.end()) {
+ return it->second;
}
-
- auto it = count_factor_cache.find(count);
- if (it != count_factor_cache.end()) {
- return it->second;
- }
- double r = our_pow(count, 1.05);
- count_factor_cache.emplace(count, r);
- return r;
- }
-
- // LUT: pow(len, -3) for len in range [0,8].
- static const array<double, 9> len_lut;
-
- double len_factor(u32 len) {
- assert(len <= len_lut.size());
- return len_lut[len];
- }
-
-public:
- double operator()(u32 len, u32 count) {
- if (len == 0) {
- return numeric_limits<double>::max();
- }
- return count_factor(count) * len_factor(len);
- }
-};
-
-const array<double, 100> Scorer::count_lut{{
- pow(0, 1.05), pow(1, 1.05), pow(2, 1.05), pow(3, 1.05), pow(4, 1.05),
- pow(5, 1.05), pow(6, 1.05), pow(7, 1.05), pow(8, 1.05), pow(9, 1.05),
- pow(10, 1.05), pow(11, 1.05), pow(12, 1.05), pow(13, 1.05), pow(14, 1.05),
- pow(15, 1.05), pow(16, 1.05), pow(17, 1.05), pow(18, 1.05), pow(19, 1.05),
- pow(20, 1.05), pow(21, 1.05), pow(22, 1.05), pow(23, 1.05), pow(24, 1.05),
- pow(25, 1.05), pow(26, 1.05), pow(27, 1.05), pow(28, 1.05), pow(29, 1.05),
- pow(30, 1.05), pow(31, 1.05), pow(32, 1.05), pow(33, 1.05), pow(34, 1.05),
- pow(35, 1.05), pow(36, 1.05), pow(37, 1.05), pow(38, 1.05), pow(39, 1.05),
- pow(40, 1.05), pow(41, 1.05), pow(42, 1.05), pow(43, 1.05), pow(44, 1.05),
- pow(45, 1.05), pow(46, 1.05), pow(47, 1.05), pow(48, 1.05), pow(49, 1.05),
- pow(50, 1.05), pow(51, 1.05), pow(52, 1.05), pow(53, 1.05), pow(54, 1.05),
- pow(55, 1.05), pow(56, 1.05), pow(57, 1.05), pow(58, 1.05), pow(59, 1.05),
- pow(60, 1.05), pow(61, 1.05), pow(62, 1.05), pow(63, 1.05), pow(64, 1.05),
- pow(65, 1.05), pow(66, 1.05), pow(67, 1.05), pow(68, 1.05), pow(69, 1.05),
- pow(70, 1.05), pow(71, 1.05), pow(72, 1.05), pow(73, 1.05), pow(74, 1.05),
- pow(75, 1.05), pow(76, 1.05), pow(77, 1.05), pow(78, 1.05), pow(79, 1.05),
- pow(80, 1.05), pow(81, 1.05), pow(82, 1.05), pow(83, 1.05), pow(84, 1.05),
- pow(85, 1.05), pow(86, 1.05), pow(87, 1.05), pow(88, 1.05), pow(89, 1.05),
- pow(90, 1.05), pow(91, 1.05), pow(92, 1.05), pow(93, 1.05), pow(94, 1.05),
- pow(95, 1.05), pow(96, 1.05), pow(97, 1.05), pow(98, 1.05), pow(99, 1.05),
-}};
-
-const array<double, 9> Scorer::len_lut{{
+ double r = our_pow(count, 1.05);
+ count_factor_cache.emplace(count, r);
+ return r;
+ }
+
+ // LUT: pow(len, -3) for len in range [0,8].
+ static const array<double, 9> len_lut;
+
+ double len_factor(u32 len) {
+ assert(len <= len_lut.size());
+ return len_lut[len];
+ }
+
+public:
+ double operator()(u32 len, u32 count) {
+ if (len == 0) {
+ return numeric_limits<double>::max();
+ }
+ return count_factor(count) * len_factor(len);
+ }
+};
+
+const array<double, 100> Scorer::count_lut{{
+ pow(0, 1.05), pow(1, 1.05), pow(2, 1.05), pow(3, 1.05), pow(4, 1.05),
+ pow(5, 1.05), pow(6, 1.05), pow(7, 1.05), pow(8, 1.05), pow(9, 1.05),
+ pow(10, 1.05), pow(11, 1.05), pow(12, 1.05), pow(13, 1.05), pow(14, 1.05),
+ pow(15, 1.05), pow(16, 1.05), pow(17, 1.05), pow(18, 1.05), pow(19, 1.05),
+ pow(20, 1.05), pow(21, 1.05), pow(22, 1.05), pow(23, 1.05), pow(24, 1.05),
+ pow(25, 1.05), pow(26, 1.05), pow(27, 1.05), pow(28, 1.05), pow(29, 1.05),
+ pow(30, 1.05), pow(31, 1.05), pow(32, 1.05), pow(33, 1.05), pow(34, 1.05),
+ pow(35, 1.05), pow(36, 1.05), pow(37, 1.05), pow(38, 1.05), pow(39, 1.05),
+ pow(40, 1.05), pow(41, 1.05), pow(42, 1.05), pow(43, 1.05), pow(44, 1.05),
+ pow(45, 1.05), pow(46, 1.05), pow(47, 1.05), pow(48, 1.05), pow(49, 1.05),
+ pow(50, 1.05), pow(51, 1.05), pow(52, 1.05), pow(53, 1.05), pow(54, 1.05),
+ pow(55, 1.05), pow(56, 1.05), pow(57, 1.05), pow(58, 1.05), pow(59, 1.05),
+ pow(60, 1.05), pow(61, 1.05), pow(62, 1.05), pow(63, 1.05), pow(64, 1.05),
+ pow(65, 1.05), pow(66, 1.05), pow(67, 1.05), pow(68, 1.05), pow(69, 1.05),
+ pow(70, 1.05), pow(71, 1.05), pow(72, 1.05), pow(73, 1.05), pow(74, 1.05),
+ pow(75, 1.05), pow(76, 1.05), pow(77, 1.05), pow(78, 1.05), pow(79, 1.05),
+ pow(80, 1.05), pow(81, 1.05), pow(82, 1.05), pow(83, 1.05), pow(84, 1.05),
+ pow(85, 1.05), pow(86, 1.05), pow(87, 1.05), pow(88, 1.05), pow(89, 1.05),
+ pow(90, 1.05), pow(91, 1.05), pow(92, 1.05), pow(93, 1.05), pow(94, 1.05),
+ pow(95, 1.05), pow(96, 1.05), pow(97, 1.05), pow(98, 1.05), pow(99, 1.05),
+}};
+
+const array<double, 9> Scorer::len_lut{{
0, pow(1, -3.0), pow(2, -3.0), pow(3, -3.0), pow(4, -3.0),
pow(5, -3.0), pow(6, -3.0), pow(7, -3.0), pow(8, -3.0)}};
-/**
- * Returns true if the two given literals should be placed in the same chunk as
- * they are identical except for a difference in caselessness.
- */
-static
-bool isEquivLit(const hwlmLiteral &a, const hwlmLiteral &b,
- const hwlmLiteral *last_nocase_lit) {
- const size_t a_len = a.s.size();
- const size_t b_len = b.s.size();
-
- if (a_len != b_len) {
- return false;
- }
-
- bool nocase = last_nocase_lit && a_len == last_nocase_lit->s.size() &&
- !cmp(a.s.c_str(), last_nocase_lit->s.c_str(), a_len, true);
- return !cmp(a.s.c_str(), b.s.c_str(), a.s.size(), nocase);
-}
-
-struct Chunk {
- Chunk(u32 first_id_in, u32 count_in, u32 length_in)
- : first_id(first_id_in), count(count_in), length(length_in) {}
- u32 first_id; //!< first id in this chunk
- u32 count; //!< how many are in this chunk
- u32 length; //!< how long things in the chunk are
-};
-
-static
-vector<Chunk> assignChunks(const vector<hwlmLiteral> &lits,
- const map<u32, u32> &lenCounts) {
- const u32 CHUNK_MAX = 512;
+/**
+ * Returns true if the two given literals should be placed in the same chunk as
+ * they are identical except for a difference in caselessness.
+ */
+static
+bool isEquivLit(const hwlmLiteral &a, const hwlmLiteral &b,
+ const hwlmLiteral *last_nocase_lit) {
+ const size_t a_len = a.s.size();
+ const size_t b_len = b.s.size();
+
+ if (a_len != b_len) {
+ return false;
+ }
+
+ bool nocase = last_nocase_lit && a_len == last_nocase_lit->s.size() &&
+ !cmp(a.s.c_str(), last_nocase_lit->s.c_str(), a_len, true);
+ return !cmp(a.s.c_str(), b.s.c_str(), a.s.size(), nocase);
+}
+
+struct Chunk {
+ Chunk(u32 first_id_in, u32 count_in, u32 length_in)
+ : first_id(first_id_in), count(count_in), length(length_in) {}
+ u32 first_id; //!< first id in this chunk
+ u32 count; //!< how many are in this chunk
+ u32 length; //!< how long things in the chunk are
+};
+
+static
+vector<Chunk> assignChunks(const vector<hwlmLiteral> &lits,
+ const map<u32, u32> &lenCounts) {
+ const u32 CHUNK_MAX = 512;
const u32 MAX_CONSIDERED_LENGTH = 16;
-
- // TODO: detailed early stage literal analysis for v. small cases (actually
- // look at lits) yes - after we factor this out and merge in the Teddy
- // style of building we can look at this, although the teddy merge
- // modelling is quite different. It's still probably adaptable to some
- // extent for this class of problem.
-
- vector<Chunk> chunks;
- chunks.reserve(CHUNK_MAX);
-
- const u32 maxPerChunk = lits.size() /
- (CHUNK_MAX - MIN(MAX_CONSIDERED_LENGTH, lenCounts.size())) + 1;
-
+
+ // TODO: detailed early stage literal analysis for v. small cases (actually
+ // look at lits) yes - after we factor this out and merge in the Teddy
+ // style of building we can look at this, although the teddy merge
+ // modelling is quite different. It's still probably adaptable to some
+ // extent for this class of problem.
+
+ vector<Chunk> chunks;
+ chunks.reserve(CHUNK_MAX);
+
+ const u32 maxPerChunk = lits.size() /
+ (CHUNK_MAX - MIN(MAX_CONSIDERED_LENGTH, lenCounts.size())) + 1;
+
u32 currentSize = 0;
u32 chunkStartID = 0;
- const hwlmLiteral *last_nocase_lit = nullptr;
-
- for (u32 i = 0; i < lits.size() && chunks.size() < CHUNK_MAX - 1; i++) {
- const auto &lit = lits[i];
-
- DEBUG_PRINTF("i=%u, lit=%s%s\n", i, escapeString(lit.s).c_str(),
- lit.nocase ? " (nocase)" : "");
-
- // If this literal is identical to the last one (aside from differences
- // in caselessness), keep going even if we will "overfill" a chunk; we
- // don't want to split identical literals into different buckets.
- if (i != 0 && isEquivLit(lit, lits[i - 1], last_nocase_lit)) {
- DEBUG_PRINTF("identical lit\n");
- goto next_literal;
- }
-
- if ((currentSize < MAX_CONSIDERED_LENGTH &&
- (lit.s.size() != currentSize)) ||
+ const hwlmLiteral *last_nocase_lit = nullptr;
+
+ for (u32 i = 0; i < lits.size() && chunks.size() < CHUNK_MAX - 1; i++) {
+ const auto &lit = lits[i];
+
+ DEBUG_PRINTF("i=%u, lit=%s%s\n", i, escapeString(lit.s).c_str(),
+ lit.nocase ? " (nocase)" : "");
+
+ // If this literal is identical to the last one (aside from differences
+ // in caselessness), keep going even if we will "overfill" a chunk; we
+ // don't want to split identical literals into different buckets.
+ if (i != 0 && isEquivLit(lit, lits[i - 1], last_nocase_lit)) {
+ DEBUG_PRINTF("identical lit\n");
+ goto next_literal;
+ }
+
+ if ((currentSize < MAX_CONSIDERED_LENGTH &&
+ (lit.s.size() != currentSize)) ||
(currentSize != 1 && ((i - chunkStartID) >= maxPerChunk))) {
- currentSize = lit.s.size();
- if (!chunks.empty()) {
- chunks.back().count = i - chunkStartID;
+ currentSize = lit.s.size();
+ if (!chunks.empty()) {
+ chunks.back().count = i - chunkStartID;
}
- chunkStartID = i;
- chunks.emplace_back(i, 0, currentSize);
+ chunkStartID = i;
+ chunks.emplace_back(i, 0, currentSize);
+ }
+next_literal:
+ if (lit.nocase) {
+ last_nocase_lit = &lit;
}
-next_literal:
- if (lit.nocase) {
- last_nocase_lit = &lit;
- }
}
- assert(!chunks.empty());
- chunks.back().count = lits.size() - chunkStartID;
+ assert(!chunks.empty());
+ chunks.back().count = lits.size() - chunkStartID;
// close off chunks with an empty row
- chunks.emplace_back(lits.size(), 0, 0);
+ chunks.emplace_back(lits.size(), 0, 0);
#ifdef DEBUG_ASSIGNMENT
- for (size_t j = 0; j < chunks.size(); j++) {
- const auto &chunk = chunks[j];
- printf("chunk %zu first_id=%u count=%u length=%u\n", j, chunk.first_id,
- chunk.count, chunk.length);
+ for (size_t j = 0; j < chunks.size(); j++) {
+ const auto &chunk = chunks[j];
+ printf("chunk %zu first_id=%u count=%u length=%u\n", j, chunk.first_id,
+ chunk.count, chunk.length);
}
#endif
- DEBUG_PRINTF("built %zu chunks (%zu lits)\n", chunks.size(), lits.size());
- assert(chunks.size() <= CHUNK_MAX);
- return chunks;
-}
-
-static
-map<BucketIndex, vector<LiteralIndex>> assignStringsToBuckets(
- vector<hwlmLiteral> &lits,
- const FDREngineDescription &eng) {
- const double MAX_SCORE = numeric_limits<double>::max();
-
- assert(!lits.empty()); // Shouldn't be called with no literals.
-
- // Count the number of literals for each length.
- map<u32, u32> lenCounts;
- for (const auto &lit : lits) {
- lenCounts[lit.s.size()]++;
- }
-
-#ifdef DEBUG_ASSIGNMENT
- for (const auto &m : lenCounts) {
- printf("l<%u>:%u ", m.first, m.second);
- }
- printf("\n");
-#endif
-
- // Sort literals by literal length. If tied on length, use lexicographic
- // ordering (of the reversed literals).
- stable_sort(lits.begin(), lits.end(),
- [](const hwlmLiteral &a, const hwlmLiteral &b) {
- if (a.s.size() != b.s.size()) {
- return a.s.size() < b.s.size();
- }
- auto p = mismatch(a.s.rbegin(), a.s.rend(), b.s.rbegin());
- if (p.first != a.s.rend()) {
- return *p.first < *p.second;
- }
- // Sort caseless variants first.
- return a.nocase > b.nocase;
- });
-
- vector<Chunk> chunks = assignChunks(lits, lenCounts);
-
- const u32 numChunks = chunks.size();
- const u32 numBuckets = eng.getNumBuckets();
-
- // 2D array of (score, chunk index) pairs, indexed by
- // [chunk_index][bucket_index].
- boost::multi_array<pair<double, u32>, 2> t(
- boost::extents[numChunks][numBuckets]);
-
- Scorer scorer;
-
- for (u32 j = 0; j < numChunks; j++) {
+ DEBUG_PRINTF("built %zu chunks (%zu lits)\n", chunks.size(), lits.size());
+ assert(chunks.size() <= CHUNK_MAX);
+ return chunks;
+}
+
+static
+map<BucketIndex, vector<LiteralIndex>> assignStringsToBuckets(
+ vector<hwlmLiteral> &lits,
+ const FDREngineDescription &eng) {
+ const double MAX_SCORE = numeric_limits<double>::max();
+
+ assert(!lits.empty()); // Shouldn't be called with no literals.
+
+ // Count the number of literals for each length.
+ map<u32, u32> lenCounts;
+ for (const auto &lit : lits) {
+ lenCounts[lit.s.size()]++;
+ }
+
+#ifdef DEBUG_ASSIGNMENT
+ for (const auto &m : lenCounts) {
+ printf("l<%u>:%u ", m.first, m.second);
+ }
+ printf("\n");
+#endif
+
+ // Sort literals by literal length. If tied on length, use lexicographic
+ // ordering (of the reversed literals).
+ stable_sort(lits.begin(), lits.end(),
+ [](const hwlmLiteral &a, const hwlmLiteral &b) {
+ if (a.s.size() != b.s.size()) {
+ return a.s.size() < b.s.size();
+ }
+ auto p = mismatch(a.s.rbegin(), a.s.rend(), b.s.rbegin());
+ if (p.first != a.s.rend()) {
+ return *p.first < *p.second;
+ }
+ // Sort caseless variants first.
+ return a.nocase > b.nocase;
+ });
+
+ vector<Chunk> chunks = assignChunks(lits, lenCounts);
+
+ const u32 numChunks = chunks.size();
+ const u32 numBuckets = eng.getNumBuckets();
+
+ // 2D array of (score, chunk index) pairs, indexed by
+ // [chunk_index][bucket_index].
+ boost::multi_array<pair<double, u32>, 2> t(
+ boost::extents[numChunks][numBuckets]);
+
+ Scorer scorer;
+
+ for (u32 j = 0; j < numChunks; j++) {
u32 cnt = 0;
- for (u32 k = j; k < numChunks; ++k) {
- cnt += chunks[k].count;
+ for (u32 k = j; k < numChunks; ++k) {
+ cnt += chunks[k].count;
}
- t[j][0] = {scorer(chunks[j].length, cnt), 0};
+ t[j][0] = {scorer(chunks[j].length, cnt), 0};
}
- for (u32 i = 1; i < numBuckets; i++) {
- for (u32 j = 0; j < numChunks - 1; j++) { // don't do last, empty row
- pair<double, u32> best = {MAX_SCORE, 0};
- u32 cnt = chunks[j].count;
- for (u32 k = j + 1; k < numChunks - 1; k++) {
- auto score = scorer(chunks[j].length, cnt);
+ for (u32 i = 1; i < numBuckets; i++) {
+ for (u32 j = 0; j < numChunks - 1; j++) { // don't do last, empty row
+ pair<double, u32> best = {MAX_SCORE, 0};
+ u32 cnt = chunks[j].count;
+ for (u32 k = j + 1; k < numChunks - 1; k++) {
+ auto score = scorer(chunks[j].length, cnt);
if (score > best.first) {
- break; // now worse locally than our best score, give up
+ break; // now worse locally than our best score, give up
}
score += t[k][i-1].first;
if (score < best.first) {
- best = {score, k};
+ best = {score, k};
}
- cnt += chunks[k].count;
+ cnt += chunks[k].count;
}
t[j][i] = best;
}
- t[numChunks - 1][i] = {0,0}; // fill in empty final row for next iter
+ t[numChunks - 1][i] = {0,0}; // fill in empty final row for next iter
}
#ifdef DEBUG_ASSIGNMENT
- for (u32 j = 0; j < numChunks; j++) {
- printf("%03u: ", j);
- for (u32 i = 0; i < numBuckets; i++) {
- const auto &v = t[j][i];
- printf("<%0.3f,%3d> ", v.first, v.second);
+ for (u32 j = 0; j < numChunks; j++) {
+ printf("%03u: ", j);
+ for (u32 i = 0; i < numBuckets; i++) {
+ const auto &v = t[j][i];
+ printf("<%0.3f,%3d> ", v.first, v.second);
}
printf("\n");
}
#endif
- // our best score is in t[0][N_BUCKETS-1] and we can follow the links
+ // our best score is in t[0][N_BUCKETS-1] and we can follow the links
// to find where our buckets should start and what goes into them
- vector<vector<LiteralIndex>> buckets;
- for (u32 i = 0, n = numBuckets; n && (i != numChunks - 1); n--) {
+ vector<vector<LiteralIndex>> buckets;
+ for (u32 i = 0, n = numBuckets; n && (i != numChunks - 1); n--) {
u32 j = t[i][n - 1].second;
if (j == 0) {
- j = numChunks - 1;
+ j = numChunks - 1;
}
-
- // put chunks between i - j into bucket (numBuckets - n).
- u32 first_id = chunks[i].first_id;
- u32 last_id = chunks[j].first_id;
- assert(first_id < last_id);
- UNUSED const auto &first_lit = lits[first_id];
- UNUSED const auto &last_lit = lits[last_id - 1];
- DEBUG_PRINTF("placing [%u-%u) in one bucket (%u lits, len %zu-%zu, "
- "score %0.4f)\n",
- first_id, last_id, last_id - first_id,
- first_lit.s.length(), last_lit.s.length(),
- scorer(first_lit.s.length(), last_id - first_id));
-
- vector<LiteralIndex> litIds;
- u32 cnt = last_id - first_id;
- // long literals first for included literals checking
- for (u32 k = 0; k < cnt; k++) {
- litIds.push_back(last_id - k - 1);
+
+ // put chunks between i - j into bucket (numBuckets - n).
+ u32 first_id = chunks[i].first_id;
+ u32 last_id = chunks[j].first_id;
+ assert(first_id < last_id);
+ UNUSED const auto &first_lit = lits[first_id];
+ UNUSED const auto &last_lit = lits[last_id - 1];
+ DEBUG_PRINTF("placing [%u-%u) in one bucket (%u lits, len %zu-%zu, "
+ "score %0.4f)\n",
+ first_id, last_id, last_id - first_id,
+ first_lit.s.length(), last_lit.s.length(),
+ scorer(first_lit.s.length(), last_id - first_id));
+
+ vector<LiteralIndex> litIds;
+ u32 cnt = last_id - first_id;
+ // long literals first for included literals checking
+ for (u32 k = 0; k < cnt; k++) {
+ litIds.push_back(last_id - k - 1);
}
-
+
i = j;
- buckets.push_back(litIds);
- }
-
- // reverse bucket id, longer literals come first
- map<BucketIndex, vector<LiteralIndex>> bucketToLits;
- size_t bucketCnt = buckets.size();
- for (size_t i = 0; i < bucketCnt; i++) {
- bucketToLits.emplace(bucketCnt - i - 1, move(buckets[i]));
- }
-
- return bucketToLits;
+ buckets.push_back(litIds);
+ }
+
+ // reverse bucket id, longer literals come first
+ map<BucketIndex, vector<LiteralIndex>> bucketToLits;
+ size_t bucketCnt = buckets.size();
+ for (size_t i = 0; i < bucketCnt; i++) {
+ bucketToLits.emplace(bucketCnt - i - 1, move(buckets[i]));
+ }
+
+ return bucketToLits;
}
#ifdef DEBUG
@@ -529,7 +529,7 @@ bool getMultiEntriesAtPosition(const FDREngineDescription &eng,
const vector<LiteralIndex> &vl,
const vector<hwlmLiteral> &lits,
SuffixPositionInString pos,
- map<u32, unordered_set<u32>> &m2) {
+ map<u32, unordered_set<u32>> &m2) {
assert(eng.bits < 32);
u32 distance = 0;
@@ -541,7 +541,7 @@ bool getMultiEntriesAtPosition(const FDREngineDescription &eng,
distance = 4;
}
- for (auto i = vl.begin(), e = vl.end(); i != e; ++i) {
+ for (auto i = vl.begin(), e = vl.end(); i != e; ++i) {
if (e - i > 5) {
__builtin_prefetch(&lits[*(i + 5)]);
}
@@ -600,20 +600,20 @@ void FDRCompiler::setupTab() {
SuffixPositionInString pLimit = eng.getBucketWidth(b);
for (SuffixPositionInString pos = 0; pos < pLimit; pos++) {
u32 bit = eng.getSchemeBit(b, pos);
- map<u32, unordered_set<u32>> m2;
+ map<u32, unordered_set<u32>> m2;
bool done = getMultiEntriesAtPosition(eng, vl, lits, pos, m2);
if (done) {
clearbit(&defaultMask[0], bit);
continue;
}
- for (const auto &elem : m2) {
- u32 dc = elem.first;
- const unordered_set<u32> &mskSet = elem.second;
+ for (const auto &elem : m2) {
+ u32 dc = elem.first;
+ const unordered_set<u32> &mskSet = elem.second;
u32 v = ~dc;
do {
u32 b2 = v & dc;
- for (const u32 &mskVal : mskSet) {
- u32 val = (mskVal & ~dc) | b2;
+ for (const u32 &mskVal : mskSet) {
+ u32 val = (mskVal & ~dc) | b2;
clearbit(tabIndexToMask(val), bit);
}
v = (v + (dc & -dc)) | ~dc;
@@ -631,230 +631,230 @@ void FDRCompiler::setupTab() {
#endif
}
-bytecode_ptr<FDR> FDRCompiler::build() {
+bytecode_ptr<FDR> FDRCompiler::build() {
setupTab();
- return setupFDR();
+ return setupFDR();
+}
+
+static
+bool isSuffix(const hwlmLiteral &lit1, const hwlmLiteral &lit2) {
+ const auto &s1 = lit1.s;
+ const auto &s2 = lit2.s;
+ size_t len1 = s1.length();
+ size_t len2 = s2.length();
+ assert(len1 >= len2);
+
+ if (lit1.nocase || lit2.nocase) {
+ return equal(s2.begin(), s2.end(), s1.begin() + len1 - len2,
+ [](char a, char b) { return mytoupper(a) == mytoupper(b); });
+ } else {
+ return equal(s2.begin(), s2.end(), s1.begin() + len1 - len2);
+ }
+}
+
+/*
+ * if lit2 is a suffix of lit1 but the case sensitivity, groups or mask info
+ * of lit2 is a subset of lit1, then lit1 can't squash lit2 and lit2 can
+ * possibly match when lit1 matches. In this case, we can't do bucket
+ * squashing. e.g. AAA(no case) in bucket 0, AA(no case) and aa in bucket 1,
+ * we can't squash bucket 1 if we have input like "aaa" as aa can also match.
+ */
+static
+bool includedCheck(const hwlmLiteral &lit1, const hwlmLiteral &lit2) {
+ /* lit1 is caseless and lit2 is case sensitive */
+ if ((lit1.nocase && !lit2.nocase)) {
+ return true;
+ }
+
+ /* lit2's group is a subset of lit1 */
+ if (lit1.groups != lit2.groups &&
+ (lit2.groups == (lit1.groups & lit2.groups))) {
+ return true;
+ }
+
+ /* TODO: narrow down cases for mask check */
+ if (lit1.cmp != lit2.cmp || lit1.msk != lit2.msk) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * if lit2 is an included literal of both lit0 and lit1, then lit0 and lit1
+ * shouldn't match at the same offset, otherwise we give up squashing for lit1.
+ * e.g. lit0:AAA(no case), lit1:aa, lit2:A(no case). We can have duplicate
+ * matches for input "aaa" if lit0 and lit1 both squash lit2.
+ */
+static
+bool checkParentLit(
+ const vector<hwlmLiteral> &lits, u32 pos1,
+ const unordered_set<u32> &parent_map,
+ const unordered_map<u32, unordered_set<u32>> &exception_map) {
+ assert(pos1 < lits.size());
+ const auto &lit1 = lits[pos1];
+ for (const auto pos2 : parent_map) {
+ if (contains(exception_map, pos2)) {
+ const auto &exception_pos = exception_map.at(pos2);
+ if (contains(exception_pos, pos1)) {
+ return false;
+ }
+ }
+
+ /* if lit1 isn't an exception of lit2, then we have to do further
+ * exclusive check.
+ * TODO: More mask checks. Note if two literals are group exclusive,
+ * it is possible that they match at the same offset. */
+ assert(pos2 < lits.size());
+ const auto &lit2 = lits[pos2];
+ if (isSuffix(lit2, lit1)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static
+void buildSquashMask(vector<hwlmLiteral> &lits, u32 id1, u32 bucket1,
+ size_t start, const vector<pair<u32, u32>> &group,
+ unordered_map<u32, unordered_set<u32>> &parent_map,
+ unordered_map<u32, unordered_set<u32>> &exception_map) {
+ auto &lit1 = lits[id1];
+ DEBUG_PRINTF("b:%u len:%zu\n", bucket1, lit1.s.length());
+
+ size_t cnt = group.size();
+ bool included = false;
+ bool exception = false;
+ u32 child_id = ~0U;
+ for (size_t i = start; i < cnt; i++) {
+ u32 bucket2 = group[i].first;
+ assert(bucket2 >= bucket1);
+
+ u32 id2 = group[i].second;
+ auto &lit2 = lits[id2];
+ // check if lit2 is a suffix of lit1
+ if (isSuffix(lit1, lit2)) {
+ /* if we have a included literal in the same bucket,
+ * quit and let the included literal to do possible squashing */
+ if (bucket1 == bucket2) {
+ DEBUG_PRINTF("same bucket\n");
+ return;
+ }
+ /* if lit2 is a suffix but doesn't pass included checks for
+ * extra info, we give up sqaushing */
+ if (includedCheck(lit1, lit2)) {
+ DEBUG_PRINTF("find exceptional suffix %u\n", lit2.id);
+ exception_map[id1].insert(id2);
+ exception = true;
+ } else if (checkParentLit(lits, id1, parent_map[id2],
+ exception_map)) {
+ if (lit1.included_id == INVALID_LIT_ID) {
+ DEBUG_PRINTF("find suffix lit1 %u lit2 %u\n",
+ lit1.id, lit2.id);
+ lit1.included_id = lit2.id;
+ } else {
+ /* if we have multiple included literals in one bucket,
+ * give up squashing. */
+ DEBUG_PRINTF("multiple included literals\n");
+ lit1.included_id = INVALID_LIT_ID;
+ return;
+ }
+ child_id = id2;
+ included = true;
+ }
+ }
+
+ size_t next = i + 1;
+ u32 nextBucket = next < cnt ? group[next].first : ~0U;
+ if (bucket2 != nextBucket) {
+ if (included) {
+ if (exception) {
+ /* give up if we have exception literals
+ * in the same bucket as the included literal. */
+ lit1.included_id = INVALID_LIT_ID;
+ } else {
+ parent_map[child_id].insert(id1);
+
+ lit1.squash |= 1U << bucket2;
+ DEBUG_PRINTF("build squash mask %2x for %u\n",
+ lit1.squash, lit1.id);
+ }
+ return;
+ }
+ exception = false;
+ }
+ }
+}
+
+static constexpr u32 INCLUDED_LIMIT = 1000;
+
+static
+void findIncludedLits(vector<hwlmLiteral> &lits,
+ const vector<vector<pair<u32, u32>>> &lastCharMap) {
+ /* Map for finding the positions of literal which includes a literal
+ * in FDR hwlm literal vector. */
+ unordered_map<u32, unordered_set<u32>> parent_map;
+
+ /* Map for finding the positions of exception literals which could
+ * sometimes match if a literal matches in FDR hwlm literal vector. */
+ unordered_map<u32, unordered_set<u32>> exception_map;
+ for (const auto &group : lastCharMap) {
+ size_t cnt = group.size();
+ if (cnt > INCLUDED_LIMIT) {
+ continue;
+ }
+ for (size_t i = 0; i < cnt; i++) {
+ u32 bucket1 = group[i].first;
+ u32 id1 = group[i].second;
+ buildSquashMask(lits, id1, bucket1, i + 1, group, parent_map,
+ exception_map);
+ }
+ }
}
-static
-bool isSuffix(const hwlmLiteral &lit1, const hwlmLiteral &lit2) {
- const auto &s1 = lit1.s;
- const auto &s2 = lit2.s;
- size_t len1 = s1.length();
- size_t len2 = s2.length();
- assert(len1 >= len2);
-
- if (lit1.nocase || lit2.nocase) {
- return equal(s2.begin(), s2.end(), s1.begin() + len1 - len2,
- [](char a, char b) { return mytoupper(a) == mytoupper(b); });
- } else {
- return equal(s2.begin(), s2.end(), s1.begin() + len1 - len2);
- }
-}
-
-/*
- * if lit2 is a suffix of lit1 but the case sensitivity, groups or mask info
- * of lit2 is a subset of lit1, then lit1 can't squash lit2 and lit2 can
- * possibly match when lit1 matches. In this case, we can't do bucket
- * squashing. e.g. AAA(no case) in bucket 0, AA(no case) and aa in bucket 1,
- * we can't squash bucket 1 if we have input like "aaa" as aa can also match.
- */
static
-bool includedCheck(const hwlmLiteral &lit1, const hwlmLiteral &lit2) {
- /* lit1 is caseless and lit2 is case sensitive */
- if ((lit1.nocase && !lit2.nocase)) {
- return true;
- }
-
- /* lit2's group is a subset of lit1 */
- if (lit1.groups != lit2.groups &&
- (lit2.groups == (lit1.groups & lit2.groups))) {
- return true;
- }
-
- /* TODO: narrow down cases for mask check */
- if (lit1.cmp != lit2.cmp || lit1.msk != lit2.msk) {
- return true;
- }
-
- return false;
-}
-
-/*
- * if lit2 is an included literal of both lit0 and lit1, then lit0 and lit1
- * shouldn't match at the same offset, otherwise we give up squashing for lit1.
- * e.g. lit0:AAA(no case), lit1:aa, lit2:A(no case). We can have duplicate
- * matches for input "aaa" if lit0 and lit1 both squash lit2.
- */
-static
-bool checkParentLit(
- const vector<hwlmLiteral> &lits, u32 pos1,
- const unordered_set<u32> &parent_map,
- const unordered_map<u32, unordered_set<u32>> &exception_map) {
- assert(pos1 < lits.size());
- const auto &lit1 = lits[pos1];
- for (const auto pos2 : parent_map) {
- if (contains(exception_map, pos2)) {
- const auto &exception_pos = exception_map.at(pos2);
- if (contains(exception_pos, pos1)) {
- return false;
- }
- }
-
- /* if lit1 isn't an exception of lit2, then we have to do further
- * exclusive check.
- * TODO: More mask checks. Note if two literals are group exclusive,
- * it is possible that they match at the same offset. */
- assert(pos2 < lits.size());
- const auto &lit2 = lits[pos2];
- if (isSuffix(lit2, lit1)) {
- return false;
- }
- }
-
- return true;
-}
-
-static
-void buildSquashMask(vector<hwlmLiteral> &lits, u32 id1, u32 bucket1,
- size_t start, const vector<pair<u32, u32>> &group,
- unordered_map<u32, unordered_set<u32>> &parent_map,
- unordered_map<u32, unordered_set<u32>> &exception_map) {
- auto &lit1 = lits[id1];
- DEBUG_PRINTF("b:%u len:%zu\n", bucket1, lit1.s.length());
-
- size_t cnt = group.size();
- bool included = false;
- bool exception = false;
- u32 child_id = ~0U;
- for (size_t i = start; i < cnt; i++) {
- u32 bucket2 = group[i].first;
- assert(bucket2 >= bucket1);
-
- u32 id2 = group[i].second;
- auto &lit2 = lits[id2];
- // check if lit2 is a suffix of lit1
- if (isSuffix(lit1, lit2)) {
- /* if we have a included literal in the same bucket,
- * quit and let the included literal to do possible squashing */
- if (bucket1 == bucket2) {
- DEBUG_PRINTF("same bucket\n");
- return;
- }
- /* if lit2 is a suffix but doesn't pass included checks for
- * extra info, we give up sqaushing */
- if (includedCheck(lit1, lit2)) {
- DEBUG_PRINTF("find exceptional suffix %u\n", lit2.id);
- exception_map[id1].insert(id2);
- exception = true;
- } else if (checkParentLit(lits, id1, parent_map[id2],
- exception_map)) {
- if (lit1.included_id == INVALID_LIT_ID) {
- DEBUG_PRINTF("find suffix lit1 %u lit2 %u\n",
- lit1.id, lit2.id);
- lit1.included_id = lit2.id;
- } else {
- /* if we have multiple included literals in one bucket,
- * give up squashing. */
- DEBUG_PRINTF("multiple included literals\n");
- lit1.included_id = INVALID_LIT_ID;
- return;
- }
- child_id = id2;
- included = true;
- }
- }
-
- size_t next = i + 1;
- u32 nextBucket = next < cnt ? group[next].first : ~0U;
- if (bucket2 != nextBucket) {
- if (included) {
- if (exception) {
- /* give up if we have exception literals
- * in the same bucket as the included literal. */
- lit1.included_id = INVALID_LIT_ID;
- } else {
- parent_map[child_id].insert(id1);
-
- lit1.squash |= 1U << bucket2;
- DEBUG_PRINTF("build squash mask %2x for %u\n",
- lit1.squash, lit1.id);
- }
- return;
- }
- exception = false;
- }
- }
-}
-
-static constexpr u32 INCLUDED_LIMIT = 1000;
-
-static
-void findIncludedLits(vector<hwlmLiteral> &lits,
- const vector<vector<pair<u32, u32>>> &lastCharMap) {
- /* Map for finding the positions of literal which includes a literal
- * in FDR hwlm literal vector. */
- unordered_map<u32, unordered_set<u32>> parent_map;
-
- /* Map for finding the positions of exception literals which could
- * sometimes match if a literal matches in FDR hwlm literal vector. */
- unordered_map<u32, unordered_set<u32>> exception_map;
- for (const auto &group : lastCharMap) {
- size_t cnt = group.size();
- if (cnt > INCLUDED_LIMIT) {
- continue;
- }
- for (size_t i = 0; i < cnt; i++) {
- u32 bucket1 = group[i].first;
- u32 id1 = group[i].second;
- buildSquashMask(lits, id1, bucket1, i + 1, group, parent_map,
- exception_map);
- }
- }
-}
-
-static
-void addIncludedInfo(
- vector<hwlmLiteral> &lits, u32 nBuckets,
- map<BucketIndex, vector<LiteralIndex>> &bucketToLits) {
- vector<vector<pair<u32, u32>>> lastCharMap(256);
-
- for (BucketIndex b = 0; b < nBuckets; b++) {
- if (!bucketToLits[b].empty()) {
- for (const LiteralIndex &lit_idx : bucketToLits[b]) {
- const auto &lit = lits[lit_idx];
- u8 c = mytoupper(lit.s.back());
- lastCharMap[c].emplace_back(b, lit_idx);
- }
- }
- }
-
- findIncludedLits(lits, lastCharMap);
-}
-
-} // namespace
-
-static
-unique_ptr<HWLMProto> fdrBuildProtoInternal(u8 engType,
- vector<hwlmLiteral> &lits,
- bool make_small,
- const target_t &target,
- const Grey &grey, u32 hint) {
+void addIncludedInfo(
+ vector<hwlmLiteral> &lits, u32 nBuckets,
+ map<BucketIndex, vector<LiteralIndex>> &bucketToLits) {
+ vector<vector<pair<u32, u32>>> lastCharMap(256);
+
+ for (BucketIndex b = 0; b < nBuckets; b++) {
+ if (!bucketToLits[b].empty()) {
+ for (const LiteralIndex &lit_idx : bucketToLits[b]) {
+ const auto &lit = lits[lit_idx];
+ u8 c = mytoupper(lit.s.back());
+ lastCharMap[c].emplace_back(b, lit_idx);
+ }
+ }
+ }
+
+ findIncludedLits(lits, lastCharMap);
+}
+
+} // namespace
+
+static
+unique_ptr<HWLMProto> fdrBuildProtoInternal(u8 engType,
+ vector<hwlmLiteral> &lits,
+ bool make_small,
+ const target_t &target,
+ const Grey &grey, u32 hint) {
DEBUG_PRINTF("cpu has %s\n", target.has_avx2() ? "avx2" : "no-avx2");
if (grey.fdrAllowTeddy) {
- auto proto = teddyBuildProtoHinted(engType, lits, make_small, hint,
- target);
- if (proto) {
+ auto proto = teddyBuildProtoHinted(engType, lits, make_small, hint,
+ target);
+ if (proto) {
DEBUG_PRINTF("build with teddy succeeded\n");
- return proto;
+ return proto;
} else {
DEBUG_PRINTF("build with teddy failed, will try with FDR\n");
}
}
- auto des = (hint == HINT_INVALID) ? chooseEngine(target, lits, make_small)
- : getFdrDescription(hint);
+ auto des = (hint == HINT_INVALID) ? chooseEngine(target, lits, make_small)
+ : getFdrDescription(hint);
if (!des) {
return nullptr;
}
@@ -862,50 +862,50 @@ unique_ptr<HWLMProto> fdrBuildProtoInternal(u8 engType,
// temporary hack for unit testing
if (hint != HINT_INVALID) {
des->bits = 9;
- des->stride = 1;
+ des->stride = 1;
+ }
+
+ auto bucketToLits = assignStringsToBuckets(lits, *des);
+ addIncludedInfo(lits, des->getNumBuckets(), bucketToLits);
+ auto proto =
+ ue2::make_unique<HWLMProto>(engType, move(des), lits, bucketToLits,
+ make_small);
+ return proto;
+}
+
+unique_ptr<HWLMProto> fdrBuildProto(u8 engType, vector<hwlmLiteral> lits,
+ bool make_small, const target_t &target,
+ const Grey &grey) {
+ return fdrBuildProtoInternal(engType, lits, make_small, target, grey,
+ HINT_INVALID);
+}
+
+static
+bytecode_ptr<FDR> fdrBuildTableInternal(const HWLMProto &proto,
+ const Grey &grey) {
+
+ if (proto.teddyEng) {
+ return teddyBuildTable(proto, grey);
}
- auto bucketToLits = assignStringsToBuckets(lits, *des);
- addIncludedInfo(lits, des->getNumBuckets(), bucketToLits);
- auto proto =
- ue2::make_unique<HWLMProto>(engType, move(des), lits, bucketToLits,
- make_small);
- return proto;
+ FDRCompiler fc(proto.lits, proto.bucketToLits, *(proto.fdrEng),
+ proto.make_small, grey);
+ return fc.build();
}
-unique_ptr<HWLMProto> fdrBuildProto(u8 engType, vector<hwlmLiteral> lits,
- bool make_small, const target_t &target,
- const Grey &grey) {
- return fdrBuildProtoInternal(engType, lits, make_small, target, grey,
- HINT_INVALID);
+bytecode_ptr<FDR> fdrBuildTable(const HWLMProto &proto, const Grey &grey) {
+ return fdrBuildTableInternal(proto, grey);
}
-static
-bytecode_ptr<FDR> fdrBuildTableInternal(const HWLMProto &proto,
- const Grey &grey) {
-
- if (proto.teddyEng) {
- return teddyBuildTable(proto, grey);
- }
-
- FDRCompiler fc(proto.lits, proto.bucketToLits, *(proto.fdrEng),
- proto.make_small, grey);
- return fc.build();
-}
-
-bytecode_ptr<FDR> fdrBuildTable(const HWLMProto &proto, const Grey &grey) {
- return fdrBuildTableInternal(proto, grey);
-}
-
#if !defined(RELEASE_BUILD)
-unique_ptr<HWLMProto> fdrBuildProtoHinted(u8 engType,
- vector<hwlmLiteral> lits,
- bool make_small, u32 hint,
- const target_t &target,
- const Grey &grey) {
- return fdrBuildProtoInternal(engType, lits, make_small, target, grey,
- hint);
+unique_ptr<HWLMProto> fdrBuildProtoHinted(u8 engType,
+ vector<hwlmLiteral> lits,
+ bool make_small, u32 hint,
+ const target_t &target,
+ const Grey &grey) {
+ return fdrBuildProtoInternal(engType, lits, make_small, target, grey,
+ hint);
}
#endif
@@ -914,5 +914,5 @@ size_t fdrSize(const FDR *fdr) {
assert(fdr);
return fdr->size;
}
-
-} // namespace ue2
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_compile.h b/contrib/libs/hyperscan/src/fdr/fdr_compile.h
index dd86530ba39..f0ce49256a9 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_compile.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_compile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,8 +34,8 @@
#define FDR_COMPILE_H
#include "ue2common.h"
-#include "hwlm/hwlm_build.h"
-#include "util/bytecode_ptr.h"
+#include "hwlm/hwlm_build.h"
+#include "util/bytecode_ptr.h"
#include <vector>
@@ -47,25 +47,25 @@ struct hwlmLiteral;
struct Grey;
struct target_t;
-bytecode_ptr<FDR> fdrBuildTable(const HWLMProto &proto, const Grey &grey);
+bytecode_ptr<FDR> fdrBuildTable(const HWLMProto &proto, const Grey &grey);
#if !defined(RELEASE_BUILD)
-std::unique_ptr<HWLMProto> fdrBuildProtoHinted(
- u8 engType,
- std::vector<hwlmLiteral> lits,
- bool make_small, u32 hint,
- const target_t &target,
- const Grey &grey);
-#endif
+std::unique_ptr<HWLMProto> fdrBuildProtoHinted(
+ u8 engType,
+ std::vector<hwlmLiteral> lits,
+ bool make_small, u32 hint,
+ const target_t &target,
+ const Grey &grey);
+#endif
-std::unique_ptr<HWLMProto> fdrBuildProto(
- u8 engType,
- std::vector<hwlmLiteral> lits,
- bool make_small, const target_t &target,
- const Grey &grey);
+std::unique_ptr<HWLMProto> fdrBuildProto(
+ u8 engType,
+ std::vector<hwlmLiteral> lits,
+ bool make_small, const target_t &target,
+ const Grey &grey);
-/** \brief Returns size in bytes of the given FDR engine. */
-size_t fdrSize(const struct FDR *fdr);
+/** \brief Returns size in bytes of the given FDR engine. */
+size_t fdrSize(const struct FDR *fdr);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_compile_internal.h b/contrib/libs/hyperscan/src/fdr/fdr_compile_internal.h
index 701c7742b02..3879960a297 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_compile_internal.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_compile_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,7 @@
#include "ue2common.h"
#include "hwlm/hwlm_literal.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include <map>
#include <utility>
@@ -55,25 +55,25 @@ typedef u32 PositionInBucket; // zero is 'we are matching right now!",
class EngineDescription;
class FDREngineDescription;
struct hwlmStreamingControl;
-struct Grey;
+struct Grey;
-bytecode_ptr<u8> setupFullConfs(
- const std::vector<hwlmLiteral> &lits,
- const EngineDescription &eng,
- const std::map<BucketIndex, std::vector<LiteralIndex>> &bucketToLits,
- bool make_small);
+bytecode_ptr<u8> setupFullConfs(
+ const std::vector<hwlmLiteral> &lits,
+ const EngineDescription &eng,
+ const std::map<BucketIndex, std::vector<LiteralIndex>> &bucketToLits,
+ bool make_small);
// all suffixes include an implicit max_bucket_width suffix to ensure that
// we always read a full-scale flood "behind" us in terms of what's in our
// state; if we don't have a flood that's long enough we won't be in the
// right state yet to allow blindly advancing
-bytecode_ptr<u8> setupFDRFloodControl(const std::vector<hwlmLiteral> &lits,
- const EngineDescription &eng,
- const Grey &grey);
+bytecode_ptr<u8> setupFDRFloodControl(const std::vector<hwlmLiteral> &lits,
+ const EngineDescription &eng,
+ const Grey &grey);
-bytecode_ptr<u8>
+bytecode_ptr<u8>
fdrBuildTableStreaming(const std::vector<hwlmLiteral> &lits,
- hwlmStreamingControl &stream_control);
+ hwlmStreamingControl &stream_control);
static constexpr u32 HINT_INVALID = 0xffffffff;
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_confirm.h b/contrib/libs/hyperscan/src/fdr/fdr_confirm.h
index 45c5d4d4fc2..a23082cc6db 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_confirm.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_confirm.h
@@ -42,30 +42,30 @@ u32 mul_hash_64(u64a lv, u64a andmsk, u64a mult, u32 nBits) {
#define CONF_TYPE u64a
#define CONF_HASH_CALL mul_hash_64
-/**
- * \brief Flag indicating this literal doesn't need to be delivered more than
- * once, used in LitInfo::flags.
- */
-#define FDR_LIT_FLAG_NOREPEAT 1
+/**
+ * \brief Flag indicating this literal doesn't need to be delivered more than
+ * once, used in LitInfo::flags.
+ */
+#define FDR_LIT_FLAG_NOREPEAT 1
/**
* \brief Structure describing a literal, linked to by FDRConfirm.
*
- * This structure is followed in memory by a variable-sized string prefix, for
- * strings that are longer than CONF_TYPE.
+ * This structure is followed in memory by a variable-sized string prefix, for
+ * strings that are longer than CONF_TYPE.
*/
struct LitInfo {
CONF_TYPE v;
CONF_TYPE msk;
hwlm_group_t groups;
u32 id; // literal ID as passed in
- u8 size;
- u8 flags; //!< bitfield of flags from FDR_LIT_FLAG_* above.
+ u8 size;
+ u8 flags; //!< bitfield of flags from FDR_LIT_FLAG_* above.
u8 next;
};
#define FDRC_FLAG_NO_CONFIRM 1
-#define FDRC_FLAG_NOREPEAT 2
+#define FDRC_FLAG_NOREPEAT 2
/**
* \brief FDR confirm header.
@@ -78,7 +78,7 @@ struct LitInfo {
struct FDRConfirm {
CONF_TYPE andmsk;
CONF_TYPE mult;
- u32 nBits;
+ u32 nBits;
hwlm_group_t groups;
};
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_confirm_compile.cpp b/contrib/libs/hyperscan/src/fdr/fdr_confirm_compile.cpp
index aed2224cc20..8e3690895ed 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_confirm_compile.cpp
+++ b/contrib/libs/hyperscan/src/fdr/fdr_confirm_compile.cpp
@@ -35,7 +35,7 @@
#include "util/alloc.h"
#include "util/bitutils.h"
#include "util/compare.h"
-#include "util/container.h"
+#include "util/container.h"
#include "util/verify_types.h"
#include <algorithm>
@@ -46,7 +46,7 @@ using namespace std;
namespace ue2 {
-using BC2CONF = map<BucketIndex, bytecode_ptr<FDRConfirm>>;
+using BC2CONF = map<BucketIndex, bytecode_ptr<FDRConfirm>>;
static
u64a make_u64a_mask(const vector<u8> &v) {
@@ -80,12 +80,12 @@ void fillLitInfo(const vector<hwlmLiteral> &lits, vector<LitInfo> &tmpLitInfo,
LitInfo &info = tmpLitInfo[i];
memset(&info, 0, sizeof(info));
info.id = lit.id;
- u8 flags = 0;
+ u8 flags = 0;
if (lit.noruns) {
- flags |= FDR_LIT_FLAG_NOREPEAT;
+ flags |= FDR_LIT_FLAG_NOREPEAT;
}
info.flags = flags;
- info.size = verify_u8(max(lit.msk.size(), lit.s.size()));
+ info.size = verify_u8(max(lit.msk.size(), lit.s.size()));
info.groups = lit.groups;
// these are built up assuming a LE machine
@@ -129,13 +129,13 @@ void fillLitInfo(const vector<hwlmLiteral> &lits, vector<LitInfo> &tmpLitInfo,
//#define FDR_CONFIRM_DUMP 1
static
-bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
- bool make_small) {
- // Every literal must fit within CONF_TYPE.
- assert(all_of_in(lits, [](const hwlmLiteral &lit) {
- return lit.s.size() <= sizeof(CONF_TYPE);
- }));
-
+bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
+ bool make_small) {
+ // Every literal must fit within CONF_TYPE.
+ assert(all_of_in(lits, [](const hwlmLiteral &lit) {
+ return lit.s.size() <= sizeof(CONF_TYPE);
+ }));
+
vector<LitInfo> tmpLitInfo(lits.size());
CONF_TYPE andmsk;
fillLitInfo(lits, tmpLitInfo, andmsk);
@@ -149,7 +149,7 @@ bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
if (make_small) {
nBits = min(10U, lg2(lits.size()) + 1);
} else {
- nBits = lg2(lits.size()) + 4;
+ nBits = lg2(lits.size()) + 4;
}
CONF_TYPE mult = (CONF_TYPE)0x0b4e0ef37bc32127ULL;
@@ -169,61 +169,61 @@ bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
#ifdef FDR_CONFIRM_DUMP
// print out the literals reversed - makes it easier to line up analyses
// that are end-offset based
- for (const auto &m : res2lits) {
- const u32 &hash = m.first;
- const vector<LiteralIndex> &vlidx = m.second;
- if (vlidx.size() <= 1) {
- continue;
- }
- printf("%x -> %zu literals\n", hash, vlidx.size());
- size_t min_len = lits[vlidx.front()].s.size();
-
- vector<set<u8>> vsl; // contains the set of chars at each location
- // reversed from the end
-
- for (const auto &litIdx : vlidx) {
- const auto &lit = lits[litIdx];
- if (lit.s.size() > vsl.size()) {
- vsl.resize(lit.s.size());
+ for (const auto &m : res2lits) {
+ const u32 &hash = m.first;
+ const vector<LiteralIndex> &vlidx = m.second;
+ if (vlidx.size() <= 1) {
+ continue;
+ }
+ printf("%x -> %zu literals\n", hash, vlidx.size());
+ size_t min_len = lits[vlidx.front()].s.size();
+
+ vector<set<u8>> vsl; // contains the set of chars at each location
+ // reversed from the end
+
+ for (const auto &litIdx : vlidx) {
+ const auto &lit = lits[litIdx];
+ if (lit.s.size() > vsl.size()) {
+ vsl.resize(lit.s.size());
}
- for (size_t j = lit.s.size(); j != 0; j--) {
- vsl[lit.s.size() - j].insert(lit.s[j - 1]);
- }
- min_len = min(min_len, lit.s.size());
- }
- printf("common ");
- for (size_t j = 0; j < min_len; j++) {
- if (vsl[j].size() == 1) {
- printf("%02x", *vsl[j].begin());
- } else {
- printf("__");
- }
- }
- printf("\n");
- for (const auto &litIdx : vlidx) {
- const auto &lit = lits[litIdx];
- printf("%8x %c", lit.id, lit.nocase ? '!' : ' ');
- for (size_t j = lit.s.size(); j != 0; j--) {
- size_t dist_from_end = lit.s.size() - j;
- if (dist_from_end < min_len && vsl[dist_from_end].size() == 1) {
- printf("__");
+ for (size_t j = lit.s.size(); j != 0; j--) {
+ vsl[lit.s.size() - j].insert(lit.s[j - 1]);
+ }
+ min_len = min(min_len, lit.s.size());
+ }
+ printf("common ");
+ for (size_t j = 0; j < min_len; j++) {
+ if (vsl[j].size() == 1) {
+ printf("%02x", *vsl[j].begin());
+ } else {
+ printf("__");
+ }
+ }
+ printf("\n");
+ for (const auto &litIdx : vlidx) {
+ const auto &lit = lits[litIdx];
+ printf("%8x %c", lit.id, lit.nocase ? '!' : ' ');
+ for (size_t j = lit.s.size(); j != 0; j--) {
+ size_t dist_from_end = lit.s.size() - j;
+ if (dist_from_end < min_len && vsl[dist_from_end].size() == 1) {
+ printf("__");
} else {
- printf("%02x", lit.s[j - 1]);
+ printf("%02x", lit.s[j - 1]);
}
}
printf("\n");
}
- size_t total_compares = 0;
- for (const auto &v : vsl) {
- total_compares += v.size();
- }
- size_t total_string_size = 0;
- for (const auto &litIdx : vlidx) {
- const auto &lit = lits[litIdx];
- total_string_size += lit.s.size();
- }
- printf("Total compare load: %zu Total string size: %zu\n\n",
- total_compares, total_string_size);
+ size_t total_compares = 0;
+ for (const auto &v : vsl) {
+ total_compares += v.size();
+ }
+ size_t total_string_size = 0;
+ for (const auto &litIdx : vlidx) {
+ const auto &lit = lits[litIdx];
+ total_string_size += lit.s.size();
+ }
+ printf("Total compare load: %zu Total string size: %zu\n\n",
+ total_compares, total_string_size);
}
#endif
@@ -232,20 +232,20 @@ bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
// this size can now be a worst-case as we can always be a bit smaller
size_t size = ROUNDUP_N(sizeof(FDRConfirm), alignof(u32)) +
ROUNDUP_N(bitsToLitIndexSize, alignof(LitInfo)) +
- sizeof(LitInfo) * lits.size();
+ sizeof(LitInfo) * lits.size();
size = ROUNDUP_N(size, alignof(FDRConfirm));
- auto fdrc = make_zeroed_bytecode_ptr<FDRConfirm>(size);
+ auto fdrc = make_zeroed_bytecode_ptr<FDRConfirm>(size);
assert(fdrc); // otherwise would have thrown std::bad_alloc
fdrc->andmsk = andmsk;
fdrc->mult = mult;
- fdrc->nBits = nBits;
+ fdrc->nBits = nBits;
fdrc->groups = gm;
// After the FDRConfirm, we have the lit index array.
- u8 *fdrc_base = (u8 *)fdrc.get();
+ u8 *fdrc_base = (u8 *)fdrc.get();
u8 *ptr = fdrc_base + sizeof(*fdrc);
ptr = ROUNDUP_PTR(ptr, alignof(u32));
u32 *bitsToLitIndex = (u32 *)ptr;
@@ -257,23 +257,23 @@ bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
// Walk the map by hash value assigning indexes and laying out the
// elements (and their associated string confirm material) in memory.
- for (const auto &m : res2lits) {
- const u32 hash = m.first;
- const vector<LiteralIndex> &vlidx = m.second;
- bitsToLitIndex[hash] = verify_u32(ptr - fdrc_base);
- for (auto i = vlidx.begin(), e = vlidx.end(); i != e; ++i) {
- LiteralIndex litIdx = *i;
+ for (const auto &m : res2lits) {
+ const u32 hash = m.first;
+ const vector<LiteralIndex> &vlidx = m.second;
+ bitsToLitIndex[hash] = verify_u32(ptr - fdrc_base);
+ for (auto i = vlidx.begin(), e = vlidx.end(); i != e; ++i) {
+ LiteralIndex litIdx = *i;
// Write LitInfo header.
LitInfo &finalLI = *(LitInfo *)ptr;
finalLI = tmpLitInfo[litIdx];
ptr += sizeof(LitInfo); // String starts directly after LitInfo.
- assert(lits[litIdx].s.size() <= sizeof(CONF_TYPE));
- if (next(i) == e) {
- finalLI.next = 0;
+ assert(lits[litIdx].s.size() <= sizeof(CONF_TYPE));
+ if (next(i) == e) {
+ finalLI.next = 0;
} else {
- finalLI.next = 1;
+ finalLI.next = 1;
}
}
assert((size_t)(ptr - fdrc_base) <= size);
@@ -284,57 +284,57 @@ bytecode_ptr<FDRConfirm> getFDRConfirm(const vector<hwlmLiteral> &lits,
size_t actual_size = ROUNDUP_N((size_t)(ptr - fdrc_base),
alignof(FDRConfirm));
assert(actual_size <= size);
- fdrc.shrink(actual_size);
-
- return fdrc;
+ fdrc.shrink(actual_size);
+
+ return fdrc;
}
-bytecode_ptr<u8>
-setupFullConfs(const vector<hwlmLiteral> &lits,
- const EngineDescription &eng,
- const map<BucketIndex, vector<LiteralIndex>> &bucketToLits,
- bool make_small) {
+bytecode_ptr<u8>
+setupFullConfs(const vector<hwlmLiteral> &lits,
+ const EngineDescription &eng,
+ const map<BucketIndex, vector<LiteralIndex>> &bucketToLits,
+ bool make_small) {
unique_ptr<TeddyEngineDescription> teddyDescr =
getTeddyDescription(eng.getID());
- BC2CONF bc2Conf;
+ BC2CONF bc2Conf;
u32 totalConfirmSize = 0;
for (BucketIndex b = 0; b < eng.getNumBuckets(); b++) {
- if (contains(bucketToLits, b)) {
- vector<hwlmLiteral> vl;
- for (const LiteralIndex &lit_idx : bucketToLits.at(b)) {
- vl.push_back(lits[lit_idx]);
+ if (contains(bucketToLits, b)) {
+ vector<hwlmLiteral> vl;
+ for (const LiteralIndex &lit_idx : bucketToLits.at(b)) {
+ vl.push_back(lits[lit_idx]);
}
- DEBUG_PRINTF("b %d sz %zu\n", b, vl.size());
- auto fc = getFDRConfirm(vl, make_small);
- totalConfirmSize += fc.size();
- bc2Conf.emplace(b, move(fc));
+ DEBUG_PRINTF("b %d sz %zu\n", b, vl.size());
+ auto fc = getFDRConfirm(vl, make_small);
+ totalConfirmSize += fc.size();
+ bc2Conf.emplace(b, move(fc));
}
}
u32 nBuckets = eng.getNumBuckets();
- u32 totalConfSwitchSize = ROUNDUP_CL(nBuckets * sizeof(u32));
- u32 totalSize = totalConfSwitchSize + totalConfirmSize;
+ u32 totalConfSwitchSize = ROUNDUP_CL(nBuckets * sizeof(u32));
+ u32 totalSize = totalConfSwitchSize + totalConfirmSize;
- auto buf = make_zeroed_bytecode_ptr<u8>(totalSize, 64);
+ auto buf = make_zeroed_bytecode_ptr<u8>(totalSize, 64);
assert(buf); // otherwise would have thrown std::bad_alloc
- u32 *confBase = (u32 *)buf.get();
- u8 *ptr = buf.get() + totalConfSwitchSize;
- assert(ISALIGNED_CL(ptr));
+ u32 *confBase = (u32 *)buf.get();
+ u8 *ptr = buf.get() + totalConfSwitchSize;
+ assert(ISALIGNED_CL(ptr));
- for (const auto &m : bc2Conf) {
- const BucketIndex &idx = m.first;
- const bytecode_ptr<FDRConfirm> &p = m.second;
+ for (const auto &m : bc2Conf) {
+ const BucketIndex &idx = m.first;
+ const bytecode_ptr<FDRConfirm> &p = m.second;
// confirm offset is relative to the base of this structure, now
- u32 confirm_offset = verify_u32(ptr - buf.get());
- memcpy(ptr, p.get(), p.size());
- ptr += p.size();
+ u32 confirm_offset = verify_u32(ptr - buf.get());
+ memcpy(ptr, p.get(), p.size());
+ ptr += p.size();
confBase[idx] = confirm_offset;
}
-
- return buf;
+
+ return buf;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_confirm_runtime.h b/contrib/libs/hyperscan/src/fdr/fdr_confirm_runtime.h
index 79b8a1bf56b..5a2164952c9 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_confirm_runtime.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_confirm_runtime.h
@@ -29,7 +29,7 @@
#ifndef FDR_CONFIRM_RUNTIME_H
#define FDR_CONFIRM_RUNTIME_H
-#include "scratch.h"
+#include "scratch.h"
#include "fdr_internal.h"
#include "fdr_loadval.h"
#include "hwlm/hwlm.h"
@@ -40,65 +40,65 @@
// this is ordinary confirmation function which runs through
// the whole confirmation procedure
static really_inline
-void confWithBit(const struct FDRConfirm *fdrc, const struct FDR_Runtime_Args *a,
- size_t i, hwlmcb_rv_t *control, u32 *last_match,
- u64a conf_key, u64a *conf, u8 bit) {
+void confWithBit(const struct FDRConfirm *fdrc, const struct FDR_Runtime_Args *a,
+ size_t i, hwlmcb_rv_t *control, u32 *last_match,
+ u64a conf_key, u64a *conf, u8 bit) {
assert(i < a->len);
- assert(i >= a->start_offset);
+ assert(i >= a->start_offset);
assert(ISALIGNED(fdrc));
const u8 * buf = a->buf;
- u32 c = CONF_HASH_CALL(conf_key, fdrc->andmsk, fdrc->mult,
- fdrc->nBits);
- u32 start = getConfirmLitIndex(fdrc)[c];
- if (likely(!start)) {
- return;
+ u32 c = CONF_HASH_CALL(conf_key, fdrc->andmsk, fdrc->mult,
+ fdrc->nBits);
+ u32 start = getConfirmLitIndex(fdrc)[c];
+ if (likely(!start)) {
+ return;
}
- const struct LitInfo *li
- = (const struct LitInfo *)((const u8 *)fdrc + start);
+ const struct LitInfo *li
+ = (const struct LitInfo *)((const u8 *)fdrc + start);
- struct hs_scratch *scratch = a->scratch;
- assert(!scratch->fdr_conf);
- scratch->fdr_conf = conf;
- scratch->fdr_conf_offset = bit;
- u8 oldNext; // initialized in loop
- do {
- assert(ISALIGNED(li));
+ struct hs_scratch *scratch = a->scratch;
+ assert(!scratch->fdr_conf);
+ scratch->fdr_conf = conf;
+ scratch->fdr_conf_offset = bit;
+ u8 oldNext; // initialized in loop
+ do {
+ assert(ISALIGNED(li));
- if (unlikely((conf_key & li->msk) != li->v)) {
- goto out;
- }
+ if (unlikely((conf_key & li->msk) != li->v)) {
+ goto out;
+ }
- if ((*last_match == li->id) && (li->flags & FDR_LIT_FLAG_NOREPEAT)) {
- goto out;
- }
+ if ((*last_match == li->id) && (li->flags & FDR_LIT_FLAG_NOREPEAT)) {
+ goto out;
+ }
- const u8 *loc = buf + i - li->size + 1;
+ const u8 *loc = buf + i - li->size + 1;
- if (loc < buf) {
- u32 full_overhang = buf - loc;
- size_t len_history = a->len_history;
+ if (loc < buf) {
+ u32 full_overhang = buf - loc;
+ size_t len_history = a->len_history;
- // can't do a vectored confirm either if we don't have
- // the bytes
- if (full_overhang > len_history) {
+ // can't do a vectored confirm either if we don't have
+ // the bytes
+ if (full_overhang > len_history) {
goto out;
}
}
- assert(li->size <= sizeof(CONF_TYPE));
+ assert(li->size <= sizeof(CONF_TYPE));
- if (unlikely(!(li->groups & *control))) {
- goto out;
+ if (unlikely(!(li->groups & *control))) {
+ goto out;
}
- *last_match = li->id;
- *control = a->cb(i, li->id, scratch);
- out:
- oldNext = li->next; // oldNext is either 0 or an 'adjust' value
- li++;
- } while (oldNext);
- scratch->fdr_conf = NULL;
+ *last_match = li->id;
+ *control = a->cb(i, li->id, scratch);
+ out:
+ oldNext = li->next; // oldNext is either 0 or an 'adjust' value
+ li++;
+ } while (oldNext);
+ scratch->fdr_conf = NULL;
}
#endif
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_engine_description.cpp b/contrib/libs/hyperscan/src/fdr/fdr_engine_description.cpp
index fa92b664323..2f9ba420c03 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_engine_description.cpp
+++ b/contrib/libs/hyperscan/src/fdr/fdr_engine_description.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -44,8 +44,8 @@ namespace ue2 {
FDREngineDescription::FDREngineDescription(const FDREngineDef &def)
: EngineDescription(def.id, targetByArchFeatures(def.cpu_features),
- def.numBuckets),
- schemeWidth(def.schemeWidth), stride(0), bits(0) {}
+ def.numBuckets),
+ schemeWidth(def.schemeWidth), stride(0), bits(0) {}
u32 FDREngineDescription::getDefaultFloodSuffixLength() const {
// rounding up, so that scheme width 32 and 6 buckets is 6 not 5!
@@ -53,12 +53,12 @@ u32 FDREngineDescription::getDefaultFloodSuffixLength() const {
return ((getSchemeWidth() + getNumBuckets() - 1) / getNumBuckets()) + 1;
}
-void getFdrDescriptions(vector<FDREngineDescription> *out) {
- static const FDREngineDef def = {0, 64, 8, 0};
- out->clear();
- out->emplace_back(def);
-}
-
+void getFdrDescriptions(vector<FDREngineDescription> *out) {
+ static const FDREngineDef def = {0, 64, 8, 0};
+ out->clear();
+ out->emplace_back(def);
+}
+
static
u32 findDesiredStride(size_t num_lits, size_t min_len, size_t min_len_count) {
u32 desiredStride = 1; // always our safe fallback
@@ -111,33 +111,33 @@ unique_ptr<FDREngineDescription> chooseEngine(const target_t &target,
FDREngineDescription *best = nullptr;
u32 best_score = 0;
- FDREngineDescription &eng = allDescs[0];
-
+ FDREngineDescription &eng = allDescs[0];
+
for (u32 domain = 9; domain <= 15; domain++) {
- for (size_t stride = 1; stride <= 4; stride *= 2) {
+ for (size_t stride = 1; stride <= 4; stride *= 2) {
// to make sure that domains >=14 have stride 1 according to origin
- if (domain > 13 && stride > 1) {
+ if (domain > 13 && stride > 1) {
continue;
}
if (!eng.isValidOnTarget(target)) {
continue;
}
- if (msl < stride) {
+ if (msl < stride) {
continue;
}
u32 score = 100;
- score -= absdiff(desiredStride, stride);
+ score -= absdiff(desiredStride, stride);
- if (stride <= desiredStride) {
- score += stride;
+ if (stride <= desiredStride) {
+ score += stride;
}
u32 effLits = vl.size(); /* * desiredStride;*/
u32 ideal;
if (effLits < eng.getNumBuckets()) {
- if (stride == 1) {
+ if (stride == 1) {
ideal = 8;
} else {
ideal = 10;
@@ -162,28 +162,28 @@ unique_ptr<FDREngineDescription> chooseEngine(const target_t &target,
ideal -= 2;
}
- if (stride > 1) {
+ if (stride > 1) {
ideal++;
}
DEBUG_PRINTF("effLits %u\n", effLits);
if (target.is_atom_class() && !make_small && effLits < 4000) {
- /* Unless it is a very heavy case, we want to build smaller
- * tables on lightweight machines due to their small caches. */
+ /* Unless it is a very heavy case, we want to build smaller
+ * tables on lightweight machines due to their small caches. */
ideal -= 2;
}
score -= absdiff(ideal, domain);
- DEBUG_PRINTF("fdr %u: width=%u, domain=%u, buckets=%u, stride=%zu "
+ DEBUG_PRINTF("fdr %u: width=%u, domain=%u, buckets=%u, stride=%zu "
"-> score=%u\n",
- eng.getID(), eng.schemeWidth, domain,
- eng.getNumBuckets(), stride, score);
+ eng.getID(), eng.schemeWidth, domain,
+ eng.getNumBuckets(), stride, score);
if (!best || score > best_score) {
eng.bits = domain;
- eng.stride = stride;
+ eng.stride = stride;
best = &eng;
best_score = score;
}
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_engine_description.h b/contrib/libs/hyperscan/src/fdr/fdr_engine_description.h
index b82ed006397..1c464fe3ad1 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_engine_description.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_engine_description.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_internal.h b/contrib/libs/hyperscan/src/fdr/fdr_internal.h
index d0395e0feff..c79f61c1f17 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_internal.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,8 +36,8 @@
#include "ue2common.h"
#include "hwlm/hwlm.h" // for hwlm_group_t, HWLMCallback
-struct hs_scratch;
-
+struct hs_scratch;
+
typedef enum {
NOT_CAUTIOUS, //!< not near a boundary (quantify?)
VECTORING //!< potentially vectoring
@@ -70,18 +70,18 @@ struct FDR {
u32 engineID;
u32 size;
u32 maxStringLen;
- u32 numStrings;
- u32 confOffset;
+ u32 numStrings;
+ u32 confOffset;
u32 floodOffset;
- u8 stride; /* stride - how frequently the data is consulted by the first
- * stage matcher */
- u8 domain; /* number of bits used to index into main FDR table. This value
- * is used only of debugging/asserts. */
+ u8 stride; /* stride - how frequently the data is consulted by the first
+ * stage matcher */
+ u8 domain; /* number of bits used to index into main FDR table. This value
+ * is used only of debugging/asserts. */
u16 domainMask; /* pre-computed domain mask */
u32 tabSize; /* pre-computed hashtable size in bytes */
- m128 start; /* initial start state to use at offset 0. The state has been
- * set up based on the min length of buckets to reduce the need
- * for pointless confirms. */
+ m128 start; /* initial start state to use at offset 0. The state has been
+ * set up based on the min length of buckets to reduce the need
+ * for pointless confirms. */
};
/** \brief FDR runtime arguments.
@@ -97,7 +97,7 @@ struct FDR_Runtime_Args {
size_t len_history;
size_t start_offset;
HWLMCallback cb;
- struct hs_scratch *scratch;
+ struct hs_scratch *scratch;
const u8 *firstFloodDetect;
const u64a histBytes;
};
diff --git a/contrib/libs/hyperscan/src/fdr/fdr_loadval.h b/contrib/libs/hyperscan/src/fdr/fdr_loadval.h
index 887df03aab6..86c39c7f30a 100644
--- a/contrib/libs/hyperscan/src/fdr/fdr_loadval.h
+++ b/contrib/libs/hyperscan/src/fdr/fdr_loadval.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,23 +32,23 @@
#include "ue2common.h"
#include "util/unaligned.h"
-#define MAKE_LOADVAL(type, name) \
- static really_inline \
- type name(const u8 *ptr, UNUSED const u8 *lo, UNUSED const u8 *hi)
+#define MAKE_LOADVAL(type, name) \
+ static really_inline \
+ type name(const u8 *ptr, UNUSED const u8 *lo, UNUSED const u8 *hi)
-#define NORMAL_SAFE(type) \
- do { \
- assert(ptr >= lo); \
- assert(ptr + sizeof(type) - 1 < hi); \
- } while(0)
+#define NORMAL_SAFE(type) \
+ do { \
+ assert(ptr >= lo); \
+ assert(ptr + sizeof(type) - 1 < hi); \
+ } while(0)
-#define MAKE_LOOP_CE(TYPE) \
- TYPE v = 0; \
- for (TYPE i = 0; i < sizeof(TYPE); i++) { \
- if ((lo <= ptr + i) && (ptr + i < hi)) { \
- v += (TYPE)ptr[i] << (i*8); \
- } \
- } \
+#define MAKE_LOOP_CE(TYPE) \
+ TYPE v = 0; \
+ for (TYPE i = 0; i < sizeof(TYPE); i++) { \
+ if ((lo <= ptr + i) && (ptr + i < hi)) { \
+ v += (TYPE)ptr[i] << (i*8); \
+ } \
+ } \
return v;
// no suffix = normal (unaligned)
@@ -64,8 +64,8 @@ MAKE_LOADVAL(u64a, lv_u64a) {
return unaligned_load_u64a(ptr);
}
-MAKE_LOADVAL(u16, lv_u16_ce) { MAKE_LOOP_CE(u16); }
+MAKE_LOADVAL(u16, lv_u16_ce) { MAKE_LOOP_CE(u16); }
-MAKE_LOADVAL(u64a, lv_u64a_ce) { MAKE_LOOP_CE(u64a); }
+MAKE_LOADVAL(u64a, lv_u64a_ce) { MAKE_LOOP_CE(u64a); }
#endif
diff --git a/contrib/libs/hyperscan/src/fdr/flood_compile.cpp b/contrib/libs/hyperscan/src/fdr/flood_compile.cpp
index 9f7b9a9c6ff..ff805ca399a 100644
--- a/contrib/libs/hyperscan/src/fdr/flood_compile.cpp
+++ b/contrib/libs/hyperscan/src/fdr/flood_compile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,7 +30,7 @@
#include "fdr_confirm.h"
#include "fdr_compile_internal.h"
#include "fdr_engine_description.h"
-#include "grey.h"
+#include "grey.h"
#include "ue2common.h"
#include "util/alloc.h"
#include "util/bitutils.h"
@@ -70,7 +70,7 @@ static
void updateFloodSuffix(vector<FDRFlood> &tmpFlood, u8 c, u32 suffix) {
FDRFlood &fl = tmpFlood[c];
fl.suffix = MAX(fl.suffix, suffix + 1);
- DEBUG_PRINTF("Updated Flood Suffix for char 0x%02x to %u\n", c, fl.suffix);
+ DEBUG_PRINTF("Updated Flood Suffix for char 0x%02x to %u\n", c, fl.suffix);
}
static
@@ -85,14 +85,14 @@ void addFlood(vector<FDRFlood> &tmpFlood, u8 c, const hwlmLiteral &lit,
// when idCount gets to max_ids this flood no longer happens
// only incremented one more time to avoid arithmetic overflow
DEBUG_PRINTF("Added Flood for char '%c' suffix=%u len[%hu]=%u\n",
- c, fl.suffix, fl.idCount, suffix);
+ c, fl.suffix, fl.idCount, suffix);
fl.idCount++;
}
}
-bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
- const EngineDescription &eng,
- const Grey &grey) {
+bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
+ const EngineDescription &eng,
+ const Grey &grey) {
vector<FDRFlood> tmpFlood(N_CHARS);
u32 default_suffix = eng.getDefaultFloodSuffixLength();
@@ -125,9 +125,9 @@ bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
for (u32 i = 0; i < iEnd; i++) {
if (i < litSize) {
if (isDifferent(c, lit.s[litSize - i - 1], lit.nocase)) {
- DEBUG_PRINTF("non-flood char in literal[%u]: "
- "0x%02x != 0x%02x\n",
- i, c, lit.s[litSize - i - 1]);
+ DEBUG_PRINTF("non-flood char in literal[%u]: "
+ "0x%02x != 0x%02x\n",
+ i, c, lit.s[litSize - i - 1]);
upSuffix = MIN(upSuffix, i);
loSuffix = MIN(loSuffix, i); // makes sense only for case-less
break;
@@ -181,19 +181,19 @@ bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
printf("i is %02x fl->idCount is %hd fl->suffix is %d fl->allGroups is "
"%016llx\n", i, fl.idCount, fl.suffix, fl.allGroups);
for (u32 j = 0; j < fl.idCount; j++) {
- printf("j is %d fl.groups[j] %016llx\n", j, fl.groups[j]);
+ printf("j is %d fl.groups[j] %016llx\n", j, fl.groups[j]);
}
}
#endif
- // If flood detection has been switched off in the grey box, we comply by
- // setting idCount too high for all floods.
- if (!grey.fdrAllowFlood) {
- for (auto &fl : tmpFlood) {
- fl.idCount = FDR_FLOOD_MAX_IDS;
- }
- }
-
+ // If flood detection has been switched off in the grey box, we comply by
+ // setting idCount too high for all floods.
+ if (!grey.fdrAllowFlood) {
+ for (auto &fl : tmpFlood) {
+ fl.idCount = FDR_FLOOD_MAX_IDS;
+ }
+ }
+
map<FDRFlood, CharReach, FloodComparator> flood2chars;
for (u32 i = 0; i < N_CHARS; i++) {
FDRFlood fl = tmpFlood[i];
@@ -204,12 +204,12 @@ bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
size_t floodHeaderSize = sizeof(u32) * N_CHARS;
size_t floodStructSize = sizeof(FDRFlood) * nDistinctFloods;
size_t totalSize = ROUNDUP_16(floodHeaderSize + floodStructSize);
-
- auto buf = make_zeroed_bytecode_ptr<u8>(totalSize, 16);
+
+ auto buf = make_zeroed_bytecode_ptr<u8>(totalSize, 16);
assert(buf); // otherwise would have thrown std::bad_alloc
- u32 *floodHeader = (u32 *)buf.get();
- FDRFlood *layoutFlood = (FDRFlood *)(buf.get() + floodHeaderSize);
+ u32 *floodHeader = (u32 *)buf.get();
+ FDRFlood *layoutFlood = (FDRFlood *)(buf.get() + floodHeaderSize);
u32 currentFloodIndex = 0;
for (const auto &m : flood2chars) {
@@ -225,7 +225,7 @@ bytecode_ptr<u8> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
DEBUG_PRINTF("made a flood structure with %zu + %zu = %zu\n",
floodHeaderSize, floodStructSize, totalSize);
- return buf;
+ return buf;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/fdr/flood_runtime.h b/contrib/libs/hyperscan/src/fdr/flood_runtime.h
index b82b9500933..2d5a32d92ad 100644
--- a/contrib/libs/hyperscan/src/fdr/flood_runtime.h
+++ b/contrib/libs/hyperscan/src/fdr/flood_runtime.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -94,13 +94,13 @@ const u8 * floodDetect(const struct FDR * fdr,
const u8 * buf = a->buf;
const size_t len = a->len;
HWLMCallback cb = a->cb;
- struct hs_scratch *scratch = a->scratch;
+ struct hs_scratch *scratch = a->scratch;
const u8 * ptr = *ptrPtr;
// tryFloodDetect is never put in places where unconditional
// reads a short distance forward or backward here
// TODO: rationale for this line needs to be rediscovered!!
- size_t mainLoopLen = len > 2 * iterBytes ? len - 2 * iterBytes : 0;
+ size_t mainLoopLen = len > 2 * iterBytes ? len - 2 * iterBytes : 0;
const u32 i = ptr - buf;
u32 j = i;
@@ -197,67 +197,67 @@ const u8 * floodDetect(const struct FDR * fdr,
t += 4) {
DEBUG_PRINTF("aaa %u %llx\n", t, fl->groups[0]);
if (*control & fl->groups[0]) {
- *control = cb(i + t + 0, fl->ids[0], scratch);
+ *control = cb(i + t + 0, fl->ids[0], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 1, fl->ids[0], scratch);
+ *control = cb(i + t + 1, fl->ids[0], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 2, fl->ids[0], scratch);
+ *control = cb(i + t + 2, fl->ids[0], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 3, fl->ids[0], scratch);
+ *control = cb(i + t + 3, fl->ids[0], scratch);
}
}
break;
case 2:
for (u32 t = 0; t < floodSize && (*control & fl->allGroups); t += 4) {
if (*control & fl->groups[0]) {
- *control = cb(i + t, fl->ids[0], scratch);
+ *control = cb(i + t, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t, fl->ids[1], scratch);
+ *control = cb(i + t, fl->ids[1], scratch);
}
if (*control & fl->groups[0]) {
*control =
- cb(i + t + 1, fl->ids[0], scratch);
+ cb(i + t + 1, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t + 1, fl->ids[1], scratch);
+ *control = cb(i + t + 1, fl->ids[1], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 2, fl->ids[0], scratch);
+ *control = cb(i + t + 2, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t + 2, fl->ids[1], scratch);
+ *control = cb(i + t + 2, fl->ids[1], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 3, fl->ids[0], scratch);
+ *control = cb(i + t + 3, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t + 3, fl->ids[1], scratch);
+ *control = cb(i + t + 3, fl->ids[1], scratch);
}
}
break;
case 3:
for (u32 t = 0; t < floodSize && (*control & fl->allGroups); t += 2) {
if (*control & fl->groups[0]) {
- *control = cb(i + t, fl->ids[0], scratch);
+ *control = cb(i + t, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t, fl->ids[1], scratch);
+ *control = cb(i + t, fl->ids[1], scratch);
}
if (*control & fl->groups[2]) {
- *control = cb(i + t, fl->ids[2], scratch);
+ *control = cb(i + t, fl->ids[2], scratch);
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 1, fl->ids[0], scratch);
+ *control = cb(i + t + 1, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t + 1, fl->ids[1], scratch);
+ *control = cb(i + t + 1, fl->ids[1], scratch);
}
if (*control & fl->groups[2]) {
- *control = cb(i + t + 1, fl->ids[2], scratch);
+ *control = cb(i + t + 1, fl->ids[2], scratch);
}
}
break;
@@ -266,40 +266,40 @@ const u8 * floodDetect(const struct FDR * fdr,
for (u32 t = 0; t < floodSize && (*control & fl->allGroups); t += 2) {
if (*control & fl->groups[0]) {
- *control = cb(i + t, fl->ids[0], scratch);
+ *control = cb(i + t, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t, fl->ids[1], scratch);
+ *control = cb(i + t, fl->ids[1], scratch);
}
if (*control & fl->groups[2]) {
- *control = cb(i + t, fl->ids[2], scratch);
+ *control = cb(i + t, fl->ids[2], scratch);
}
if (*control & fl->groups[3]) {
- *control = cb(i + t, fl->ids[3], scratch);
+ *control = cb(i + t, fl->ids[3], scratch);
}
for (u32 t2 = 4; t2 < fl->idCount; t2++) {
if (*control & fl->groups[t2]) {
- *control = cb(i + t, fl->ids[t2], scratch);
+ *control = cb(i + t, fl->ids[t2], scratch);
}
}
if (*control & fl->groups[0]) {
- *control = cb(i + t + 1, fl->ids[0], scratch);
+ *control = cb(i + t + 1, fl->ids[0], scratch);
}
if (*control & fl->groups[1]) {
- *control = cb(i + t + 1, fl->ids[1], scratch);
+ *control = cb(i + t + 1, fl->ids[1], scratch);
}
if (*control & fl->groups[2]) {
- *control = cb(i + t + 1, fl->ids[2], scratch);
+ *control = cb(i + t + 1, fl->ids[2], scratch);
}
if (*control & fl->groups[3]) {
- *control = cb(i + t + 1, fl->ids[3], scratch);
+ *control = cb(i + t + 1, fl->ids[3], scratch);
}
for (u32 t2 = 4; t2 < fl->idCount; t2++) {
if (*control & fl->groups[t2]) {
- *control = cb(i + t + 1, fl->ids[t2], scratch);
+ *control = cb(i + t + 1, fl->ids[t2], scratch);
}
}
}
@@ -310,7 +310,7 @@ const u8 * floodDetect(const struct FDR * fdr,
for (u32 t = 0; t < floodSize && (*control & fl->allGroups); t++) {
for (u32 t2 = 0; t2 < fl->idCount; t2++) {
if (*control & fl->groups[t2]) {
- *control = cb(i + t, fl->ids[t2], scratch);
+ *control = cb(i + t, fl->ids[t2], scratch);
}
}
}
diff --git a/contrib/libs/hyperscan/src/fdr/teddy.c b/contrib/libs/hyperscan/src/fdr/teddy.c
index c62d9fa77e7..e6f5476198f 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy.c
+++ b/contrib/libs/hyperscan/src/fdr/teddy.c
@@ -26,52 +26,52 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/** \file
- * \brief Teddy literal matcher: SSSE3 engine runtime.
- */
-
-#include "fdr_internal.h"
-#include "flood_runtime.h"
-#include "teddy.h"
-#include "teddy_internal.h"
-#include "teddy_runtime_common.h"
+/** \file
+ * \brief Teddy literal matcher: SSSE3 engine runtime.
+ */
+
+#include "fdr_internal.h"
+#include "flood_runtime.h"
+#include "teddy.h"
+#include "teddy_internal.h"
+#include "teddy_runtime_common.h"
#include "util/simd_utils.h"
-const u8 ALIGN_DIRECTIVE p_mask_arr[17][32] = {
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+const u8 ALIGN_DIRECTIVE p_mask_arr[17][32] = {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
#if defined(HAVE_AVX512VBMI) // VBMI strong teddy
@@ -98,31 +98,31 @@ do { \
#else
-#define CONF_CHUNK_64(chunk, bucket, off, reason, conf_fn) \
-do { \
- if (unlikely(chunk != ones_u64a)) { \
- chunk = ~chunk; \
- conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
- &control, &last_match); \
- CHECK_HWLM_TERMINATE_MATCHING; \
- } \
-} while(0)
-
-#define CONF_CHUNK_32(chunk, bucket, off, reason, conf_fn) \
-do { \
- if (unlikely(chunk != ones_u32)) { \
- chunk = ~chunk; \
- conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
- &control, &last_match); \
- CHECK_HWLM_TERMINATE_MATCHING; \
- } \
-} while(0)
+#define CONF_CHUNK_64(chunk, bucket, off, reason, conf_fn) \
+do { \
+ if (unlikely(chunk != ones_u64a)) { \
+ chunk = ~chunk; \
+ conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
+ &control, &last_match); \
+ CHECK_HWLM_TERMINATE_MATCHING; \
+ } \
+} while(0)
+
+#define CONF_CHUNK_32(chunk, bucket, off, reason, conf_fn) \
+do { \
+ if (unlikely(chunk != ones_u32)) { \
+ chunk = ~chunk; \
+ conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
+ &control, &last_match); \
+ CHECK_HWLM_TERMINATE_MATCHING; \
+ } \
+} while(0)
#endif
-
+
#if defined(HAVE_AVX512VBMI) // VBMI strong teddy
-#ifdef ARCH_64_BIT
+#ifdef ARCH_64_BIT
#define CONFIRM_TEDDY(var, bucket, offset, reason, pt, conf_fn) \
do { \
if (unlikely(diff512(var, ones512()))) { \
@@ -390,725 +390,725 @@ do { \
#elif defined(HAVE_AVX512) // AVX512 reinforced teddy
#ifdef ARCH_64_BIT
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff512(var, ones512()))) { \
- m128 p128_0 = extract128from512(var, 0); \
- m128 p128_1 = extract128from512(var, 1); \
- m128 p128_2 = extract128from512(var, 2); \
- m128 p128_3 = extract128from512(var, 3); \
- u64a part1 = movq(p128_0); \
- u64a part2 = movq(rshiftbyte_m128(p128_0, 8)); \
- u64a part3 = movq(p128_1); \
- u64a part4 = movq(rshiftbyte_m128(p128_1, 8)); \
- u64a part5 = movq(p128_2); \
- u64a part6 = movq(rshiftbyte_m128(p128_2, 8)); \
- u64a part7 = movq(p128_3); \
- u64a part8 = movq(rshiftbyte_m128(p128_3, 8)); \
- CONF_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_64(part2, bucket, offset + 8, reason, conf_fn); \
- CONF_CHUNK_64(part3, bucket, offset + 16, reason, conf_fn); \
- CONF_CHUNK_64(part4, bucket, offset + 24, reason, conf_fn); \
- CONF_CHUNK_64(part5, bucket, offset + 32, reason, conf_fn); \
- CONF_CHUNK_64(part6, bucket, offset + 40, reason, conf_fn); \
- CONF_CHUNK_64(part7, bucket, offset + 48, reason, conf_fn); \
- CONF_CHUNK_64(part8, bucket, offset + 56, reason, conf_fn); \
- } \
-} while(0)
-#else
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff512(var, ones512()))) { \
- m128 p128_0 = extract128from512(var, 0); \
- m128 p128_1 = extract128from512(var, 1); \
- m128 p128_2 = extract128from512(var, 2); \
- m128 p128_3 = extract128from512(var, 3); \
- u32 part1 = movd(p128_0); \
- u32 part2 = movd(rshiftbyte_m128(p128_0, 4)); \
- u32 part3 = movd(rshiftbyte_m128(p128_0, 8)); \
- u32 part4 = movd(rshiftbyte_m128(p128_0, 12)); \
- u32 part5 = movd(p128_1); \
- u32 part6 = movd(rshiftbyte_m128(p128_1, 4)); \
- u32 part7 = movd(rshiftbyte_m128(p128_1, 8)); \
- u32 part8 = movd(rshiftbyte_m128(p128_1, 12)); \
- u32 part9 = movd(p128_2); \
- u32 part10 = movd(rshiftbyte_m128(p128_2, 4)); \
- u32 part11 = movd(rshiftbyte_m128(p128_2, 8)); \
- u32 part12 = movd(rshiftbyte_m128(p128_2, 12)); \
- u32 part13 = movd(p128_3); \
- u32 part14 = movd(rshiftbyte_m128(p128_3, 4)); \
- u32 part15 = movd(rshiftbyte_m128(p128_3, 8)); \
- u32 part16 = movd(rshiftbyte_m128(p128_3, 12)); \
- CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
- CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
- CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
- CONF_CHUNK_32(part5, bucket, offset + 16, reason, conf_fn); \
- CONF_CHUNK_32(part6, bucket, offset + 20, reason, conf_fn); \
- CONF_CHUNK_32(part7, bucket, offset + 24, reason, conf_fn); \
- CONF_CHUNK_32(part8, bucket, offset + 28, reason, conf_fn); \
- CONF_CHUNK_32(part9, bucket, offset + 32, reason, conf_fn); \
- CONF_CHUNK_32(part10, bucket, offset + 36, reason, conf_fn); \
- CONF_CHUNK_32(part11, bucket, offset + 40, reason, conf_fn); \
- CONF_CHUNK_32(part12, bucket, offset + 44, reason, conf_fn); \
- CONF_CHUNK_32(part13, bucket, offset + 48, reason, conf_fn); \
- CONF_CHUNK_32(part14, bucket, offset + 52, reason, conf_fn); \
- CONF_CHUNK_32(part15, bucket, offset + 56, reason, conf_fn); \
- CONF_CHUNK_32(part16, bucket, offset + 60, reason, conf_fn); \
- } \
-} while(0)
-#endif
-
-#define PREP_SHUF_MASK_NO_REINFORCEMENT(val) \
- m512 lo = and512(val, *lo_mask); \
- m512 hi = and512(rshift64_m512(val, 4), *lo_mask)
-
-#define PREP_SHUF_MASK \
- PREP_SHUF_MASK_NO_REINFORCEMENT(load512(ptr)); \
- *c_16 = *(ptr + 15); \
- *c_32 = *(ptr + 31); \
- *c_48 = *(ptr + 47); \
- m512 r_msk = set512_64(0ULL, r_msk_base[*c_48], 0ULL, r_msk_base[*c_32],\
- 0ULL, r_msk_base[*c_16], 0ULL, r_msk_base[*c_0]);\
- *c_0 = *(ptr + 63)
-
-#define SHIFT_OR_M1 \
- or512(pshufb_m512(dup_mask[0], lo), pshufb_m512(dup_mask[1], hi))
-
-#define SHIFT_OR_M2 \
- or512(lshift128_m512(or512(pshufb_m512(dup_mask[2], lo), \
- pshufb_m512(dup_mask[3], hi)), \
- 1), SHIFT_OR_M1)
-
-#define SHIFT_OR_M3 \
- or512(lshift128_m512(or512(pshufb_m512(dup_mask[4], lo), \
- pshufb_m512(dup_mask[5], hi)), \
- 2), SHIFT_OR_M2)
-
-#define SHIFT_OR_M4 \
- or512(lshift128_m512(or512(pshufb_m512(dup_mask[6], lo), \
- pshufb_m512(dup_mask[7], hi)), \
- 3), SHIFT_OR_M3)
-
-static really_inline
-m512 prep_conf_teddy_no_reinforcement_m1(const m512 *lo_mask,
- const m512 *dup_mask,
- const m512 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M1;
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff512(var, ones512()))) { \
+ m128 p128_0 = extract128from512(var, 0); \
+ m128 p128_1 = extract128from512(var, 1); \
+ m128 p128_2 = extract128from512(var, 2); \
+ m128 p128_3 = extract128from512(var, 3); \
+ u64a part1 = movq(p128_0); \
+ u64a part2 = movq(rshiftbyte_m128(p128_0, 8)); \
+ u64a part3 = movq(p128_1); \
+ u64a part4 = movq(rshiftbyte_m128(p128_1, 8)); \
+ u64a part5 = movq(p128_2); \
+ u64a part6 = movq(rshiftbyte_m128(p128_2, 8)); \
+ u64a part7 = movq(p128_3); \
+ u64a part8 = movq(rshiftbyte_m128(p128_3, 8)); \
+ CONF_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_64(part2, bucket, offset + 8, reason, conf_fn); \
+ CONF_CHUNK_64(part3, bucket, offset + 16, reason, conf_fn); \
+ CONF_CHUNK_64(part4, bucket, offset + 24, reason, conf_fn); \
+ CONF_CHUNK_64(part5, bucket, offset + 32, reason, conf_fn); \
+ CONF_CHUNK_64(part6, bucket, offset + 40, reason, conf_fn); \
+ CONF_CHUNK_64(part7, bucket, offset + 48, reason, conf_fn); \
+ CONF_CHUNK_64(part8, bucket, offset + 56, reason, conf_fn); \
+ } \
+} while(0)
+#else
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff512(var, ones512()))) { \
+ m128 p128_0 = extract128from512(var, 0); \
+ m128 p128_1 = extract128from512(var, 1); \
+ m128 p128_2 = extract128from512(var, 2); \
+ m128 p128_3 = extract128from512(var, 3); \
+ u32 part1 = movd(p128_0); \
+ u32 part2 = movd(rshiftbyte_m128(p128_0, 4)); \
+ u32 part3 = movd(rshiftbyte_m128(p128_0, 8)); \
+ u32 part4 = movd(rshiftbyte_m128(p128_0, 12)); \
+ u32 part5 = movd(p128_1); \
+ u32 part6 = movd(rshiftbyte_m128(p128_1, 4)); \
+ u32 part7 = movd(rshiftbyte_m128(p128_1, 8)); \
+ u32 part8 = movd(rshiftbyte_m128(p128_1, 12)); \
+ u32 part9 = movd(p128_2); \
+ u32 part10 = movd(rshiftbyte_m128(p128_2, 4)); \
+ u32 part11 = movd(rshiftbyte_m128(p128_2, 8)); \
+ u32 part12 = movd(rshiftbyte_m128(p128_2, 12)); \
+ u32 part13 = movd(p128_3); \
+ u32 part14 = movd(rshiftbyte_m128(p128_3, 4)); \
+ u32 part15 = movd(rshiftbyte_m128(p128_3, 8)); \
+ u32 part16 = movd(rshiftbyte_m128(p128_3, 12)); \
+ CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
+ CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
+ CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
+ CONF_CHUNK_32(part5, bucket, offset + 16, reason, conf_fn); \
+ CONF_CHUNK_32(part6, bucket, offset + 20, reason, conf_fn); \
+ CONF_CHUNK_32(part7, bucket, offset + 24, reason, conf_fn); \
+ CONF_CHUNK_32(part8, bucket, offset + 28, reason, conf_fn); \
+ CONF_CHUNK_32(part9, bucket, offset + 32, reason, conf_fn); \
+ CONF_CHUNK_32(part10, bucket, offset + 36, reason, conf_fn); \
+ CONF_CHUNK_32(part11, bucket, offset + 40, reason, conf_fn); \
+ CONF_CHUNK_32(part12, bucket, offset + 44, reason, conf_fn); \
+ CONF_CHUNK_32(part13, bucket, offset + 48, reason, conf_fn); \
+ CONF_CHUNK_32(part14, bucket, offset + 52, reason, conf_fn); \
+ CONF_CHUNK_32(part15, bucket, offset + 56, reason, conf_fn); \
+ CONF_CHUNK_32(part16, bucket, offset + 60, reason, conf_fn); \
+ } \
+} while(0)
+#endif
+
+#define PREP_SHUF_MASK_NO_REINFORCEMENT(val) \
+ m512 lo = and512(val, *lo_mask); \
+ m512 hi = and512(rshift64_m512(val, 4), *lo_mask)
+
+#define PREP_SHUF_MASK \
+ PREP_SHUF_MASK_NO_REINFORCEMENT(load512(ptr)); \
+ *c_16 = *(ptr + 15); \
+ *c_32 = *(ptr + 31); \
+ *c_48 = *(ptr + 47); \
+ m512 r_msk = set512_64(0ULL, r_msk_base[*c_48], 0ULL, r_msk_base[*c_32],\
+ 0ULL, r_msk_base[*c_16], 0ULL, r_msk_base[*c_0]);\
+ *c_0 = *(ptr + 63)
+
+#define SHIFT_OR_M1 \
+ or512(pshufb_m512(dup_mask[0], lo), pshufb_m512(dup_mask[1], hi))
+
+#define SHIFT_OR_M2 \
+ or512(lshift128_m512(or512(pshufb_m512(dup_mask[2], lo), \
+ pshufb_m512(dup_mask[3], hi)), \
+ 1), SHIFT_OR_M1)
+
+#define SHIFT_OR_M3 \
+ or512(lshift128_m512(or512(pshufb_m512(dup_mask[4], lo), \
+ pshufb_m512(dup_mask[5], hi)), \
+ 2), SHIFT_OR_M2)
+
+#define SHIFT_OR_M4 \
+ or512(lshift128_m512(or512(pshufb_m512(dup_mask[6], lo), \
+ pshufb_m512(dup_mask[7], hi)), \
+ 3), SHIFT_OR_M3)
+
+static really_inline
+m512 prep_conf_teddy_no_reinforcement_m1(const m512 *lo_mask,
+ const m512 *dup_mask,
+ const m512 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M1;
+}
+
+static really_inline
+m512 prep_conf_teddy_no_reinforcement_m2(const m512 *lo_mask,
+ const m512 *dup_mask,
+ const m512 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M2;
+}
+
+static really_inline
+m512 prep_conf_teddy_no_reinforcement_m3(const m512 *lo_mask,
+ const m512 *dup_mask,
+ const m512 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M3;
+}
+
+static really_inline
+m512 prep_conf_teddy_no_reinforcement_m4(const m512 *lo_mask,
+ const m512 *dup_mask,
+ const m512 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M4;
}
-static really_inline
-m512 prep_conf_teddy_no_reinforcement_m2(const m512 *lo_mask,
- const m512 *dup_mask,
- const m512 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M2;
-}
-
-static really_inline
-m512 prep_conf_teddy_no_reinforcement_m3(const m512 *lo_mask,
- const m512 *dup_mask,
- const m512 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M3;
-}
-
-static really_inline
-m512 prep_conf_teddy_no_reinforcement_m4(const m512 *lo_mask,
- const m512 *dup_mask,
- const m512 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M4;
+static really_inline
+m512 prep_conf_teddy_m1(const m512 *lo_mask, const m512 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
+ PREP_SHUF_MASK;
+ return or512(SHIFT_OR_M1, r_msk);
}
-static really_inline
-m512 prep_conf_teddy_m1(const m512 *lo_mask, const m512 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
- PREP_SHUF_MASK;
- return or512(SHIFT_OR_M1, r_msk);
-}
-
-static really_inline
-m512 prep_conf_teddy_m2(const m512 *lo_mask, const m512 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
- PREP_SHUF_MASK;
- return or512(SHIFT_OR_M2, r_msk);
-}
-
-static really_inline
-m512 prep_conf_teddy_m3(const m512 *lo_mask, const m512 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
- PREP_SHUF_MASK;
- return or512(SHIFT_OR_M3, r_msk);
-}
-
-static really_inline
-m512 prep_conf_teddy_m4(const m512 *lo_mask, const m512 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
- PREP_SHUF_MASK;
- return or512(SHIFT_OR_M4, r_msk);
-}
-
-#define PREP_CONF_FN_NO_REINFORCEMENT(val, n) \
- prep_conf_teddy_no_reinforcement_m##n(&lo_mask, dup_mask, val)
-
-#define PREP_CONF_FN(ptr, n) \
- prep_conf_teddy_m##n(&lo_mask, dup_mask, ptr, r_msk_base, \
- &c_0, &c_16, &c_32, &c_48)
-
-#define PREPARE_MASKS_1 \
- dup_mask[0] = set4x128(maskBase[0]); \
- dup_mask[1] = set4x128(maskBase[1]);
-
-#define PREPARE_MASKS_2 \
- PREPARE_MASKS_1 \
- dup_mask[2] = set4x128(maskBase[2]); \
- dup_mask[3] = set4x128(maskBase[3]);
-
-#define PREPARE_MASKS_3 \
- PREPARE_MASKS_2 \
- dup_mask[4] = set4x128(maskBase[4]); \
- dup_mask[5] = set4x128(maskBase[5]);
-
-#define PREPARE_MASKS_4 \
- PREPARE_MASKS_3 \
- dup_mask[6] = set4x128(maskBase[6]); \
- dup_mask[7] = set4x128(maskBase[7]);
-
-#define PREPARE_MASKS(n) \
- m512 lo_mask = set64x8(0xf); \
- m512 dup_mask[n * 2]; \
- PREPARE_MASKS_##n
-
-#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
-do { \
- const u8 *buf_end = a->buf + a->len; \
- const u8 *ptr = a->buf + a->start_offset; \
- u32 floodBackoff = FLOOD_BACKOFF_START; \
- const u8 *tryFloodDetect = a->firstFloodDetect; \
- u32 last_match = ones_u32; \
- const struct Teddy *teddy = (const struct Teddy *)fdr; \
- const size_t iterBytes = 128; \
- DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
- a->buf, a->len, a->start_offset); \
- \
- const m128 *maskBase = getMaskBase(teddy); \
- PREPARE_MASKS(n_msk); \
- const u32 *confBase = getConfBase(teddy); \
- \
- const u64a *r_msk_base = getReinforcedMaskBase(teddy, n_msk); \
- u32 c_0 = 0x100; \
- u32 c_16 = 0x100; \
- u32 c_32 = 0x100; \
- u32 c_48 = 0x100; \
- const u8 *mainStart = ROUNDUP_PTR(ptr, 64); \
- DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
- if (ptr < mainStart) { \
- ptr = mainStart - 64; \
- m512 p_mask; \
- m512 val_0 = vectoredLoad512(&p_mask, ptr, a->start_offset, \
- a->buf, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m512 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
- r_0 = or512(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 64; \
- } \
- \
- if (ptr + 64 <= buf_end) { \
- m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 64; \
- } \
- \
- for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
- __builtin_prefetch(ptr + (iterBytes * 4)); \
- CHECK_FLOOD; \
- m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- m512 r_1 = PREP_CONF_FN(ptr + 64, n_msk); \
- CONFIRM_TEDDY(r_1, 8, 64, NOT_CAUTIOUS, conf_fn); \
- } \
- \
- if (ptr + 64 <= buf_end) { \
- m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- ptr += 64; \
- } \
- \
- assert(ptr + 64 > buf_end); \
- if (ptr < buf_end) { \
- m512 p_mask; \
- m512 val_0 = vectoredLoad512(&p_mask, ptr, 0, ptr, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m512 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
- r_0 = or512(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- } \
- \
- return HWLM_SUCCESS; \
-} while(0)
-
-#elif defined(HAVE_AVX2) // not HAVE_AVX512 but HAVE_AVX2 reinforced teddy
-
-#ifdef ARCH_64_BIT
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff256(var, ones256()))) { \
- m128 lo = movdq_lo(var); \
- m128 hi = movdq_hi(var); \
- u64a part1 = movq(lo); \
- u64a part2 = movq(rshiftbyte_m128(lo, 8)); \
- u64a part3 = movq(hi); \
- u64a part4 = movq(rshiftbyte_m128(hi, 8)); \
- CONF_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_64(part2, bucket, offset + 8, reason, conf_fn); \
- CONF_CHUNK_64(part3, bucket, offset + 16, reason, conf_fn); \
- CONF_CHUNK_64(part4, bucket, offset + 24, reason, conf_fn); \
- } \
-} while(0)
-#else
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff256(var, ones256()))) { \
- m128 lo = movdq_lo(var); \
- m128 hi = movdq_hi(var); \
- u32 part1 = movd(lo); \
- u32 part2 = movd(rshiftbyte_m128(lo, 4)); \
- u32 part3 = movd(rshiftbyte_m128(lo, 8)); \
- u32 part4 = movd(rshiftbyte_m128(lo, 12)); \
- u32 part5 = movd(hi); \
- u32 part6 = movd(rshiftbyte_m128(hi, 4)); \
- u32 part7 = movd(rshiftbyte_m128(hi, 8)); \
- u32 part8 = movd(rshiftbyte_m128(hi, 12)); \
- CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
- CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
- CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
- CONF_CHUNK_32(part5, bucket, offset + 16, reason, conf_fn); \
- CONF_CHUNK_32(part6, bucket, offset + 20, reason, conf_fn); \
- CONF_CHUNK_32(part7, bucket, offset + 24, reason, conf_fn); \
- CONF_CHUNK_32(part8, bucket, offset + 28, reason, conf_fn); \
- } \
-} while(0)
-#endif
-
-#define PREP_SHUF_MASK_NO_REINFORCEMENT(val) \
- m256 lo = and256(val, *lo_mask); \
- m256 hi = and256(rshift64_m256(val, 4), *lo_mask)
-
-#define PREP_SHUF_MASK \
- PREP_SHUF_MASK_NO_REINFORCEMENT(load256(ptr)); \
- *c_128 = *(ptr + 15); \
- m256 r_msk = set64x4(0ULL, r_msk_base[*c_128], 0ULL, r_msk_base[*c_0]); \
- *c_0 = *(ptr + 31)
-
-#define SHIFT_OR_M1 \
- or256(pshufb_m256(dup_mask[0], lo), pshufb_m256(dup_mask[1], hi))
-
-#define SHIFT_OR_M2 \
- or256(lshift128_m256(or256(pshufb_m256(dup_mask[2], lo), \
- pshufb_m256(dup_mask[3], hi)), \
- 1), SHIFT_OR_M1)
-
-#define SHIFT_OR_M3 \
- or256(lshift128_m256(or256(pshufb_m256(dup_mask[4], lo), \
- pshufb_m256(dup_mask[5], hi)), \
- 2), SHIFT_OR_M2)
-
-#define SHIFT_OR_M4 \
- or256(lshift128_m256(or256(pshufb_m256(dup_mask[6], lo), \
- pshufb_m256(dup_mask[7], hi)), \
- 3), SHIFT_OR_M3)
-
-static really_inline
-m256 prep_conf_teddy_no_reinforcement_m1(const m256 *lo_mask,
- const m256 *dup_mask,
- const m256 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M1;
+static really_inline
+m512 prep_conf_teddy_m2(const m512 *lo_mask, const m512 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
+ PREP_SHUF_MASK;
+ return or512(SHIFT_OR_M2, r_msk);
}
-static really_inline
-m256 prep_conf_teddy_no_reinforcement_m2(const m256 *lo_mask,
- const m256 *dup_mask,
- const m256 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M2;
-}
-
-static really_inline
-m256 prep_conf_teddy_no_reinforcement_m3(const m256 *lo_mask,
- const m256 *dup_mask,
- const m256 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M3;
-}
-
-static really_inline
-m256 prep_conf_teddy_no_reinforcement_m4(const m256 *lo_mask,
- const m256 *dup_mask,
- const m256 val) {
- PREP_SHUF_MASK_NO_REINFORCEMENT(val);
- return SHIFT_OR_M4;
-}
-
-static really_inline
-m256 prep_conf_teddy_m1(const m256 *lo_mask, const m256 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_128) {
- PREP_SHUF_MASK;
- return or256(SHIFT_OR_M1, r_msk);
-}
-
-static really_inline
-m256 prep_conf_teddy_m2(const m256 *lo_mask, const m256 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_128) {
- PREP_SHUF_MASK;
- return or256(SHIFT_OR_M2, r_msk);
-}
-
-static really_inline
-m256 prep_conf_teddy_m3(const m256 *lo_mask, const m256 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_128) {
- PREP_SHUF_MASK;
- return or256(SHIFT_OR_M3, r_msk);
-}
-
-static really_inline
-m256 prep_conf_teddy_m4(const m256 *lo_mask, const m256 *dup_mask,
- const u8 *ptr, const u64a *r_msk_base,
- u32 *c_0, u32 *c_128) {
- PREP_SHUF_MASK;
- return or256(SHIFT_OR_M4, r_msk);
-}
-
-#define PREP_CONF_FN_NO_REINFORCEMENT(val, n) \
- prep_conf_teddy_no_reinforcement_m##n(&lo_mask, dup_mask, val)
-
-#define PREP_CONF_FN(ptr, n) \
- prep_conf_teddy_m##n(&lo_mask, dup_mask, ptr, r_msk_base, &c_0, &c_128)
-
-#define PREPARE_MASKS_1 \
- dup_mask[0] = set2x128(maskBase[0]); \
- dup_mask[1] = set2x128(maskBase[1]);
-
-#define PREPARE_MASKS_2 \
- PREPARE_MASKS_1 \
- dup_mask[2] = set2x128(maskBase[2]); \
- dup_mask[3] = set2x128(maskBase[3]);
-
-#define PREPARE_MASKS_3 \
- PREPARE_MASKS_2 \
- dup_mask[4] = set2x128(maskBase[4]); \
- dup_mask[5] = set2x128(maskBase[5]);
-
-#define PREPARE_MASKS_4 \
- PREPARE_MASKS_3 \
- dup_mask[6] = set2x128(maskBase[6]); \
- dup_mask[7] = set2x128(maskBase[7]);
-
-#define PREPARE_MASKS(n) \
- m256 lo_mask = set32x8(0xf); \
- m256 dup_mask[n * 2]; \
- PREPARE_MASKS_##n
-
-#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
-do { \
- const u8 *buf_end = a->buf + a->len; \
- const u8 *ptr = a->buf + a->start_offset; \
- u32 floodBackoff = FLOOD_BACKOFF_START; \
- const u8 *tryFloodDetect = a->firstFloodDetect; \
- u32 last_match = ones_u32; \
- const struct Teddy *teddy = (const struct Teddy *)fdr; \
- const size_t iterBytes = 64; \
- DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
- a->buf, a->len, a->start_offset); \
- \
- const m128 *maskBase = getMaskBase(teddy); \
- PREPARE_MASKS(n_msk); \
- const u32 *confBase = getConfBase(teddy); \
- \
- const u64a *r_msk_base = getReinforcedMaskBase(teddy, n_msk); \
- u32 c_0 = 0x100; \
- u32 c_128 = 0x100; \
- const u8 *mainStart = ROUNDUP_PTR(ptr, 32); \
- DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
- if (ptr < mainStart) { \
- ptr = mainStart - 32; \
- m256 p_mask; \
- m256 val_0 = vectoredLoad256(&p_mask, ptr, a->start_offset, \
- a->buf, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m256 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
- r_0 = or256(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 32; \
- } \
- \
- if (ptr + 32 <= buf_end) { \
- m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 32; \
- } \
- \
- for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
- __builtin_prefetch(ptr + (iterBytes * 4)); \
- CHECK_FLOOD; \
- m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- m256 r_1 = PREP_CONF_FN(ptr + 32, n_msk); \
- CONFIRM_TEDDY(r_1, 8, 32, NOT_CAUTIOUS, conf_fn); \
- } \
- \
- if (ptr + 32 <= buf_end) { \
- m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- ptr += 32; \
- } \
- \
- assert(ptr + 32 > buf_end); \
- if (ptr < buf_end) { \
- m256 p_mask; \
- m256 val_0 = vectoredLoad256(&p_mask, ptr, 0, ptr, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m256 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
- r_0 = or256(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- } \
- \
- return HWLM_SUCCESS; \
-} while(0)
-
-#else // not defined HAVE_AVX2
-
-#ifdef ARCH_64_BIT
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff128(var, ones128()))) { \
- u64a lo = movq(var); \
- u64a hi = movq(rshiftbyte_m128(var, 8)); \
- CONF_CHUNK_64(lo, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_64(hi, bucket, offset + 8, reason, conf_fn); \
- } \
-} while(0)
-#else
-#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff128(var, ones128()))) { \
- u32 part1 = movd(var); \
- u32 part2 = movd(rshiftbyte_m128(var, 4)); \
- u32 part3 = movd(rshiftbyte_m128(var, 8)); \
- u32 part4 = movd(rshiftbyte_m128(var, 12)); \
- CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
- CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
- CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
- CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
- } \
-} while(0)
-#endif
-
-static really_inline
-m128 prep_conf_teddy_m1(const m128 *maskBase, m128 val) {
- m128 mask = set16x8(0xf);
- m128 lo = and128(val, mask);
- m128 hi = and128(rshift64_m128(val, 4), mask);
- return or128(pshufb_m128(maskBase[0 * 2], lo),
- pshufb_m128(maskBase[0 * 2 + 1], hi));
-}
-
-static really_inline
-m128 prep_conf_teddy_m2(const m128 *maskBase, m128 *old_1, m128 val) {
- m128 mask = set16x8(0xf);
- m128 lo = and128(val, mask);
- m128 hi = and128(rshift64_m128(val, 4), mask);
- m128 r = prep_conf_teddy_m1(maskBase, val);
-
- m128 res_1 = or128(pshufb_m128(maskBase[1 * 2], lo),
- pshufb_m128(maskBase[1 * 2 + 1], hi));
- m128 res_shifted_1 = palignr(res_1, *old_1, 16 - 1);
- *old_1 = res_1;
- return or128(r, res_shifted_1);
-}
-
-static really_inline
-m128 prep_conf_teddy_m3(const m128 *maskBase, m128 *old_1, m128 *old_2,
- m128 val) {
- m128 mask = set16x8(0xf);
- m128 lo = and128(val, mask);
- m128 hi = and128(rshift64_m128(val, 4), mask);
- m128 r = prep_conf_teddy_m2(maskBase, old_1, val);
-
- m128 res_2 = or128(pshufb_m128(maskBase[2 * 2], lo),
- pshufb_m128(maskBase[2 * 2 + 1], hi));
- m128 res_shifted_2 = palignr(res_2, *old_2, 16 - 2);
- *old_2 = res_2;
- return or128(r, res_shifted_2);
-}
-
-static really_inline
-m128 prep_conf_teddy_m4(const m128 *maskBase, m128 *old_1, m128 *old_2,
- m128 *old_3, m128 val) {
- m128 mask = set16x8(0xf);
- m128 lo = and128(val, mask);
- m128 hi = and128(rshift64_m128(val, 4), mask);
- m128 r = prep_conf_teddy_m3(maskBase, old_1, old_2, val);
-
- m128 res_3 = or128(pshufb_m128(maskBase[3 * 2], lo),
- pshufb_m128(maskBase[3 * 2 + 1], hi));
- m128 res_shifted_3 = palignr(res_3, *old_3, 16 - 3);
- *old_3 = res_3;
- return or128(r, res_shifted_3);
-}
-
-#define FDR_EXEC_TEDDY_RES_OLD_1
-
-#define FDR_EXEC_TEDDY_RES_OLD_2 \
- m128 res_old_1 = zeroes128();
-
-#define FDR_EXEC_TEDDY_RES_OLD_3 \
- m128 res_old_1 = zeroes128(); \
- m128 res_old_2 = zeroes128();
-
-#define FDR_EXEC_TEDDY_RES_OLD_4 \
- m128 res_old_1 = zeroes128(); \
- m128 res_old_2 = zeroes128(); \
- m128 res_old_3 = zeroes128();
-
-#define FDR_EXEC_TEDDY_RES_OLD(n) FDR_EXEC_TEDDY_RES_OLD_##n
-
-#define PREP_CONF_FN_1(mask_base, val) \
- prep_conf_teddy_m1(mask_base, val)
-
-#define PREP_CONF_FN_2(mask_base, val) \
- prep_conf_teddy_m2(mask_base, &res_old_1, val)
-
-#define PREP_CONF_FN_3(mask_base, val) \
- prep_conf_teddy_m3(mask_base, &res_old_1, &res_old_2, val)
-
-#define PREP_CONF_FN_4(mask_base, val) \
- prep_conf_teddy_m4(mask_base, &res_old_1, &res_old_2, &res_old_3, val)
-
-#define PREP_CONF_FN(mask_base, val, n) \
- PREP_CONF_FN_##n(mask_base, val)
-
-#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
-do { \
- const u8 *buf_end = a->buf + a->len; \
- const u8 *ptr = a->buf + a->start_offset; \
- u32 floodBackoff = FLOOD_BACKOFF_START; \
- const u8 *tryFloodDetect = a->firstFloodDetect; \
- u32 last_match = ones_u32; \
- const struct Teddy *teddy = (const struct Teddy *)fdr; \
- const size_t iterBytes = 32; \
- DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
- a->buf, a->len, a->start_offset); \
- \
- const m128 *maskBase = getMaskBase(teddy); \
- const u32 *confBase = getConfBase(teddy); \
- \
- FDR_EXEC_TEDDY_RES_OLD(n_msk); \
- const u8 *mainStart = ROUNDUP_PTR(ptr, 16); \
- DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
- if (ptr < mainStart) { \
- ptr = mainStart - 16; \
- m128 p_mask; \
- m128 val_0 = vectoredLoad128(&p_mask, ptr, a->start_offset, \
- a->buf, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m128 r_0 = PREP_CONF_FN(maskBase, val_0, n_msk); \
- r_0 = or128(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 16; \
- } \
- \
- if (ptr + 16 <= buf_end) { \
- m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- ptr += 16; \
- } \
- \
- for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
- __builtin_prefetch(ptr + (iterBytes * 4)); \
- CHECK_FLOOD; \
- m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- m128 r_1 = PREP_CONF_FN(maskBase, load128(ptr + 16), n_msk); \
- CONFIRM_TEDDY(r_1, 8, 16, NOT_CAUTIOUS, conf_fn); \
- } \
- \
- if (ptr + 16 <= buf_end) { \
- m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
- CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
- ptr += 16; \
- } \
- \
- assert(ptr + 16 > buf_end); \
- if (ptr < buf_end) { \
- m128 p_mask; \
- m128 val_0 = vectoredLoad128(&p_mask, ptr, 0, ptr, buf_end, \
- a->buf_history, a->len_history, n_msk); \
- m128 r_0 = PREP_CONF_FN(maskBase, val_0, n_msk); \
- r_0 = or128(r_0, p_mask); \
- CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
- } \
- \
- return HWLM_SUCCESS; \
-} while(0)
-
-#endif // HAVE_AVX2 HAVE_AVX512
-
-hwlm_error_t fdr_exec_teddy_msks1(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks1_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks2(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks2_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks3(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks3_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks4(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_teddy_msks4_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
-}
+static really_inline
+m512 prep_conf_teddy_m3(const m512 *lo_mask, const m512 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
+ PREP_SHUF_MASK;
+ return or512(SHIFT_OR_M3, r_msk);
+}
+
+static really_inline
+m512 prep_conf_teddy_m4(const m512 *lo_mask, const m512 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_16, u32 *c_32, u32 *c_48) {
+ PREP_SHUF_MASK;
+ return or512(SHIFT_OR_M4, r_msk);
+}
+
+#define PREP_CONF_FN_NO_REINFORCEMENT(val, n) \
+ prep_conf_teddy_no_reinforcement_m##n(&lo_mask, dup_mask, val)
+
+#define PREP_CONF_FN(ptr, n) \
+ prep_conf_teddy_m##n(&lo_mask, dup_mask, ptr, r_msk_base, \
+ &c_0, &c_16, &c_32, &c_48)
+
+#define PREPARE_MASKS_1 \
+ dup_mask[0] = set4x128(maskBase[0]); \
+ dup_mask[1] = set4x128(maskBase[1]);
+
+#define PREPARE_MASKS_2 \
+ PREPARE_MASKS_1 \
+ dup_mask[2] = set4x128(maskBase[2]); \
+ dup_mask[3] = set4x128(maskBase[3]);
+
+#define PREPARE_MASKS_3 \
+ PREPARE_MASKS_2 \
+ dup_mask[4] = set4x128(maskBase[4]); \
+ dup_mask[5] = set4x128(maskBase[5]);
+
+#define PREPARE_MASKS_4 \
+ PREPARE_MASKS_3 \
+ dup_mask[6] = set4x128(maskBase[6]); \
+ dup_mask[7] = set4x128(maskBase[7]);
+
+#define PREPARE_MASKS(n) \
+ m512 lo_mask = set64x8(0xf); \
+ m512 dup_mask[n * 2]; \
+ PREPARE_MASKS_##n
+
+#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
+do { \
+ const u8 *buf_end = a->buf + a->len; \
+ const u8 *ptr = a->buf + a->start_offset; \
+ u32 floodBackoff = FLOOD_BACKOFF_START; \
+ const u8 *tryFloodDetect = a->firstFloodDetect; \
+ u32 last_match = ones_u32; \
+ const struct Teddy *teddy = (const struct Teddy *)fdr; \
+ const size_t iterBytes = 128; \
+ DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
+ a->buf, a->len, a->start_offset); \
+ \
+ const m128 *maskBase = getMaskBase(teddy); \
+ PREPARE_MASKS(n_msk); \
+ const u32 *confBase = getConfBase(teddy); \
+ \
+ const u64a *r_msk_base = getReinforcedMaskBase(teddy, n_msk); \
+ u32 c_0 = 0x100; \
+ u32 c_16 = 0x100; \
+ u32 c_32 = 0x100; \
+ u32 c_48 = 0x100; \
+ const u8 *mainStart = ROUNDUP_PTR(ptr, 64); \
+ DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
+ if (ptr < mainStart) { \
+ ptr = mainStart - 64; \
+ m512 p_mask; \
+ m512 val_0 = vectoredLoad512(&p_mask, ptr, a->start_offset, \
+ a->buf, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m512 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
+ r_0 = or512(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 64; \
+ } \
+ \
+ if (ptr + 64 <= buf_end) { \
+ m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 64; \
+ } \
+ \
+ for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
+ __builtin_prefetch(ptr + (iterBytes * 4)); \
+ CHECK_FLOOD; \
+ m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ m512 r_1 = PREP_CONF_FN(ptr + 64, n_msk); \
+ CONFIRM_TEDDY(r_1, 8, 64, NOT_CAUTIOUS, conf_fn); \
+ } \
+ \
+ if (ptr + 64 <= buf_end) { \
+ m512 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ ptr += 64; \
+ } \
+ \
+ assert(ptr + 64 > buf_end); \
+ if (ptr < buf_end) { \
+ m512 p_mask; \
+ m512 val_0 = vectoredLoad512(&p_mask, ptr, 0, ptr, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m512 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
+ r_0 = or512(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ } \
+ \
+ return HWLM_SUCCESS; \
+} while(0)
+
+#elif defined(HAVE_AVX2) // not HAVE_AVX512 but HAVE_AVX2 reinforced teddy
+
+#ifdef ARCH_64_BIT
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff256(var, ones256()))) { \
+ m128 lo = movdq_lo(var); \
+ m128 hi = movdq_hi(var); \
+ u64a part1 = movq(lo); \
+ u64a part2 = movq(rshiftbyte_m128(lo, 8)); \
+ u64a part3 = movq(hi); \
+ u64a part4 = movq(rshiftbyte_m128(hi, 8)); \
+ CONF_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_64(part2, bucket, offset + 8, reason, conf_fn); \
+ CONF_CHUNK_64(part3, bucket, offset + 16, reason, conf_fn); \
+ CONF_CHUNK_64(part4, bucket, offset + 24, reason, conf_fn); \
+ } \
+} while(0)
+#else
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff256(var, ones256()))) { \
+ m128 lo = movdq_lo(var); \
+ m128 hi = movdq_hi(var); \
+ u32 part1 = movd(lo); \
+ u32 part2 = movd(rshiftbyte_m128(lo, 4)); \
+ u32 part3 = movd(rshiftbyte_m128(lo, 8)); \
+ u32 part4 = movd(rshiftbyte_m128(lo, 12)); \
+ u32 part5 = movd(hi); \
+ u32 part6 = movd(rshiftbyte_m128(hi, 4)); \
+ u32 part7 = movd(rshiftbyte_m128(hi, 8)); \
+ u32 part8 = movd(rshiftbyte_m128(hi, 12)); \
+ CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
+ CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
+ CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
+ CONF_CHUNK_32(part5, bucket, offset + 16, reason, conf_fn); \
+ CONF_CHUNK_32(part6, bucket, offset + 20, reason, conf_fn); \
+ CONF_CHUNK_32(part7, bucket, offset + 24, reason, conf_fn); \
+ CONF_CHUNK_32(part8, bucket, offset + 28, reason, conf_fn); \
+ } \
+} while(0)
+#endif
+
+#define PREP_SHUF_MASK_NO_REINFORCEMENT(val) \
+ m256 lo = and256(val, *lo_mask); \
+ m256 hi = and256(rshift64_m256(val, 4), *lo_mask)
+
+#define PREP_SHUF_MASK \
+ PREP_SHUF_MASK_NO_REINFORCEMENT(load256(ptr)); \
+ *c_128 = *(ptr + 15); \
+ m256 r_msk = set64x4(0ULL, r_msk_base[*c_128], 0ULL, r_msk_base[*c_0]); \
+ *c_0 = *(ptr + 31)
+
+#define SHIFT_OR_M1 \
+ or256(pshufb_m256(dup_mask[0], lo), pshufb_m256(dup_mask[1], hi))
+
+#define SHIFT_OR_M2 \
+ or256(lshift128_m256(or256(pshufb_m256(dup_mask[2], lo), \
+ pshufb_m256(dup_mask[3], hi)), \
+ 1), SHIFT_OR_M1)
+
+#define SHIFT_OR_M3 \
+ or256(lshift128_m256(or256(pshufb_m256(dup_mask[4], lo), \
+ pshufb_m256(dup_mask[5], hi)), \
+ 2), SHIFT_OR_M2)
+
+#define SHIFT_OR_M4 \
+ or256(lshift128_m256(or256(pshufb_m256(dup_mask[6], lo), \
+ pshufb_m256(dup_mask[7], hi)), \
+ 3), SHIFT_OR_M3)
+
+static really_inline
+m256 prep_conf_teddy_no_reinforcement_m1(const m256 *lo_mask,
+ const m256 *dup_mask,
+ const m256 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M1;
+}
+
+static really_inline
+m256 prep_conf_teddy_no_reinforcement_m2(const m256 *lo_mask,
+ const m256 *dup_mask,
+ const m256 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M2;
+}
+
+static really_inline
+m256 prep_conf_teddy_no_reinforcement_m3(const m256 *lo_mask,
+ const m256 *dup_mask,
+ const m256 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M3;
+}
+
+static really_inline
+m256 prep_conf_teddy_no_reinforcement_m4(const m256 *lo_mask,
+ const m256 *dup_mask,
+ const m256 val) {
+ PREP_SHUF_MASK_NO_REINFORCEMENT(val);
+ return SHIFT_OR_M4;
+}
+
+static really_inline
+m256 prep_conf_teddy_m1(const m256 *lo_mask, const m256 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_128) {
+ PREP_SHUF_MASK;
+ return or256(SHIFT_OR_M1, r_msk);
+}
+
+static really_inline
+m256 prep_conf_teddy_m2(const m256 *lo_mask, const m256 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_128) {
+ PREP_SHUF_MASK;
+ return or256(SHIFT_OR_M2, r_msk);
+}
+
+static really_inline
+m256 prep_conf_teddy_m3(const m256 *lo_mask, const m256 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_128) {
+ PREP_SHUF_MASK;
+ return or256(SHIFT_OR_M3, r_msk);
+}
+
+static really_inline
+m256 prep_conf_teddy_m4(const m256 *lo_mask, const m256 *dup_mask,
+ const u8 *ptr, const u64a *r_msk_base,
+ u32 *c_0, u32 *c_128) {
+ PREP_SHUF_MASK;
+ return or256(SHIFT_OR_M4, r_msk);
+}
+
+#define PREP_CONF_FN_NO_REINFORCEMENT(val, n) \
+ prep_conf_teddy_no_reinforcement_m##n(&lo_mask, dup_mask, val)
+
+#define PREP_CONF_FN(ptr, n) \
+ prep_conf_teddy_m##n(&lo_mask, dup_mask, ptr, r_msk_base, &c_0, &c_128)
+
+#define PREPARE_MASKS_1 \
+ dup_mask[0] = set2x128(maskBase[0]); \
+ dup_mask[1] = set2x128(maskBase[1]);
+
+#define PREPARE_MASKS_2 \
+ PREPARE_MASKS_1 \
+ dup_mask[2] = set2x128(maskBase[2]); \
+ dup_mask[3] = set2x128(maskBase[3]);
+
+#define PREPARE_MASKS_3 \
+ PREPARE_MASKS_2 \
+ dup_mask[4] = set2x128(maskBase[4]); \
+ dup_mask[5] = set2x128(maskBase[5]);
+
+#define PREPARE_MASKS_4 \
+ PREPARE_MASKS_3 \
+ dup_mask[6] = set2x128(maskBase[6]); \
+ dup_mask[7] = set2x128(maskBase[7]);
+
+#define PREPARE_MASKS(n) \
+ m256 lo_mask = set32x8(0xf); \
+ m256 dup_mask[n * 2]; \
+ PREPARE_MASKS_##n
+
+#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
+do { \
+ const u8 *buf_end = a->buf + a->len; \
+ const u8 *ptr = a->buf + a->start_offset; \
+ u32 floodBackoff = FLOOD_BACKOFF_START; \
+ const u8 *tryFloodDetect = a->firstFloodDetect; \
+ u32 last_match = ones_u32; \
+ const struct Teddy *teddy = (const struct Teddy *)fdr; \
+ const size_t iterBytes = 64; \
+ DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
+ a->buf, a->len, a->start_offset); \
+ \
+ const m128 *maskBase = getMaskBase(teddy); \
+ PREPARE_MASKS(n_msk); \
+ const u32 *confBase = getConfBase(teddy); \
+ \
+ const u64a *r_msk_base = getReinforcedMaskBase(teddy, n_msk); \
+ u32 c_0 = 0x100; \
+ u32 c_128 = 0x100; \
+ const u8 *mainStart = ROUNDUP_PTR(ptr, 32); \
+ DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
+ if (ptr < mainStart) { \
+ ptr = mainStart - 32; \
+ m256 p_mask; \
+ m256 val_0 = vectoredLoad256(&p_mask, ptr, a->start_offset, \
+ a->buf, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m256 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
+ r_0 = or256(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 32; \
+ } \
+ \
+ if (ptr + 32 <= buf_end) { \
+ m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 32; \
+ } \
+ \
+ for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
+ __builtin_prefetch(ptr + (iterBytes * 4)); \
+ CHECK_FLOOD; \
+ m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ m256 r_1 = PREP_CONF_FN(ptr + 32, n_msk); \
+ CONFIRM_TEDDY(r_1, 8, 32, NOT_CAUTIOUS, conf_fn); \
+ } \
+ \
+ if (ptr + 32 <= buf_end) { \
+ m256 r_0 = PREP_CONF_FN(ptr, n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ ptr += 32; \
+ } \
+ \
+ assert(ptr + 32 > buf_end); \
+ if (ptr < buf_end) { \
+ m256 p_mask; \
+ m256 val_0 = vectoredLoad256(&p_mask, ptr, 0, ptr, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m256 r_0 = PREP_CONF_FN_NO_REINFORCEMENT(val_0, n_msk); \
+ r_0 = or256(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ } \
+ \
+ return HWLM_SUCCESS; \
+} while(0)
+
+#else // not defined HAVE_AVX2
+
+#ifdef ARCH_64_BIT
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff128(var, ones128()))) { \
+ u64a lo = movq(var); \
+ u64a hi = movq(rshiftbyte_m128(var, 8)); \
+ CONF_CHUNK_64(lo, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_64(hi, bucket, offset + 8, reason, conf_fn); \
+ } \
+} while(0)
+#else
+#define CONFIRM_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff128(var, ones128()))) { \
+ u32 part1 = movd(var); \
+ u32 part2 = movd(rshiftbyte_m128(var, 4)); \
+ u32 part3 = movd(rshiftbyte_m128(var, 8)); \
+ u32 part4 = movd(rshiftbyte_m128(var, 12)); \
+ CONF_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
+ CONF_CHUNK_32(part2, bucket, offset + 4, reason, conf_fn); \
+ CONF_CHUNK_32(part3, bucket, offset + 8, reason, conf_fn); \
+ CONF_CHUNK_32(part4, bucket, offset + 12, reason, conf_fn); \
+ } \
+} while(0)
+#endif
+
+static really_inline
+m128 prep_conf_teddy_m1(const m128 *maskBase, m128 val) {
+ m128 mask = set16x8(0xf);
+ m128 lo = and128(val, mask);
+ m128 hi = and128(rshift64_m128(val, 4), mask);
+ return or128(pshufb_m128(maskBase[0 * 2], lo),
+ pshufb_m128(maskBase[0 * 2 + 1], hi));
+}
+
+static really_inline
+m128 prep_conf_teddy_m2(const m128 *maskBase, m128 *old_1, m128 val) {
+ m128 mask = set16x8(0xf);
+ m128 lo = and128(val, mask);
+ m128 hi = and128(rshift64_m128(val, 4), mask);
+ m128 r = prep_conf_teddy_m1(maskBase, val);
+
+ m128 res_1 = or128(pshufb_m128(maskBase[1 * 2], lo),
+ pshufb_m128(maskBase[1 * 2 + 1], hi));
+ m128 res_shifted_1 = palignr(res_1, *old_1, 16 - 1);
+ *old_1 = res_1;
+ return or128(r, res_shifted_1);
+}
+
+static really_inline
+m128 prep_conf_teddy_m3(const m128 *maskBase, m128 *old_1, m128 *old_2,
+ m128 val) {
+ m128 mask = set16x8(0xf);
+ m128 lo = and128(val, mask);
+ m128 hi = and128(rshift64_m128(val, 4), mask);
+ m128 r = prep_conf_teddy_m2(maskBase, old_1, val);
+
+ m128 res_2 = or128(pshufb_m128(maskBase[2 * 2], lo),
+ pshufb_m128(maskBase[2 * 2 + 1], hi));
+ m128 res_shifted_2 = palignr(res_2, *old_2, 16 - 2);
+ *old_2 = res_2;
+ return or128(r, res_shifted_2);
+}
+
+static really_inline
+m128 prep_conf_teddy_m4(const m128 *maskBase, m128 *old_1, m128 *old_2,
+ m128 *old_3, m128 val) {
+ m128 mask = set16x8(0xf);
+ m128 lo = and128(val, mask);
+ m128 hi = and128(rshift64_m128(val, 4), mask);
+ m128 r = prep_conf_teddy_m3(maskBase, old_1, old_2, val);
+
+ m128 res_3 = or128(pshufb_m128(maskBase[3 * 2], lo),
+ pshufb_m128(maskBase[3 * 2 + 1], hi));
+ m128 res_shifted_3 = palignr(res_3, *old_3, 16 - 3);
+ *old_3 = res_3;
+ return or128(r, res_shifted_3);
+}
+
+#define FDR_EXEC_TEDDY_RES_OLD_1
+
+#define FDR_EXEC_TEDDY_RES_OLD_2 \
+ m128 res_old_1 = zeroes128();
+
+#define FDR_EXEC_TEDDY_RES_OLD_3 \
+ m128 res_old_1 = zeroes128(); \
+ m128 res_old_2 = zeroes128();
+
+#define FDR_EXEC_TEDDY_RES_OLD_4 \
+ m128 res_old_1 = zeroes128(); \
+ m128 res_old_2 = zeroes128(); \
+ m128 res_old_3 = zeroes128();
+
+#define FDR_EXEC_TEDDY_RES_OLD(n) FDR_EXEC_TEDDY_RES_OLD_##n
+
+#define PREP_CONF_FN_1(mask_base, val) \
+ prep_conf_teddy_m1(mask_base, val)
+
+#define PREP_CONF_FN_2(mask_base, val) \
+ prep_conf_teddy_m2(mask_base, &res_old_1, val)
+
+#define PREP_CONF_FN_3(mask_base, val) \
+ prep_conf_teddy_m3(mask_base, &res_old_1, &res_old_2, val)
+
+#define PREP_CONF_FN_4(mask_base, val) \
+ prep_conf_teddy_m4(mask_base, &res_old_1, &res_old_2, &res_old_3, val)
+
+#define PREP_CONF_FN(mask_base, val, n) \
+ PREP_CONF_FN_##n(mask_base, val)
+
+#define FDR_EXEC_TEDDY(fdr, a, control, n_msk, conf_fn) \
+do { \
+ const u8 *buf_end = a->buf + a->len; \
+ const u8 *ptr = a->buf + a->start_offset; \
+ u32 floodBackoff = FLOOD_BACKOFF_START; \
+ const u8 *tryFloodDetect = a->firstFloodDetect; \
+ u32 last_match = ones_u32; \
+ const struct Teddy *teddy = (const struct Teddy *)fdr; \
+ const size_t iterBytes = 32; \
+ DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
+ a->buf, a->len, a->start_offset); \
+ \
+ const m128 *maskBase = getMaskBase(teddy); \
+ const u32 *confBase = getConfBase(teddy); \
+ \
+ FDR_EXEC_TEDDY_RES_OLD(n_msk); \
+ const u8 *mainStart = ROUNDUP_PTR(ptr, 16); \
+ DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
+ if (ptr < mainStart) { \
+ ptr = mainStart - 16; \
+ m128 p_mask; \
+ m128 val_0 = vectoredLoad128(&p_mask, ptr, a->start_offset, \
+ a->buf, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m128 r_0 = PREP_CONF_FN(maskBase, val_0, n_msk); \
+ r_0 = or128(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ if (ptr + 16 <= buf_end) { \
+ m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ for (; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
+ __builtin_prefetch(ptr + (iterBytes * 4)); \
+ CHECK_FLOOD; \
+ m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ m128 r_1 = PREP_CONF_FN(maskBase, load128(ptr + 16), n_msk); \
+ CONFIRM_TEDDY(r_1, 8, 16, NOT_CAUTIOUS, conf_fn); \
+ } \
+ \
+ if (ptr + 16 <= buf_end) { \
+ m128 r_0 = PREP_CONF_FN(maskBase, load128(ptr), n_msk); \
+ CONFIRM_TEDDY(r_0, 8, 0, NOT_CAUTIOUS, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ assert(ptr + 16 > buf_end); \
+ if (ptr < buf_end) { \
+ m128 p_mask; \
+ m128 val_0 = vectoredLoad128(&p_mask, ptr, 0, ptr, buf_end, \
+ a->buf_history, a->len_history, n_msk); \
+ m128 r_0 = PREP_CONF_FN(maskBase, val_0, n_msk); \
+ r_0 = or128(r_0, p_mask); \
+ CONFIRM_TEDDY(r_0, 8, 0, VECTORING, conf_fn); \
+ } \
+ \
+ return HWLM_SUCCESS; \
+} while(0)
+
+#endif // HAVE_AVX2 HAVE_AVX512
+
+hwlm_error_t fdr_exec_teddy_msks1(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks1_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks2(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks2_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks3(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks3_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks4(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_teddy_msks4_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
+}
diff --git a/contrib/libs/hyperscan/src/fdr/teddy.h b/contrib/libs/hyperscan/src/fdr/teddy.h
index fb24b5caf27..40ae075626e 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy.h
+++ b/contrib/libs/hyperscan/src/fdr/teddy.h
@@ -1,110 +1,110 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Teddy literal matcher: function declarations.
- */
-
-#ifndef TEDDY_H_
-#define TEDDY_H_
-
-#include "hwlm/hwlm.h" // for hwlm_group_t
-#include "util/arch.h"
-
-struct FDR; // forward declaration from fdr_internal.h
-struct FDR_Runtime_Args;
-
-hwlm_error_t fdr_exec_teddy_msks1(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks1_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks2(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks2_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks3(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks3_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks4(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_teddy_msks4_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-#if defined(HAVE_AVX2)
-
-hwlm_error_t fdr_exec_fat_teddy_msks1(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks1_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks2(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks2_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks3(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks3_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks4(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-hwlm_error_t fdr_exec_fat_teddy_msks4_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control);
-
-#endif /* HAVE_AVX2 */
-
-#endif /* TEDDY_H_ */
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Teddy literal matcher: function declarations.
+ */
+
+#ifndef TEDDY_H_
+#define TEDDY_H_
+
+#include "hwlm/hwlm.h" // for hwlm_group_t
+#include "util/arch.h"
+
+struct FDR; // forward declaration from fdr_internal.h
+struct FDR_Runtime_Args;
+
+hwlm_error_t fdr_exec_teddy_msks1(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks1_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks2(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks2_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks3(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks3_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks4(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_teddy_msks4_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+#if defined(HAVE_AVX2)
+
+hwlm_error_t fdr_exec_fat_teddy_msks1(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks1_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks2(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks2_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks3(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks3_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks4(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+hwlm_error_t fdr_exec_fat_teddy_msks4_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control);
+
+#endif /* HAVE_AVX2 */
+
+#endif /* TEDDY_H_ */
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_avx2.c b/contrib/libs/hyperscan/src/fdr/teddy_avx2.c
index d1a98f081ab..6a6b27a5f2f 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_avx2.c
+++ b/contrib/libs/hyperscan/src/fdr/teddy_avx2.c
@@ -1,114 +1,114 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Teddy literal matcher: AVX2 engine runtime.
- */
-
-#include "fdr_internal.h"
-#include "flood_runtime.h"
-#include "teddy.h"
-#include "teddy_internal.h"
-#include "teddy_runtime_common.h"
-#include "util/arch.h"
-#include "util/simd_utils.h"
-
-#if defined(HAVE_AVX2)
-
-const u8 ALIGN_AVX_DIRECTIVE p_mask_arr256[33][64] = {
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Teddy literal matcher: AVX2 engine runtime.
+ */
+
+#include "fdr_internal.h"
+#include "flood_runtime.h"
+#include "teddy.h"
+#include "teddy_internal.h"
+#include "teddy_runtime_common.h"
+#include "util/arch.h"
+#include "util/simd_utils.h"
+
+#if defined(HAVE_AVX2)
+
+const u8 ALIGN_AVX_DIRECTIVE p_mask_arr256[33][64] = {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
#if defined(HAVE_AVX512VBMI) // VBMI strong fat teddy
#define CONF_FAT_CHUNK_64(chunk, bucket, off, reason, pt, conf_fn) \
@@ -139,35 +139,35 @@ const m512 *getDupMaskBase(const struct Teddy *teddy, u8 numMask) {
#else
-#define CONF_FAT_CHUNK_64(chunk, bucket, off, reason, conf_fn) \
-do { \
- if (unlikely(chunk != ones_u64a)) { \
- chunk = ~chunk; \
- conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
- &control, &last_match); \
- CHECK_HWLM_TERMINATE_MATCHING; \
- } \
-} while(0)
-
-#define CONF_FAT_CHUNK_32(chunk, bucket, off, reason, conf_fn) \
-do { \
- if (unlikely(chunk != ones_u32)) { \
- chunk = ~chunk; \
- conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
- &control, &last_match); \
- CHECK_HWLM_TERMINATE_MATCHING; \
- } \
-} while(0)
-
-static really_inline
-const m256 *getMaskBase_fat(const struct Teddy *teddy) {
- return (const m256 *)((const u8 *)teddy + ROUNDUP_CL(sizeof(struct Teddy)));
-}
-
+#define CONF_FAT_CHUNK_64(chunk, bucket, off, reason, conf_fn) \
+do { \
+ if (unlikely(chunk != ones_u64a)) { \
+ chunk = ~chunk; \
+ conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
+ &control, &last_match); \
+ CHECK_HWLM_TERMINATE_MATCHING; \
+ } \
+} while(0)
+
+#define CONF_FAT_CHUNK_32(chunk, bucket, off, reason, conf_fn) \
+do { \
+ if (unlikely(chunk != ones_u32)) { \
+ chunk = ~chunk; \
+ conf_fn(&chunk, bucket, off, confBase, reason, a, ptr, \
+ &control, &last_match); \
+ CHECK_HWLM_TERMINATE_MATCHING; \
+ } \
+} while(0)
+
+static really_inline
+const m256 *getMaskBase_fat(const struct Teddy *teddy) {
+ return (const m256 *)((const u8 *)teddy + ROUNDUP_CL(sizeof(struct Teddy)));
+}
+
#endif
-
+
#if defined(HAVE_AVX512VBMI) // VBMI strong fat teddy
-
+
const u8 ALIGN_AVX_DIRECTIVE p_mask_interleave[64] = {
0, 32, 1, 33, 2, 34, 3, 35, 4, 36, 5, 37, 6, 38, 7, 39,
8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47,
@@ -175,18 +175,18 @@ const u8 ALIGN_AVX_DIRECTIVE p_mask_interleave[64] = {
24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63
};
-#ifdef ARCH_64_BIT
+#ifdef ARCH_64_BIT
#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, pt, conf_fn) \
-do { \
- if (unlikely(diff512(var, ones512()))) { \
+do { \
+ if (unlikely(diff512(var, ones512()))) { \
m512 msk_interleave = load512(p_mask_interleave); \
m512 r = vpermb512(msk_interleave, var); \
- m128 r0 = extract128from512(r, 0); \
- m128 r1 = extract128from512(r, 1); \
+ m128 r0 = extract128from512(r, 0); \
+ m128 r1 = extract128from512(r, 1); \
m128 r2 = extract128from512(r, 2); \
m128 r3 = extract128from512(r, 3); \
- u64a part1 = movq(r0); \
- u64a part2 = extract64from128(r0, 1); \
+ u64a part1 = movq(r0); \
+ u64a part2 = extract64from128(r0, 1); \
u64a part3 = movq(r1); \
u64a part4 = extract64from128(r1, 1); \
u64a part5 = movq(r2); \
@@ -201,22 +201,22 @@ do { \
CONF_FAT_CHUNK_64(part6, bucket, offset + 20, reason, pt, conf_fn); \
CONF_FAT_CHUNK_64(part7, bucket, offset + 24, reason, pt, conf_fn); \
CONF_FAT_CHUNK_64(part8, bucket, offset + 28, reason, pt, conf_fn); \
- } \
-} while(0)
-#else
+ } \
+} while(0)
+#else
#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, pt, conf_fn) \
-do { \
- if (unlikely(diff512(var, ones512()))) { \
+do { \
+ if (unlikely(diff512(var, ones512()))) { \
m512 msk_interleave = load512(p_mask_interleave); \
m512 r = vpermb512(msk_interleave, var); \
- m128 r0 = extract128from512(r, 0); \
- m128 r1 = extract128from512(r, 1); \
+ m128 r0 = extract128from512(r, 0); \
+ m128 r1 = extract128from512(r, 1); \
m128 r2 = extract128from512(r, 2); \
m128 r3 = extract128from512(r, 3); \
- u32 part1 = movd(r0); \
- u32 part2 = extract32from128(r0, 1); \
- u32 part3 = extract32from128(r0, 2); \
- u32 part4 = extract32from128(r0, 3); \
+ u32 part1 = movd(r0); \
+ u32 part2 = extract32from128(r0, 1); \
+ u32 part3 = extract32from128(r0, 2); \
+ u32 part4 = extract32from128(r0, 3); \
u32 part5 = movd(r1); \
u32 part6 = extract32from128(r1, 1); \
u32 part7 = extract32from128(r1, 2); \
@@ -245,51 +245,51 @@ do { \
CONF_FAT_CHUNK_32(part14, bucket, offset + 26, reason, pt, conf_fn);\
CONF_FAT_CHUNK_32(part15, bucket, offset + 28, reason, pt, conf_fn);\
CONF_FAT_CHUNK_32(part16, bucket, offset + 30, reason, pt, conf_fn);\
- } \
-} while(0)
-#endif
-
+ } \
+} while(0)
+#endif
+
#define PREP_FAT_SHUF_MASK \
- m512 lo = and512(val, *lo_mask); \
- m512 hi = and512(rshift64_m512(val, 4), *lo_mask)
-
+ m512 lo = and512(val, *lo_mask); \
+ m512 hi = and512(rshift64_m512(val, 4), *lo_mask)
+
#define FAT_TEDDY_VBMI_PSHUFB_OR_M1 \
m512 shuf_or_b0 = or512(pshufb_m512(dup_mask[0], lo), \
pshufb_m512(dup_mask[1], hi));
-
+
#define FAT_TEDDY_VBMI_PSHUFB_OR_M2 \
FAT_TEDDY_VBMI_PSHUFB_OR_M1 \
m512 shuf_or_b1 = or512(pshufb_m512(dup_mask[2], lo), \
pshufb_m512(dup_mask[3], hi));
-
+
#define FAT_TEDDY_VBMI_PSHUFB_OR_M3 \
FAT_TEDDY_VBMI_PSHUFB_OR_M2 \
m512 shuf_or_b2 = or512(pshufb_m512(dup_mask[4], lo), \
pshufb_m512(dup_mask[5], hi));
-
+
#define FAT_TEDDY_VBMI_PSHUFB_OR_M4 \
FAT_TEDDY_VBMI_PSHUFB_OR_M3 \
m512 shuf_or_b3 = or512(pshufb_m512(dup_mask[6], lo), \
pshufb_m512(dup_mask[7], hi));
-
+
#define FAT_TEDDY_VBMI_SL1_MASK 0xfffffffefffffffeULL
#define FAT_TEDDY_VBMI_SL2_MASK 0xfffffffcfffffffcULL
#define FAT_TEDDY_VBMI_SL3_MASK 0xfffffff8fffffff8ULL
-
+
#define FAT_TEDDY_VBMI_SHIFT_M1
-
+
#define FAT_TEDDY_VBMI_SHIFT_M2 \
FAT_TEDDY_VBMI_SHIFT_M1 \
m512 sl1 = maskz_vpermb512(FAT_TEDDY_VBMI_SL1_MASK, sl_msk[0], shuf_or_b1);
-
+
#define FAT_TEDDY_VBMI_SHIFT_M3 \
FAT_TEDDY_VBMI_SHIFT_M2 \
m512 sl2 = maskz_vpermb512(FAT_TEDDY_VBMI_SL2_MASK, sl_msk[1], shuf_or_b2);
-
+
#define FAT_TEDDY_VBMI_SHIFT_M4 \
FAT_TEDDY_VBMI_SHIFT_M3 \
m512 sl3 = maskz_vpermb512(FAT_TEDDY_VBMI_SL3_MASK, sl_msk[2], shuf_or_b3);
-
+
#define FAT_SHIFT_OR_M1 \
shuf_or_b0
@@ -302,49 +302,49 @@ do { \
#define FAT_SHIFT_OR_M4 \
or512(sl3, FAT_SHIFT_OR_M3)
-static really_inline
-m512 prep_conf_fat_teddy_m1(const m512 *lo_mask, const m512 *dup_mask,
+static really_inline
+m512 prep_conf_fat_teddy_m1(const m512 *lo_mask, const m512 *dup_mask,
UNUSED const m512 *sl_msk, const m512 val) {
- PREP_FAT_SHUF_MASK;
+ PREP_FAT_SHUF_MASK;
FAT_TEDDY_VBMI_PSHUFB_OR_M1;
FAT_TEDDY_VBMI_SHIFT_M1;
return FAT_SHIFT_OR_M1;
-}
-
-static really_inline
-m512 prep_conf_fat_teddy_m2(const m512 *lo_mask, const m512 *dup_mask,
+}
+
+static really_inline
+m512 prep_conf_fat_teddy_m2(const m512 *lo_mask, const m512 *dup_mask,
const m512 *sl_msk, const m512 val) {
- PREP_FAT_SHUF_MASK;
+ PREP_FAT_SHUF_MASK;
FAT_TEDDY_VBMI_PSHUFB_OR_M2;
FAT_TEDDY_VBMI_SHIFT_M2;
return FAT_SHIFT_OR_M2;
-}
-
-static really_inline
-m512 prep_conf_fat_teddy_m3(const m512 *lo_mask, const m512 *dup_mask,
+}
+
+static really_inline
+m512 prep_conf_fat_teddy_m3(const m512 *lo_mask, const m512 *dup_mask,
const m512 *sl_msk, const m512 val) {
- PREP_FAT_SHUF_MASK;
+ PREP_FAT_SHUF_MASK;
FAT_TEDDY_VBMI_PSHUFB_OR_M3;
FAT_TEDDY_VBMI_SHIFT_M3;
return FAT_SHIFT_OR_M3;
-}
-
-static really_inline
-m512 prep_conf_fat_teddy_m4(const m512 *lo_mask, const m512 *dup_mask,
+}
+
+static really_inline
+m512 prep_conf_fat_teddy_m4(const m512 *lo_mask, const m512 *dup_mask,
const m512 *sl_msk, const m512 val) {
- PREP_FAT_SHUF_MASK;
+ PREP_FAT_SHUF_MASK;
FAT_TEDDY_VBMI_PSHUFB_OR_M4;
FAT_TEDDY_VBMI_SHIFT_M4;
return FAT_SHIFT_OR_M4;
-}
-
+}
+
#define PREP_CONF_FAT_FN(val, n) \
prep_conf_fat_teddy_m##n(&lo_mask, dup_mask, sl_msk, val)
-
+
#define FAT_TEDDY_VBMI_SL1_POS 15
#define FAT_TEDDY_VBMI_SL2_POS 14
#define FAT_TEDDY_VBMI_SL3_POS 13
-
+
#define FAT_TEDDY_VBMI_LOAD_SHIFT_MASK_M1
#define FAT_TEDDY_VBMI_LOAD_SHIFT_MASK_M2 \
@@ -359,57 +359,57 @@ m512 prep_conf_fat_teddy_m4(const m512 *lo_mask, const m512 *dup_mask,
FAT_TEDDY_VBMI_LOAD_SHIFT_MASK_M3 \
sl_msk[2] = loadu512(p_sh_mask_arr + FAT_TEDDY_VBMI_SL3_POS);
-/*
- * In FAT teddy, it needs 2 bytes to represent result of each position,
- * so each nibble's(for example, lo nibble of last byte) FAT teddy mask
- * has 16x2 bytes:
- * |----------------------------------|----------------------------------|
- * 16bytes (bucket 0..7 in each byte) 16bytes (bucket 8..15 in each byte)
- * A B
- * at runtime FAT teddy reads 16 bytes once and duplicate them to 32 bytes:
- * |----------------------------------|----------------------------------|
- * 16bytes input data (lo nibbles) 16bytes duplicated data (lo nibbles)
- * X X
- * then do pshufb_m256(AB, XX).
- *
- * In AVX512 reinforced FAT teddy, it reads 32 bytes once and duplicate them
- * to 64 bytes:
- * |----------------|----------------|----------------|----------------|
- * X Y X Y
- * in this case we need DUP_FAT_MASK to construct AABB:
- * |----------------|----------------|----------------|----------------|
- * A A B B
- * then do pshufb_m512(AABB, XYXY).
- */
-
-#define PREPARE_FAT_MASKS(n) \
- m512 lo_mask = set64x8(0xf); \
+/*
+ * In FAT teddy, it needs 2 bytes to represent result of each position,
+ * so each nibble's(for example, lo nibble of last byte) FAT teddy mask
+ * has 16x2 bytes:
+ * |----------------------------------|----------------------------------|
+ * 16bytes (bucket 0..7 in each byte) 16bytes (bucket 8..15 in each byte)
+ * A B
+ * at runtime FAT teddy reads 16 bytes once and duplicate them to 32 bytes:
+ * |----------------------------------|----------------------------------|
+ * 16bytes input data (lo nibbles) 16bytes duplicated data (lo nibbles)
+ * X X
+ * then do pshufb_m256(AB, XX).
+ *
+ * In AVX512 reinforced FAT teddy, it reads 32 bytes once and duplicate them
+ * to 64 bytes:
+ * |----------------|----------------|----------------|----------------|
+ * X Y X Y
+ * in this case we need DUP_FAT_MASK to construct AABB:
+ * |----------------|----------------|----------------|----------------|
+ * A A B B
+ * then do pshufb_m512(AABB, XYXY).
+ */
+
+#define PREPARE_FAT_MASKS(n) \
+ m512 lo_mask = set64x8(0xf); \
m512 sl_msk[n - 1]; \
FAT_TEDDY_VBMI_LOAD_SHIFT_MASK_M##n
-
+
#define FAT_TEDDY_VBMI_CONF_MASK_HEAD (0xffffffffULL >> n_sh)
#define FAT_TEDDY_VBMI_CONF_MASK_FULL ((0xffffffffULL << n_sh) & 0xffffffffULL)
#define FAT_TEDDY_VBMI_CONF_MASK_VAR(n) (0xffffffffULL >> (32 - n) << overlap)
#define FAT_TEDDY_VBMI_LOAD_MASK_PATCH (0xffffffffULL >> (32 - n_sh))
-#define FDR_EXEC_FAT_TEDDY(fdr, a, control, n_msk, conf_fn) \
-do { \
- const u8 *buf_end = a->buf + a->len; \
- const u8 *ptr = a->buf + a->start_offset; \
- u32 floodBackoff = FLOOD_BACKOFF_START; \
- const u8 *tryFloodDetect = a->firstFloodDetect; \
- u32 last_match = ones_u32; \
- const struct Teddy *teddy = (const struct Teddy *)fdr; \
+#define FDR_EXEC_FAT_TEDDY(fdr, a, control, n_msk, conf_fn) \
+do { \
+ const u8 *buf_end = a->buf + a->len; \
+ const u8 *ptr = a->buf + a->start_offset; \
+ u32 floodBackoff = FLOOD_BACKOFF_START; \
+ const u8 *tryFloodDetect = a->firstFloodDetect; \
+ u32 last_match = ones_u32; \
+ const struct Teddy *teddy = (const struct Teddy *)fdr; \
const size_t iterBytes = 32; \
u32 n_sh = n_msk - 1; \
const size_t loopBytes = 32 - n_sh; \
- DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
- a->buf, a->len, a->start_offset); \
- \
+ DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
+ a->buf, a->len, a->start_offset); \
+ \
const m512 *dup_mask = getDupMaskBase(teddy, n_msk); \
- PREPARE_FAT_MASKS(n_msk); \
- const u32 *confBase = getConfBase(teddy); \
- \
+ PREPARE_FAT_MASKS(n_msk); \
+ const u32 *confBase = getConfBase(teddy); \
+ \
u64a k = FAT_TEDDY_VBMI_CONF_MASK_FULL; \
m512 p_mask = set_mask_m512(~((k << 32) | k)); \
u32 overlap = 0; \
@@ -423,17 +423,17 @@ do { \
ptr += loopBytes; \
overlap = n_sh; \
patch = FAT_TEDDY_VBMI_LOAD_MASK_PATCH; \
- } \
- \
+ } \
+ \
for (; ptr + loopBytes <= buf_end; ptr += loopBytes) { \
- CHECK_FLOOD; \
+ CHECK_FLOOD; \
m512 r_0 = PREP_CONF_FAT_FN(set2x256(loadu256(ptr - n_sh)), n_msk); \
r_0 = or512(r_0, p_mask); \
CONFIRM_FAT_TEDDY(r_0, 16, 0, NOT_CAUTIOUS, ptr - n_sh, conf_fn); \
- } \
- \
+ } \
+ \
assert(ptr + loopBytes > buf_end); \
- if (ptr < buf_end) { \
+ if (ptr < buf_end) { \
u32 left = (u32)(buf_end - ptr); \
u64a k1 = FAT_TEDDY_VBMI_CONF_MASK_VAR(left); \
m512 p_mask1 = set_mask_m512(~((k1 << 32) | k1)); \
@@ -441,269 +441,269 @@ do { \
m512 r_0 = PREP_CONF_FAT_FN(val_0, n_msk); \
r_0 = or512(r_0, p_mask1); \
CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, ptr - overlap, conf_fn); \
- } \
- \
- return HWLM_SUCCESS; \
-} while(0)
-
+ } \
+ \
+ return HWLM_SUCCESS; \
+} while(0)
+
#else // !HAVE_AVX512VBMI, AVX2 normal fat teddy
-
-#ifdef ARCH_64_BIT
-#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff256(var, ones256()))) { \
- m256 swap = swap128in256(var); \
- m256 r = interleave256lo(var, swap); \
- u64a part1 = extractlow64from256(r); \
- u64a part2 = extract64from256(r, 1); \
- r = interleave256hi(var, swap); \
- u64a part3 = extractlow64from256(r); \
- u64a part4 = extract64from256(r, 1); \
- CONF_FAT_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
- CONF_FAT_CHUNK_64(part2, bucket, offset + 4, reason, conf_fn); \
- CONF_FAT_CHUNK_64(part3, bucket, offset + 8, reason, conf_fn); \
- CONF_FAT_CHUNK_64(part4, bucket, offset + 12, reason, conf_fn); \
- } \
-} while(0)
-#else
-#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, conf_fn) \
-do { \
- if (unlikely(diff256(var, ones256()))) { \
- m256 swap = swap128in256(var); \
- m256 r = interleave256lo(var, swap); \
- u32 part1 = extractlow32from256(r); \
- u32 part2 = extract32from256(r, 1); \
- u32 part3 = extract32from256(r, 2); \
- u32 part4 = extract32from256(r, 3); \
- r = interleave256hi(var, swap); \
- u32 part5 = extractlow32from256(r); \
- u32 part6 = extract32from256(r, 1); \
- u32 part7 = extract32from256(r, 2); \
- u32 part8 = extract32from256(r, 3); \
- CONF_FAT_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part2, bucket, offset + 2, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part3, bucket, offset + 4, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part4, bucket, offset + 6, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part5, bucket, offset + 8, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part6, bucket, offset + 10, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part7, bucket, offset + 12, reason, conf_fn); \
- CONF_FAT_CHUNK_32(part8, bucket, offset + 14, reason, conf_fn); \
- } \
-} while(0)
-#endif
-
-static really_inline
-m256 vectoredLoad2x128(m256 *p_mask, const u8 *ptr, const size_t start_offset,
- const u8 *lo, const u8 *hi,
- const u8 *buf_history, size_t len_history,
- const u32 nMasks) {
- m128 p_mask128;
- m256 ret = set2x128(vectoredLoad128(&p_mask128, ptr, start_offset, lo, hi,
- buf_history, len_history, nMasks));
- *p_mask = set2x128(p_mask128);
- return ret;
-}
-
-static really_inline
-m256 prep_conf_fat_teddy_m1(const m256 *maskBase, m256 val) {
- m256 mask = set32x8(0xf);
- m256 lo = and256(val, mask);
- m256 hi = and256(rshift64_m256(val, 4), mask);
- return or256(pshufb_m256(maskBase[0 * 2], lo),
- pshufb_m256(maskBase[0 * 2 + 1], hi));
-}
-
-static really_inline
-m256 prep_conf_fat_teddy_m2(const m256 *maskBase, m256 *old_1, m256 val) {
- m256 mask = set32x8(0xf);
- m256 lo = and256(val, mask);
- m256 hi = and256(rshift64_m256(val, 4), mask);
- m256 r = prep_conf_fat_teddy_m1(maskBase, val);
-
- m256 res_1 = or256(pshufb_m256(maskBase[1 * 2], lo),
- pshufb_m256(maskBase[1 * 2 + 1], hi));
- m256 res_shifted_1 = vpalignr(res_1, *old_1, 16 - 1);
- *old_1 = res_1;
- return or256(r, res_shifted_1);
-}
-
-static really_inline
-m256 prep_conf_fat_teddy_m3(const m256 *maskBase, m256 *old_1, m256 *old_2,
- m256 val) {
- m256 mask = set32x8(0xf);
- m256 lo = and256(val, mask);
- m256 hi = and256(rshift64_m256(val, 4), mask);
- m256 r = prep_conf_fat_teddy_m2(maskBase, old_1, val);
-
- m256 res_2 = or256(pshufb_m256(maskBase[2 * 2], lo),
- pshufb_m256(maskBase[2 * 2 + 1], hi));
- m256 res_shifted_2 = vpalignr(res_2, *old_2, 16 - 2);
- *old_2 = res_2;
- return or256(r, res_shifted_2);
-}
-
-static really_inline
-m256 prep_conf_fat_teddy_m4(const m256 *maskBase, m256 *old_1, m256 *old_2,
- m256 *old_3, m256 val) {
- m256 mask = set32x8(0xf);
- m256 lo = and256(val, mask);
- m256 hi = and256(rshift64_m256(val, 4), mask);
- m256 r = prep_conf_fat_teddy_m3(maskBase, old_1, old_2, val);
-
- m256 res_3 = or256(pshufb_m256(maskBase[3 * 2], lo),
- pshufb_m256(maskBase[3 * 2 + 1], hi));
- m256 res_shifted_3 = vpalignr(res_3, *old_3, 16 - 3);
- *old_3 = res_3;
- return or256(r, res_shifted_3);
-}
-
-#define FDR_EXEC_FAT_TEDDY_RES_OLD_1 \
-do { \
-} while(0)
-
-#define FDR_EXEC_FAT_TEDDY_RES_OLD_2 \
- m256 res_old_1 = zeroes256();
-
-#define FDR_EXEC_FAT_TEDDY_RES_OLD_3 \
- m256 res_old_1 = zeroes256(); \
- m256 res_old_2 = zeroes256();
-
-#define FDR_EXEC_FAT_TEDDY_RES_OLD_4 \
- m256 res_old_1 = zeroes256(); \
- m256 res_old_2 = zeroes256(); \
- m256 res_old_3 = zeroes256();
-
-#define FDR_EXEC_FAT_TEDDY_RES_OLD(n) FDR_EXEC_FAT_TEDDY_RES_OLD_##n
-
-#define PREP_CONF_FAT_FN_1(mask_base, val) \
- prep_conf_fat_teddy_m1(mask_base, val)
-
-#define PREP_CONF_FAT_FN_2(mask_base, val) \
- prep_conf_fat_teddy_m2(mask_base, &res_old_1, val)
-
-#define PREP_CONF_FAT_FN_3(mask_base, val) \
- prep_conf_fat_teddy_m3(mask_base, &res_old_1, &res_old_2, val)
-
-#define PREP_CONF_FAT_FN_4(mask_base, val) \
- prep_conf_fat_teddy_m4(mask_base, &res_old_1, &res_old_2, &res_old_3, val)
-
-#define PREP_CONF_FAT_FN(mask_base, val, n) \
- PREP_CONF_FAT_FN_##n(mask_base, val)
-
-#define FDR_EXEC_FAT_TEDDY(fdr, a, control, n_msk, conf_fn) \
-do { \
- const u8 *buf_end = a->buf + a->len; \
- const u8 *ptr = a->buf + a->start_offset; \
- u32 floodBackoff = FLOOD_BACKOFF_START; \
- const u8 *tryFloodDetect = a->firstFloodDetect; \
- u32 last_match = ones_u32; \
- const struct Teddy *teddy = (const struct Teddy *)fdr; \
- const size_t iterBytes = 32; \
- DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
- a->buf, a->len, a->start_offset); \
- \
- const m256 *maskBase = getMaskBase_fat(teddy); \
- const u32 *confBase = getConfBase(teddy); \
- \
- FDR_EXEC_FAT_TEDDY_RES_OLD(n_msk); \
- const u8 *mainStart = ROUNDUP_PTR(ptr, 16); \
- DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
- if (ptr < mainStart) { \
- ptr = mainStart - 16; \
- m256 p_mask; \
- m256 val_0 = vectoredLoad2x128(&p_mask, ptr, a->start_offset, \
- a->buf, buf_end, \
- a->buf_history, a->len_history, \
- n_msk); \
- m256 r_0 = PREP_CONF_FAT_FN(maskBase, val_0, n_msk); \
- r_0 = or256(r_0, p_mask); \
- CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
- ptr += 16; \
- } \
- \
- if (ptr + 16 <= buf_end) { \
- m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
- CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
- ptr += 16; \
- } \
- \
- for ( ; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
- __builtin_prefetch(ptr + (iterBytes * 4)); \
- CHECK_FLOOD; \
- m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
- CONFIRM_FAT_TEDDY(r_0, 16, 0, NOT_CAUTIOUS, conf_fn); \
- m256 r_1 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr + 16), n_msk); \
- CONFIRM_FAT_TEDDY(r_1, 16, 16, NOT_CAUTIOUS, conf_fn); \
- } \
- \
- if (ptr + 16 <= buf_end) { \
- m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
- CONFIRM_FAT_TEDDY(r_0, 16, 0, NOT_CAUTIOUS, conf_fn); \
- ptr += 16; \
- } \
- \
- assert(ptr + 16 > buf_end); \
- if (ptr < buf_end) { \
- m256 p_mask; \
- m256 val_0 = vectoredLoad2x128(&p_mask, ptr, 0, ptr, buf_end, \
- a->buf_history, a->len_history, \
- n_msk); \
- m256 r_0 = PREP_CONF_FAT_FN(maskBase, val_0, n_msk); \
- r_0 = or256(r_0, p_mask); \
- CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
- } \
- \
- return HWLM_SUCCESS; \
-} while(0)
-
+
+#ifdef ARCH_64_BIT
+#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff256(var, ones256()))) { \
+ m256 swap = swap128in256(var); \
+ m256 r = interleave256lo(var, swap); \
+ u64a part1 = extractlow64from256(r); \
+ u64a part2 = extract64from256(r, 1); \
+ r = interleave256hi(var, swap); \
+ u64a part3 = extractlow64from256(r); \
+ u64a part4 = extract64from256(r, 1); \
+ CONF_FAT_CHUNK_64(part1, bucket, offset, reason, conf_fn); \
+ CONF_FAT_CHUNK_64(part2, bucket, offset + 4, reason, conf_fn); \
+ CONF_FAT_CHUNK_64(part3, bucket, offset + 8, reason, conf_fn); \
+ CONF_FAT_CHUNK_64(part4, bucket, offset + 12, reason, conf_fn); \
+ } \
+} while(0)
+#else
+#define CONFIRM_FAT_TEDDY(var, bucket, offset, reason, conf_fn) \
+do { \
+ if (unlikely(diff256(var, ones256()))) { \
+ m256 swap = swap128in256(var); \
+ m256 r = interleave256lo(var, swap); \
+ u32 part1 = extractlow32from256(r); \
+ u32 part2 = extract32from256(r, 1); \
+ u32 part3 = extract32from256(r, 2); \
+ u32 part4 = extract32from256(r, 3); \
+ r = interleave256hi(var, swap); \
+ u32 part5 = extractlow32from256(r); \
+ u32 part6 = extract32from256(r, 1); \
+ u32 part7 = extract32from256(r, 2); \
+ u32 part8 = extract32from256(r, 3); \
+ CONF_FAT_CHUNK_32(part1, bucket, offset, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part2, bucket, offset + 2, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part3, bucket, offset + 4, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part4, bucket, offset + 6, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part5, bucket, offset + 8, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part6, bucket, offset + 10, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part7, bucket, offset + 12, reason, conf_fn); \
+ CONF_FAT_CHUNK_32(part8, bucket, offset + 14, reason, conf_fn); \
+ } \
+} while(0)
+#endif
+
+static really_inline
+m256 vectoredLoad2x128(m256 *p_mask, const u8 *ptr, const size_t start_offset,
+ const u8 *lo, const u8 *hi,
+ const u8 *buf_history, size_t len_history,
+ const u32 nMasks) {
+ m128 p_mask128;
+ m256 ret = set2x128(vectoredLoad128(&p_mask128, ptr, start_offset, lo, hi,
+ buf_history, len_history, nMasks));
+ *p_mask = set2x128(p_mask128);
+ return ret;
+}
+
+static really_inline
+m256 prep_conf_fat_teddy_m1(const m256 *maskBase, m256 val) {
+ m256 mask = set32x8(0xf);
+ m256 lo = and256(val, mask);
+ m256 hi = and256(rshift64_m256(val, 4), mask);
+ return or256(pshufb_m256(maskBase[0 * 2], lo),
+ pshufb_m256(maskBase[0 * 2 + 1], hi));
+}
+
+static really_inline
+m256 prep_conf_fat_teddy_m2(const m256 *maskBase, m256 *old_1, m256 val) {
+ m256 mask = set32x8(0xf);
+ m256 lo = and256(val, mask);
+ m256 hi = and256(rshift64_m256(val, 4), mask);
+ m256 r = prep_conf_fat_teddy_m1(maskBase, val);
+
+ m256 res_1 = or256(pshufb_m256(maskBase[1 * 2], lo),
+ pshufb_m256(maskBase[1 * 2 + 1], hi));
+ m256 res_shifted_1 = vpalignr(res_1, *old_1, 16 - 1);
+ *old_1 = res_1;
+ return or256(r, res_shifted_1);
+}
+
+static really_inline
+m256 prep_conf_fat_teddy_m3(const m256 *maskBase, m256 *old_1, m256 *old_2,
+ m256 val) {
+ m256 mask = set32x8(0xf);
+ m256 lo = and256(val, mask);
+ m256 hi = and256(rshift64_m256(val, 4), mask);
+ m256 r = prep_conf_fat_teddy_m2(maskBase, old_1, val);
+
+ m256 res_2 = or256(pshufb_m256(maskBase[2 * 2], lo),
+ pshufb_m256(maskBase[2 * 2 + 1], hi));
+ m256 res_shifted_2 = vpalignr(res_2, *old_2, 16 - 2);
+ *old_2 = res_2;
+ return or256(r, res_shifted_2);
+}
+
+static really_inline
+m256 prep_conf_fat_teddy_m4(const m256 *maskBase, m256 *old_1, m256 *old_2,
+ m256 *old_3, m256 val) {
+ m256 mask = set32x8(0xf);
+ m256 lo = and256(val, mask);
+ m256 hi = and256(rshift64_m256(val, 4), mask);
+ m256 r = prep_conf_fat_teddy_m3(maskBase, old_1, old_2, val);
+
+ m256 res_3 = or256(pshufb_m256(maskBase[3 * 2], lo),
+ pshufb_m256(maskBase[3 * 2 + 1], hi));
+ m256 res_shifted_3 = vpalignr(res_3, *old_3, 16 - 3);
+ *old_3 = res_3;
+ return or256(r, res_shifted_3);
+}
+
+#define FDR_EXEC_FAT_TEDDY_RES_OLD_1 \
+do { \
+} while(0)
+
+#define FDR_EXEC_FAT_TEDDY_RES_OLD_2 \
+ m256 res_old_1 = zeroes256();
+
+#define FDR_EXEC_FAT_TEDDY_RES_OLD_3 \
+ m256 res_old_1 = zeroes256(); \
+ m256 res_old_2 = zeroes256();
+
+#define FDR_EXEC_FAT_TEDDY_RES_OLD_4 \
+ m256 res_old_1 = zeroes256(); \
+ m256 res_old_2 = zeroes256(); \
+ m256 res_old_3 = zeroes256();
+
+#define FDR_EXEC_FAT_TEDDY_RES_OLD(n) FDR_EXEC_FAT_TEDDY_RES_OLD_##n
+
+#define PREP_CONF_FAT_FN_1(mask_base, val) \
+ prep_conf_fat_teddy_m1(mask_base, val)
+
+#define PREP_CONF_FAT_FN_2(mask_base, val) \
+ prep_conf_fat_teddy_m2(mask_base, &res_old_1, val)
+
+#define PREP_CONF_FAT_FN_3(mask_base, val) \
+ prep_conf_fat_teddy_m3(mask_base, &res_old_1, &res_old_2, val)
+
+#define PREP_CONF_FAT_FN_4(mask_base, val) \
+ prep_conf_fat_teddy_m4(mask_base, &res_old_1, &res_old_2, &res_old_3, val)
+
+#define PREP_CONF_FAT_FN(mask_base, val, n) \
+ PREP_CONF_FAT_FN_##n(mask_base, val)
+
+#define FDR_EXEC_FAT_TEDDY(fdr, a, control, n_msk, conf_fn) \
+do { \
+ const u8 *buf_end = a->buf + a->len; \
+ const u8 *ptr = a->buf + a->start_offset; \
+ u32 floodBackoff = FLOOD_BACKOFF_START; \
+ const u8 *tryFloodDetect = a->firstFloodDetect; \
+ u32 last_match = ones_u32; \
+ const struct Teddy *teddy = (const struct Teddy *)fdr; \
+ const size_t iterBytes = 32; \
+ DEBUG_PRINTF("params: buf %p len %zu start_offset %zu\n", \
+ a->buf, a->len, a->start_offset); \
+ \
+ const m256 *maskBase = getMaskBase_fat(teddy); \
+ const u32 *confBase = getConfBase(teddy); \
+ \
+ FDR_EXEC_FAT_TEDDY_RES_OLD(n_msk); \
+ const u8 *mainStart = ROUNDUP_PTR(ptr, 16); \
+ DEBUG_PRINTF("derive: ptr: %p mainstart %p\n", ptr, mainStart); \
+ if (ptr < mainStart) { \
+ ptr = mainStart - 16; \
+ m256 p_mask; \
+ m256 val_0 = vectoredLoad2x128(&p_mask, ptr, a->start_offset, \
+ a->buf, buf_end, \
+ a->buf_history, a->len_history, \
+ n_msk); \
+ m256 r_0 = PREP_CONF_FAT_FN(maskBase, val_0, n_msk); \
+ r_0 = or256(r_0, p_mask); \
+ CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ if (ptr + 16 <= buf_end) { \
+ m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
+ CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ for ( ; ptr + iterBytes <= buf_end; ptr += iterBytes) { \
+ __builtin_prefetch(ptr + (iterBytes * 4)); \
+ CHECK_FLOOD; \
+ m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
+ CONFIRM_FAT_TEDDY(r_0, 16, 0, NOT_CAUTIOUS, conf_fn); \
+ m256 r_1 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr + 16), n_msk); \
+ CONFIRM_FAT_TEDDY(r_1, 16, 16, NOT_CAUTIOUS, conf_fn); \
+ } \
+ \
+ if (ptr + 16 <= buf_end) { \
+ m256 r_0 = PREP_CONF_FAT_FN(maskBase, load2x128(ptr), n_msk); \
+ CONFIRM_FAT_TEDDY(r_0, 16, 0, NOT_CAUTIOUS, conf_fn); \
+ ptr += 16; \
+ } \
+ \
+ assert(ptr + 16 > buf_end); \
+ if (ptr < buf_end) { \
+ m256 p_mask; \
+ m256 val_0 = vectoredLoad2x128(&p_mask, ptr, 0, ptr, buf_end, \
+ a->buf_history, a->len_history, \
+ n_msk); \
+ m256 r_0 = PREP_CONF_FAT_FN(maskBase, val_0, n_msk); \
+ r_0 = or256(r_0, p_mask); \
+ CONFIRM_FAT_TEDDY(r_0, 16, 0, VECTORING, conf_fn); \
+ } \
+ \
+ return HWLM_SUCCESS; \
+} while(0)
+
#endif // HAVE_AVX512VBMI
-
-hwlm_error_t fdr_exec_fat_teddy_msks1(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks1_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks2(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks2_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks3(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks3_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks4(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
-}
-
-hwlm_error_t fdr_exec_fat_teddy_msks4_pck(const struct FDR *fdr,
- const struct FDR_Runtime_Args *a,
- hwlm_group_t control) {
- FDR_EXEC_FAT_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
-}
-
-#endif // HAVE_AVX2
+
+hwlm_error_t fdr_exec_fat_teddy_msks1(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks1_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 1, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks2(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks2_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 2, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks3(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks3_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 3, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks4(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
+}
+
+hwlm_error_t fdr_exec_fat_teddy_msks4_pck(const struct FDR *fdr,
+ const struct FDR_Runtime_Args *a,
+ hwlm_group_t control) {
+ FDR_EXEC_FAT_TEDDY(fdr, a, control, 4, do_confWithBit_teddy);
+}
+
+#endif // HAVE_AVX2
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_compile.cpp b/contrib/libs/hyperscan/src/fdr/teddy_compile.cpp
index 103220aba01..eae9c2c136b 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_compile.cpp
+++ b/contrib/libs/hyperscan/src/fdr/teddy_compile.cpp
@@ -26,30 +26,30 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief FDR literal matcher: Teddy build code.
- */
-
-#include "teddy_compile.h"
-
+/**
+ * \file
+ * \brief FDR literal matcher: Teddy build code.
+ */
+
+#include "teddy_compile.h"
+
#include "fdr.h"
#include "fdr_internal.h"
#include "fdr_compile_internal.h"
#include "fdr_confirm.h"
#include "fdr_engine_description.h"
-#include "teddy_internal.h"
-#include "teddy_engine_description.h"
-#include "grey.h"
+#include "teddy_internal.h"
+#include "teddy_engine_description.h"
+#include "grey.h"
#include "ue2common.h"
-#include "hwlm/hwlm_build.h"
+#include "hwlm/hwlm_build.h"
#include "util/alloc.h"
#include "util/compare.h"
-#include "util/container.h"
-#include "util/make_unique.h"
-#include "util/noncopyable.h"
+#include "util/container.h"
+#include "util/make_unique.h"
+#include "util/noncopyable.h"
#include "util/popcount.h"
-#include "util/small_vector.h"
+#include "util/small_vector.h"
#include "util/target_info.h"
#include "util/verify_types.h"
@@ -73,58 +73,58 @@ namespace {
//#define TEDDY_DEBUG
-/** \brief Max number of Teddy masks we use. */
-static constexpr size_t MAX_NUM_MASKS = 4;
-
-class TeddyCompiler : noncopyable {
+/** \brief Max number of Teddy masks we use. */
+static constexpr size_t MAX_NUM_MASKS = 4;
+
+class TeddyCompiler : noncopyable {
const TeddyEngineDescription &eng;
- const Grey &grey;
+ const Grey &grey;
const vector<hwlmLiteral> &lits;
- map<BucketIndex, std::vector<LiteralIndex>> bucketToLits;
+ map<BucketIndex, std::vector<LiteralIndex>> bucketToLits;
bool make_small;
public:
TeddyCompiler(const vector<hwlmLiteral> &lits_in,
- map<BucketIndex, std::vector<LiteralIndex>> bucketToLits_in,
- const TeddyEngineDescription &eng_in, bool make_small_in,
- const Grey &grey_in)
- : eng(eng_in), grey(grey_in), lits(lits_in),
- bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
+ map<BucketIndex, std::vector<LiteralIndex>> bucketToLits_in,
+ const TeddyEngineDescription &eng_in, bool make_small_in,
+ const Grey &grey_in)
+ : eng(eng_in), grey(grey_in), lits(lits_in),
+ bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
- bytecode_ptr<FDR> build();
+ bytecode_ptr<FDR> build();
};
class TeddySet {
- /**
- * \brief Estimate of the max number of literals in a set, used to
- * minimise allocations.
- */
- static constexpr size_t LITS_PER_SET = 20;
-
- /** \brief Number of masks. */
+ /**
+ * \brief Estimate of the max number of literals in a set, used to
+ * minimise allocations.
+ */
+ static constexpr size_t LITS_PER_SET = 20;
+
+ /** \brief Number of masks. */
u32 len;
-
- /**
- * \brief A series of bitfields over 16 predicates that represent the
- * shufti nibble set.
- *
- * So for num_masks = 4 we will represent our strings by 8 u16s in the
- * vector that indicate what a shufti bucket would have to look like.
- */
- small_vector<u16, MAX_NUM_MASKS * 2> nibbleSets;
-
- /**
- * \brief Sorted, unique set of literals. We maintain our own set in a
- * sorted vector to minimise allocations.
- */
- small_vector<u32, LITS_PER_SET> litIds;
-
+
+ /**
+ * \brief A series of bitfields over 16 predicates that represent the
+ * shufti nibble set.
+ *
+ * So for num_masks = 4 we will represent our strings by 8 u16s in the
+ * vector that indicate what a shufti bucket would have to look like.
+ */
+ small_vector<u16, MAX_NUM_MASKS * 2> nibbleSets;
+
+ /**
+ * \brief Sorted, unique set of literals. We maintain our own set in a
+ * sorted vector to minimise allocations.
+ */
+ small_vector<u32, LITS_PER_SET> litIds;
+
public:
- explicit TeddySet(u32 len_in) : len(len_in), nibbleSets(len_in * 2, 0) {}
+ explicit TeddySet(u32 len_in) : len(len_in), nibbleSets(len_in * 2, 0) {}
size_t litCount() const { return litIds.size(); }
- const small_vector<u32, LITS_PER_SET> &getLits() const { return litIds; }
+ const small_vector<u32, LITS_PER_SET> &getLits() const { return litIds; }
- bool operator<(const TeddySet &s) const {
+ bool operator<(const TeddySet &s) const {
return litIds < s.litIds;
}
@@ -136,38 +136,38 @@ public:
}
printf("\nnlits: %zu\nLit ids: ", litCount());
printf("Prob: %llu\n", probability());
- for (const auto &id : litIds) {
- printf("%u ", id);
+ for (const auto &id : litIds) {
+ printf("%u ", id);
}
printf("\n");
- printf("Flood prone : %s\n", isRunProne() ? "yes" : "no");
+ printf("Flood prone : %s\n", isRunProne() ? "yes" : "no");
}
#endif
- bool identicalTail(const TeddySet &ts) const {
+ bool identicalTail(const TeddySet &ts) const {
return nibbleSets == ts.nibbleSets;
}
- void addLiteral(u32 lit_id, const hwlmLiteral &lit) {
- const string &s = lit.s;
+ void addLiteral(u32 lit_id, const hwlmLiteral &lit) {
+ const string &s = lit.s;
for (u32 i = 0; i < len; i++) {
if (i < s.size()) {
u8 c = s[s.size() - i - 1];
u8 c_hi = (c >> 4) & 0xf;
u8 c_lo = c & 0xf;
- nibbleSets[i * 2] = 1 << c_lo;
- if (lit.nocase && ourisalpha(c)) {
- nibbleSets[i * 2 + 1] =
- (1 << (c_hi & 0xd)) | (1 << (c_hi | 0x2));
+ nibbleSets[i * 2] = 1 << c_lo;
+ if (lit.nocase && ourisalpha(c)) {
+ nibbleSets[i * 2 + 1] =
+ (1 << (c_hi & 0xd)) | (1 << (c_hi | 0x2));
} else {
- nibbleSets[i * 2 + 1] = 1 << c_hi;
+ nibbleSets[i * 2 + 1] = 1 << c_hi;
}
} else {
- nibbleSets[i * 2] = nibbleSets[i * 2 + 1] = 0xffff;
+ nibbleSets[i * 2] = nibbleSets[i * 2 + 1] = 0xffff;
}
}
- litIds.push_back(lit_id);
- sort_and_unique(litIds);
+ litIds.push_back(lit_id);
+ sort_and_unique(litIds);
}
// return a value p from 0 .. MAXINT64 that gives p/MAXINT64
@@ -186,15 +186,15 @@ public:
// a small fixed cost + the cost of traversing some sort of followup
// (assumption is that the followup is linear)
u64a heuristic() const {
- return probability() * (2 + litCount());
+ return probability() * (2 + litCount());
}
bool isRunProne() const {
u16 lo_and = 0xffff;
u16 hi_and = 0xffff;
for (u32 i = 0; i < len; i++) {
- lo_and &= nibbleSets[i * 2];
- hi_and &= nibbleSets[i * 2 + 1];
+ lo_and &= nibbleSets[i * 2];
+ hi_and &= nibbleSets[i * 2 + 1];
}
// we're not flood-prone if there's no way to get
// through with a flood
@@ -203,51 +203,51 @@ public:
}
return true;
}
-
- friend TeddySet merge(const TeddySet &a, const TeddySet &b) {
- assert(a.nibbleSets.size() == b.nibbleSets.size());
-
- TeddySet m(a);
-
- for (size_t i = 0; i < m.nibbleSets.size(); i++) {
- m.nibbleSets[i] |= b.nibbleSets[i];
- }
-
- m.litIds.insert(m.litIds.end(), b.litIds.begin(), b.litIds.end());
- sort_and_unique(m.litIds);
-
- return m;
- }
+
+ friend TeddySet merge(const TeddySet &a, const TeddySet &b) {
+ assert(a.nibbleSets.size() == b.nibbleSets.size());
+
+ TeddySet m(a);
+
+ for (size_t i = 0; i < m.nibbleSets.size(); i++) {
+ m.nibbleSets[i] |= b.nibbleSets[i];
+ }
+
+ m.litIds.insert(m.litIds.end(), b.litIds.begin(), b.litIds.end());
+ sort_and_unique(m.litIds);
+
+ return m;
+ }
};
-static
-bool pack(const vector<hwlmLiteral> &lits,
- const TeddyEngineDescription &eng,
- map<BucketIndex, std::vector<LiteralIndex>> &bucketToLits) {
+static
+bool pack(const vector<hwlmLiteral> &lits,
+ const TeddyEngineDescription &eng,
+ map<BucketIndex, std::vector<LiteralIndex>> &bucketToLits) {
set<TeddySet> sts;
for (u32 i = 0; i < lits.size(); i++) {
- TeddySet ts(eng.numMasks);
- ts.addLiteral(i, lits[i]);
+ TeddySet ts(eng.numMasks);
+ ts.addLiteral(i, lits[i]);
sts.insert(ts);
}
while (1) {
#ifdef TEDDY_DEBUG
printf("Size %zu\n", sts.size());
- for (const TeddySet &ts : sts) {
- printf("\n");
- ts.dump();
+ for (const TeddySet &ts : sts) {
+ printf("\n");
+ ts.dump();
}
printf("\n===============================================\n");
#endif
- auto m1 = sts.end(), m2 = sts.end();
+ auto m1 = sts.end(), m2 = sts.end();
u64a best = 0xffffffffffffffffULL;
- for (auto i1 = sts.begin(), e1 = sts.end(); i1 != e1; ++i1) {
+ for (auto i1 = sts.begin(), e1 = sts.end(); i1 != e1; ++i1) {
const TeddySet &s1 = *i1;
- for (auto i2 = next(i1), e2 = sts.end(); i2 != e2; ++i2) {
+ for (auto i2 = next(i1), e2 = sts.end(); i2 != e2; ++i2) {
const TeddySet &s2 = *i2;
// be more conservative if we don't absolutely need to
@@ -257,7 +257,7 @@ bool pack(const vector<hwlmLiteral> &lits,
continue;
}
- TeddySet tmpSet = merge(s1, s2);
+ TeddySet tmpSet = merge(s1, s2);
u64a newScore = tmpSet.heuristic();
u64a oldScore = s1.heuristic() + s2.heuristic();
if (newScore < oldScore) {
@@ -285,7 +285,7 @@ bool pack(const vector<hwlmLiteral> &lits,
}
// do the merge
- TeddySet nts = merge(*m1, *m2);
+ TeddySet nts = merge(*m1, *m2);
#ifdef TEDDY_DEBUG
printf("Merging\n");
printf("m1 = \n");
@@ -305,55 +305,55 @@ bool pack(const vector<hwlmLiteral> &lits,
return false;
}
- u32 bucket_id = 0;
- for (const TeddySet &ts : sts) {
- const auto &ts_lits = ts.getLits();
- auto &bucket_lits = bucketToLits[bucket_id];
- bucket_lits.insert(end(bucket_lits), begin(ts_lits), end(ts_lits));
- bucket_id++;
+ u32 bucket_id = 0;
+ for (const TeddySet &ts : sts) {
+ const auto &ts_lits = ts.getLits();
+ auto &bucket_lits = bucketToLits[bucket_id];
+ bucket_lits.insert(end(bucket_lits), begin(ts_lits), end(ts_lits));
+ bucket_id++;
}
return true;
}
-// this entry has all-zero mask to skip reinforcement
-#define NO_REINFORCEMENT N_CHARS
-
-// this means every entry in reinforcement table
-#define ALL_CHAR_SET N_CHARS
-
-// each item's reinforcement mask has REINFORCED_MSK_LEN bytes
-#define REINFORCED_MSK_LEN 8
-
-// reinforcement table size for each 8 buckets set
-#define RTABLE_SIZE ((N_CHARS + 1) * REINFORCED_MSK_LEN)
-
-static
-void initReinforcedTable(u8 *rmsk) {
- u64a *mask = (u64a *)rmsk;
- fill_n(mask, N_CHARS, 0x00ffffffffffffffULL);
-}
-
-static
-void fillReinforcedMskZero(u8 *rmsk) {
- u8 *mc = rmsk + NO_REINFORCEMENT * REINFORCED_MSK_LEN;
- fill_n(mc, REINFORCED_MSK_LEN, 0x00);
-}
-
-static
-void fillReinforcedMsk(u8 *rmsk, u16 c, u32 j, u8 bmsk) {
- assert(j > 0);
- if (c == ALL_CHAR_SET) {
- for (size_t i = 0; i < N_CHARS; i++) {
- u8 *mc = rmsk + i * REINFORCED_MSK_LEN;
- mc[j - 1] &= ~bmsk;
- }
+// this entry has all-zero mask to skip reinforcement
+#define NO_REINFORCEMENT N_CHARS
+
+// this means every entry in reinforcement table
+#define ALL_CHAR_SET N_CHARS
+
+// each item's reinforcement mask has REINFORCED_MSK_LEN bytes
+#define REINFORCED_MSK_LEN 8
+
+// reinforcement table size for each 8 buckets set
+#define RTABLE_SIZE ((N_CHARS + 1) * REINFORCED_MSK_LEN)
+
+static
+void initReinforcedTable(u8 *rmsk) {
+ u64a *mask = (u64a *)rmsk;
+ fill_n(mask, N_CHARS, 0x00ffffffffffffffULL);
+}
+
+static
+void fillReinforcedMskZero(u8 *rmsk) {
+ u8 *mc = rmsk + NO_REINFORCEMENT * REINFORCED_MSK_LEN;
+ fill_n(mc, REINFORCED_MSK_LEN, 0x00);
+}
+
+static
+void fillReinforcedMsk(u8 *rmsk, u16 c, u32 j, u8 bmsk) {
+ assert(j > 0);
+ if (c == ALL_CHAR_SET) {
+ for (size_t i = 0; i < N_CHARS; i++) {
+ u8 *mc = rmsk + i * REINFORCED_MSK_LEN;
+ mc[j - 1] &= ~bmsk;
+ }
} else {
- u8 *mc = rmsk + c * REINFORCED_MSK_LEN;
- mc[j - 1] &= ~bmsk;
+ u8 *mc = rmsk + c * REINFORCED_MSK_LEN;
+ mc[j - 1] &= ~bmsk;
}
-}
+}
-static
+static
void fillDupNibbleMasks(const map<BucketIndex,
vector<LiteralIndex>> &bucketToLits,
const vector<hwlmLiteral> &lits,
@@ -437,36 +437,36 @@ void fillDupNibbleMasks(const map<BucketIndex,
}
static
-void fillNibbleMasks(const map<BucketIndex,
- vector<LiteralIndex>> &bucketToLits,
- const vector<hwlmLiteral> &lits,
- u32 numMasks, u32 maskWidth, size_t maskLen,
- u8 *baseMsk) {
- memset(baseMsk, 0xff, maskLen);
-
- for (const auto &b2l : bucketToLits) {
- const u32 &bucket_id = b2l.first;
- const vector<LiteralIndex> &ids = b2l.second;
+void fillNibbleMasks(const map<BucketIndex,
+ vector<LiteralIndex>> &bucketToLits,
+ const vector<hwlmLiteral> &lits,
+ u32 numMasks, u32 maskWidth, size_t maskLen,
+ u8 *baseMsk) {
+ memset(baseMsk, 0xff, maskLen);
+
+ for (const auto &b2l : bucketToLits) {
+ const u32 &bucket_id = b2l.first;
+ const vector<LiteralIndex> &ids = b2l.second;
const u8 bmsk = 1U << (bucket_id % 8);
- for (const LiteralIndex &lit_id : ids) {
- const hwlmLiteral &l = lits[lit_id];
+ for (const LiteralIndex &lit_id : ids) {
+ const hwlmLiteral &l = lits[lit_id];
DEBUG_PRINTF("putting lit %u into bucket %u\n", lit_id, bucket_id);
const u32 sz = verify_u32(l.s.size());
// fill in masks
- for (u32 j = 0; j < numMasks; j++) {
- const u32 msk_id_lo = j * 2 * maskWidth + (bucket_id / 8);
- const u32 msk_id_hi = (j * 2 + 1) * maskWidth + (bucket_id / 8);
- const u32 lo_base = msk_id_lo * 16;
- const u32 hi_base = msk_id_hi * 16;
+ for (u32 j = 0; j < numMasks; j++) {
+ const u32 msk_id_lo = j * 2 * maskWidth + (bucket_id / 8);
+ const u32 msk_id_hi = (j * 2 + 1) * maskWidth + (bucket_id / 8);
+ const u32 lo_base = msk_id_lo * 16;
+ const u32 hi_base = msk_id_hi * 16;
// if we don't have a char at this position, fill in i
// locations in these masks with '1'
if (j >= sz) {
for (u32 n = 0; n < 16; n++) {
- baseMsk[lo_base + n] &= ~bmsk;
- baseMsk[hi_base + n] &= ~bmsk;
+ baseMsk[lo_base + n] &= ~bmsk;
+ baseMsk[hi_base + n] &= ~bmsk;
}
} else {
u8 c = l.s[sz - 1 - j];
@@ -485,126 +485,126 @@ void fillNibbleMasks(const map<BucketIndex,
for (u8 cm = 0; cm < 0x10; cm++) {
if ((cm & m_lo) == (cmp_lo & m_lo)) {
- baseMsk[lo_base + cm] &= ~bmsk;
+ baseMsk[lo_base + cm] &= ~bmsk;
}
if ((cm & m_hi) == (cmp_hi & m_hi)) {
- baseMsk[hi_base + cm] &= ~bmsk;
+ baseMsk[hi_base + cm] &= ~bmsk;
}
}
- } else {
+ } else {
if (l.nocase && ourisalpha(c)) {
u32 cmHalfClear = (0xdf >> hiShift) & 0xf;
- u32 cmHalfSet = (0x20 >> hiShift) & 0xf;
- baseMsk[hi_base + (n_hi & cmHalfClear)] &= ~bmsk;
- baseMsk[hi_base + (n_hi | cmHalfSet)] &= ~bmsk;
+ u32 cmHalfSet = (0x20 >> hiShift) & 0xf;
+ baseMsk[hi_base + (n_hi & cmHalfClear)] &= ~bmsk;
+ baseMsk[hi_base + (n_hi | cmHalfSet)] &= ~bmsk;
} else {
- baseMsk[hi_base + n_hi] &= ~bmsk;
+ baseMsk[hi_base + n_hi] &= ~bmsk;
}
- baseMsk[lo_base + n_lo] &= ~bmsk;
+ baseMsk[lo_base + n_lo] &= ~bmsk;
}
}
}
}
}
-}
-
-static
-void fillReinforcedTable(const map<BucketIndex,
- vector<LiteralIndex>> &bucketToLits,
- const vector<hwlmLiteral> &lits,
- u8 *rtable_base, const u32 num_tables) {
- vector<u8 *> tables;
- for (u32 i = 0; i < num_tables; i++) {
- tables.push_back(rtable_base + i * RTABLE_SIZE);
- }
-
- for (auto t : tables) {
- initReinforcedTable(t);
- }
-
- for (const auto &b2l : bucketToLits) {
- const u32 &bucket_id = b2l.first;
- const vector<LiteralIndex> &ids = b2l.second;
- u8 *rmsk = tables[bucket_id / 8];
- const u8 bmsk = 1U << (bucket_id % 8);
-
- for (const LiteralIndex &lit_id : ids) {
- const hwlmLiteral &l = lits[lit_id];
- DEBUG_PRINTF("putting lit %u into bucket %u\n", lit_id, bucket_id);
- const u32 sz = verify_u32(l.s.size());
-
- // fill in reinforced masks
- for (u32 j = 1; j < REINFORCED_MSK_LEN; j++) {
- if (sz - 1 < j) {
- fillReinforcedMsk(rmsk, ALL_CHAR_SET, j, bmsk);
- } else {
- u8 c = l.s[sz - 1 - j];
- if (l.nocase && ourisalpha(c)) {
- u8 c_up = c & 0xdf;
- fillReinforcedMsk(rmsk, c_up, j, bmsk);
- u8 c_lo = c | 0x20;
- fillReinforcedMsk(rmsk, c_lo, j, bmsk);
- } else {
- fillReinforcedMsk(rmsk, c, j, bmsk);
- }
- }
+}
+
+static
+void fillReinforcedTable(const map<BucketIndex,
+ vector<LiteralIndex>> &bucketToLits,
+ const vector<hwlmLiteral> &lits,
+ u8 *rtable_base, const u32 num_tables) {
+ vector<u8 *> tables;
+ for (u32 i = 0; i < num_tables; i++) {
+ tables.push_back(rtable_base + i * RTABLE_SIZE);
+ }
+
+ for (auto t : tables) {
+ initReinforcedTable(t);
+ }
+
+ for (const auto &b2l : bucketToLits) {
+ const u32 &bucket_id = b2l.first;
+ const vector<LiteralIndex> &ids = b2l.second;
+ u8 *rmsk = tables[bucket_id / 8];
+ const u8 bmsk = 1U << (bucket_id % 8);
+
+ for (const LiteralIndex &lit_id : ids) {
+ const hwlmLiteral &l = lits[lit_id];
+ DEBUG_PRINTF("putting lit %u into bucket %u\n", lit_id, bucket_id);
+ const u32 sz = verify_u32(l.s.size());
+
+ // fill in reinforced masks
+ for (u32 j = 1; j < REINFORCED_MSK_LEN; j++) {
+ if (sz - 1 < j) {
+ fillReinforcedMsk(rmsk, ALL_CHAR_SET, j, bmsk);
+ } else {
+ u8 c = l.s[sz - 1 - j];
+ if (l.nocase && ourisalpha(c)) {
+ u8 c_up = c & 0xdf;
+ fillReinforcedMsk(rmsk, c_up, j, bmsk);
+ u8 c_lo = c | 0x20;
+ fillReinforcedMsk(rmsk, c_lo, j, bmsk);
+ } else {
+ fillReinforcedMsk(rmsk, c, j, bmsk);
+ }
+ }
}
}
- }
-
- for (auto t : tables) {
- fillReinforcedMskZero(t);
- }
-}
-
-bytecode_ptr<FDR> TeddyCompiler::build() {
- u32 maskWidth = eng.getNumBuckets() / 8;
-
- size_t headerSize = sizeof(Teddy);
- size_t maskLen = eng.numMasks * 16 * 2 * maskWidth;
+ }
+
+ for (auto t : tables) {
+ fillReinforcedMskZero(t);
+ }
+}
+
+bytecode_ptr<FDR> TeddyCompiler::build() {
+ u32 maskWidth = eng.getNumBuckets() / 8;
+
+ size_t headerSize = sizeof(Teddy);
+ size_t maskLen = eng.numMasks * 16 * 2 * maskWidth;
size_t reinforcedDupMaskLen = RTABLE_SIZE * maskWidth;
if (maskWidth == 2) { // dup nibble mask table in Fat Teddy
reinforcedDupMaskLen = maskLen * 2;
}
-
- auto floodTable = setupFDRFloodControl(lits, eng, grey);
- auto confirmTable = setupFullConfs(lits, eng, bucketToLits, make_small);
-
- // Note: we place each major structure here on a cacheline boundary.
- size_t size = ROUNDUP_CL(headerSize) + ROUNDUP_CL(maskLen) +
+
+ auto floodTable = setupFDRFloodControl(lits, eng, grey);
+ auto confirmTable = setupFullConfs(lits, eng, bucketToLits, make_small);
+
+ // Note: we place each major structure here on a cacheline boundary.
+ size_t size = ROUNDUP_CL(headerSize) + ROUNDUP_CL(maskLen) +
ROUNDUP_CL(reinforcedDupMaskLen) +
- ROUNDUP_CL(confirmTable.size()) + floodTable.size();
-
- auto fdr = make_zeroed_bytecode_ptr<FDR>(size, 64);
- assert(fdr); // otherwise would have thrown std::bad_alloc
- Teddy *teddy = (Teddy *)fdr.get(); // ugly
- u8 *teddy_base = (u8 *)teddy;
-
- // Write header.
- teddy->size = size;
- teddy->engineID = eng.getID();
- teddy->maxStringLen = verify_u32(maxLen(lits));
- teddy->numStrings = verify_u32(lits.size());
-
- // Write confirm structures.
- u8 *ptr = teddy_base + ROUNDUP_CL(headerSize) + ROUNDUP_CL(maskLen) +
+ ROUNDUP_CL(confirmTable.size()) + floodTable.size();
+
+ auto fdr = make_zeroed_bytecode_ptr<FDR>(size, 64);
+ assert(fdr); // otherwise would have thrown std::bad_alloc
+ Teddy *teddy = (Teddy *)fdr.get(); // ugly
+ u8 *teddy_base = (u8 *)teddy;
+
+ // Write header.
+ teddy->size = size;
+ teddy->engineID = eng.getID();
+ teddy->maxStringLen = verify_u32(maxLen(lits));
+ teddy->numStrings = verify_u32(lits.size());
+
+ // Write confirm structures.
+ u8 *ptr = teddy_base + ROUNDUP_CL(headerSize) + ROUNDUP_CL(maskLen) +
ROUNDUP_CL(reinforcedDupMaskLen);
- assert(ISALIGNED_CL(ptr));
- teddy->confOffset = verify_u32(ptr - teddy_base);
- memcpy(ptr, confirmTable.get(), confirmTable.size());
- ptr += ROUNDUP_CL(confirmTable.size());
-
- // Write flood control structures.
- assert(ISALIGNED_CL(ptr));
- teddy->floodOffset = verify_u32(ptr - teddy_base);
- memcpy(ptr, floodTable.get(), floodTable.size());
- ptr += floodTable.size();
-
- // Write teddy masks.
- u8 *baseMsk = teddy_base + ROUNDUP_CL(headerSize);
- fillNibbleMasks(bucketToLits, lits, eng.numMasks, maskWidth, maskLen,
- baseMsk);
-
+ assert(ISALIGNED_CL(ptr));
+ teddy->confOffset = verify_u32(ptr - teddy_base);
+ memcpy(ptr, confirmTable.get(), confirmTable.size());
+ ptr += ROUNDUP_CL(confirmTable.size());
+
+ // Write flood control structures.
+ assert(ISALIGNED_CL(ptr));
+ teddy->floodOffset = verify_u32(ptr - teddy_base);
+ memcpy(ptr, floodTable.get(), floodTable.size());
+ ptr += floodTable.size();
+
+ // Write teddy masks.
+ u8 *baseMsk = teddy_base + ROUNDUP_CL(headerSize);
+ fillNibbleMasks(bucketToLits, lits, eng.numMasks, maskWidth, maskLen,
+ baseMsk);
+
if (maskWidth == 1) { // reinforcement table in Teddy
// Write reinforcement masks.
u8 *reinforcedMsk = baseMsk + ROUNDUP_CL(maskLen);
@@ -615,53 +615,53 @@ bytecode_ptr<FDR> TeddyCompiler::build() {
fillDupNibbleMasks(bucketToLits, lits, eng.numMasks,
reinforcedDupMaskLen, dupMsk);
}
-
- return fdr;
-}
-
-
-static
-bool assignStringsToBuckets(
- const vector<hwlmLiteral> &lits,
- TeddyEngineDescription &eng,
- map<BucketIndex, vector<LiteralIndex>> &bucketToLits) {
- assert(eng.numMasks <= MAX_NUM_MASKS);
- if (lits.size() > eng.getNumBuckets() * TEDDY_BUCKET_LOAD) {
- DEBUG_PRINTF("too many literals: %zu\n", lits.size());
- return false;
- }
-
-#ifdef TEDDY_DEBUG
- for (size_t i = 0; i < lits.size(); i++) {
- printf("lit %zu (len = %zu, %s) is ", i, lits[i].s.size(),
- lits[i].nocase ? "caseless" : "caseful");
- for (size_t j = 0; j < lits[i].s.size(); j++) {
- printf("%02x", ((u32)lits[i].s[j])&0xff);
- }
+
+ return fdr;
+}
+
+
+static
+bool assignStringsToBuckets(
+ const vector<hwlmLiteral> &lits,
+ TeddyEngineDescription &eng,
+ map<BucketIndex, vector<LiteralIndex>> &bucketToLits) {
+ assert(eng.numMasks <= MAX_NUM_MASKS);
+ if (lits.size() > eng.getNumBuckets() * TEDDY_BUCKET_LOAD) {
+ DEBUG_PRINTF("too many literals: %zu\n", lits.size());
+ return false;
+ }
+
+#ifdef TEDDY_DEBUG
+ for (size_t i = 0; i < lits.size(); i++) {
+ printf("lit %zu (len = %zu, %s) is ", i, lits[i].s.size(),
+ lits[i].nocase ? "caseless" : "caseful");
+ for (size_t j = 0; j < lits[i].s.size(); j++) {
+ printf("%02x", ((u32)lits[i].s[j])&0xff);
+ }
printf("\n");
}
#endif
- if (!pack(lits, eng, bucketToLits)) {
- DEBUG_PRINTF("more lits (%zu) than buckets (%u), can't pack.\n",
- lits.size(), eng.getNumBuckets());
- return false;
- }
- return true;
+ if (!pack(lits, eng, bucketToLits)) {
+ DEBUG_PRINTF("more lits (%zu) than buckets (%u), can't pack.\n",
+ lits.size(), eng.getNumBuckets());
+ return false;
+ }
+ return true;
}
} // namespace
-bytecode_ptr<FDR> teddyBuildTable(const HWLMProto &proto, const Grey &grey) {
- TeddyCompiler tc(proto.lits, proto.bucketToLits, *(proto.teddyEng),
- proto.make_small, grey);
- return tc.build();
-}
-
-
-unique_ptr<HWLMProto> teddyBuildProtoHinted(
- u8 engType, const vector<hwlmLiteral> &lits,
- bool make_small, u32 hint, const target_t &target) {
+bytecode_ptr<FDR> teddyBuildTable(const HWLMProto &proto, const Grey &grey) {
+ TeddyCompiler tc(proto.lits, proto.bucketToLits, *(proto.teddyEng),
+ proto.make_small, grey);
+ return tc.build();
+}
+
+
+unique_ptr<HWLMProto> teddyBuildProtoHinted(
+ u8 engType, const vector<hwlmLiteral> &lits,
+ bool make_small, u32 hint, const target_t &target) {
unique_ptr<TeddyEngineDescription> des;
if (hint == HINT_INVALID) {
des = chooseTeddyEngine(target, lits);
@@ -671,14 +671,14 @@ unique_ptr<HWLMProto> teddyBuildProtoHinted(
if (!des) {
return nullptr;
}
-
- map<BucketIndex, std::vector<LiteralIndex>> bucketToLits;
- if (!assignStringsToBuckets(lits, *des, bucketToLits)) {
- return nullptr;
- }
-
- return ue2::make_unique<HWLMProto>(engType, move(des), lits,
- bucketToLits, make_small);
+
+ map<BucketIndex, std::vector<LiteralIndex>> bucketToLits;
+ if (!assignStringsToBuckets(lits, *des, bucketToLits)) {
+ return nullptr;
+ }
+
+ return ue2::make_unique<HWLMProto>(engType, move(des), lits,
+ bucketToLits, make_small);
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_compile.h b/contrib/libs/hyperscan/src/fdr/teddy_compile.h
index f5e6eccaa78..a2b4a13ca36 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_compile.h
+++ b/contrib/libs/hyperscan/src/fdr/teddy_compile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief FDR literal matcher: Teddy build API.
*/
@@ -35,8 +35,8 @@
#define TEDDY_COMPILE_H
#include "ue2common.h"
-#include "hwlm/hwlm_build.h"
-#include "util/bytecode_ptr.h"
+#include "hwlm/hwlm_build.h"
+#include "util/bytecode_ptr.h"
#include <vector>
@@ -44,16 +44,16 @@ struct FDR;
namespace ue2 {
-class TeddyEngineDescription;
-struct Grey;
+class TeddyEngineDescription;
+struct Grey;
struct hwlmLiteral;
-struct target_t;
+struct target_t;
-bytecode_ptr<FDR> teddyBuildTable(const HWLMProto &proto, const Grey &grey);
+bytecode_ptr<FDR> teddyBuildTable(const HWLMProto &proto, const Grey &grey);
-std::unique_ptr<HWLMProto> teddyBuildProtoHinted(
- u8 engType, const std::vector<hwlmLiteral> &lits,
- bool make_small, u32 hint, const target_t &target);
+std::unique_ptr<HWLMProto> teddyBuildProtoHinted(
+ u8 engType, const std::vector<hwlmLiteral> &lits,
+ bool make_small, u32 hint, const target_t &target);
} // namespace ue2
#endif // TEDDY_COMPILE_H
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_engine_description.cpp b/contrib/libs/hyperscan/src/fdr/teddy_engine_description.cpp
index cd0a3590a53..88ae0f53821 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_engine_description.cpp
+++ b/contrib/libs/hyperscan/src/fdr/teddy_engine_description.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -44,35 +44,35 @@ namespace ue2 {
TeddyEngineDescription::TeddyEngineDescription(const TeddyEngineDef &def)
: EngineDescription(def.id, targetByArchFeatures(def.cpu_features),
- def.numBuckets),
+ def.numBuckets),
numMasks(def.numMasks), packed(def.packed) {}
u32 TeddyEngineDescription::getDefaultFloodSuffixLength() const {
return numMasks;
}
-void getTeddyDescriptions(vector<TeddyEngineDescription> *out) {
- static const TeddyEngineDef defns[] = {
- { 3, 0 | HS_CPU_FEATURES_AVX2, 1, 16, false },
- { 4, 0 | HS_CPU_FEATURES_AVX2, 1, 16, true },
- { 5, 0 | HS_CPU_FEATURES_AVX2, 2, 16, false },
- { 6, 0 | HS_CPU_FEATURES_AVX2, 2, 16, true },
- { 7, 0 | HS_CPU_FEATURES_AVX2, 3, 16, false },
- { 8, 0 | HS_CPU_FEATURES_AVX2, 3, 16, true },
- { 9, 0 | HS_CPU_FEATURES_AVX2, 4, 16, false },
- { 10, 0 | HS_CPU_FEATURES_AVX2, 4, 16, true },
- { 11, 0, 1, 8, false },
- { 12, 0, 1, 8, true },
- { 13, 0, 2, 8, false },
- { 14, 0, 2, 8, true },
- { 15, 0, 3, 8, false },
- { 16, 0, 3, 8, true },
- { 17, 0, 4, 8, false },
- { 18, 0, 4, 8, true },
- };
- out->clear();
- for (const auto &def : defns) {
- out->emplace_back(def);
+void getTeddyDescriptions(vector<TeddyEngineDescription> *out) {
+ static const TeddyEngineDef defns[] = {
+ { 3, 0 | HS_CPU_FEATURES_AVX2, 1, 16, false },
+ { 4, 0 | HS_CPU_FEATURES_AVX2, 1, 16, true },
+ { 5, 0 | HS_CPU_FEATURES_AVX2, 2, 16, false },
+ { 6, 0 | HS_CPU_FEATURES_AVX2, 2, 16, true },
+ { 7, 0 | HS_CPU_FEATURES_AVX2, 3, 16, false },
+ { 8, 0 | HS_CPU_FEATURES_AVX2, 3, 16, true },
+ { 9, 0 | HS_CPU_FEATURES_AVX2, 4, 16, false },
+ { 10, 0 | HS_CPU_FEATURES_AVX2, 4, 16, true },
+ { 11, 0, 1, 8, false },
+ { 12, 0, 1, 8, true },
+ { 13, 0, 2, 8, false },
+ { 14, 0, 2, 8, true },
+ { 15, 0, 3, 8, false },
+ { 16, 0, 3, 8, true },
+ { 17, 0, 4, 8, false },
+ { 18, 0, 4, 8, true },
+ };
+ out->clear();
+ for (const auto &def : defns) {
+ out->emplace_back(def);
}
}
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_engine_description.h b/contrib/libs/hyperscan/src/fdr/teddy_engine_description.h
index c263b15ba7f..95931613840 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_engine_description.h
+++ b/contrib/libs/hyperscan/src/fdr/teddy_engine_description.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_internal.h b/contrib/libs/hyperscan/src/fdr/teddy_internal.h
index 95f5ab2baa7..1e9e603fa7f 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_internal.h
+++ b/contrib/libs/hyperscan/src/fdr/teddy_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,28 +26,28 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/* Teddy bytecode layout:
- * * |-----|
- * * | | struct Teddy
- * * |-----|
- * * | | teddy masks
- * * | |
- * * |-----|
- * * | | reinforcement mask table for bucket 0..7
- * * | |
- * * |-----|
- * * | | reinforcement mask table for bucket 8..15 (FAT teddy)
- * * | |
- * * |-----|
- * * | | confirm
- * * | |
- * * | |
- * * |-----|
- * * | | flood control
- * * | |
- * * |-----|
- */
-
+/* Teddy bytecode layout:
+ * * |-----|
+ * * | | struct Teddy
+ * * |-----|
+ * * | | teddy masks
+ * * | |
+ * * |-----|
+ * * | | reinforcement mask table for bucket 0..7
+ * * | |
+ * * |-----|
+ * * | | reinforcement mask table for bucket 8..15 (FAT teddy)
+ * * | |
+ * * |-----|
+ * * | | confirm
+ * * | |
+ * * | |
+ * * |-----|
+ * * | | flood control
+ * * | |
+ * * |-----|
+ */
+
#ifndef TEDDY_INTERNAL_H
#define TEDDY_INTERNAL_H
@@ -58,8 +58,8 @@ struct Teddy {
u32 engineID;
u32 size;
u32 maxStringLen;
- u32 numStrings;
- u32 confOffset;
+ u32 numStrings;
+ u32 confOffset;
u32 floodOffset;
};
diff --git a/contrib/libs/hyperscan/src/fdr/teddy_runtime_common.h b/contrib/libs/hyperscan/src/fdr/teddy_runtime_common.h
index 692761c5e66..b76800eb041 100644
--- a/contrib/libs/hyperscan/src/fdr/teddy_runtime_common.h
+++ b/contrib/libs/hyperscan/src/fdr/teddy_runtime_common.h
@@ -1,50 +1,50 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Teddy literal matcher: common runtime procedures.
- */
-
-#ifndef TEDDY_RUNTIME_COMMON_H_
-#define TEDDY_RUNTIME_COMMON_H_
-
-#include "fdr_confirm.h"
-#include "fdr_confirm_runtime.h"
-#include "ue2common.h"
-#include "util/bitutils.h"
-#include "util/simd_utils.h"
-#include "util/uniform_ops.h"
-
-extern const u8 ALIGN_DIRECTIVE p_mask_arr[17][32];
-#if defined(HAVE_AVX2)
-extern const u8 ALIGN_AVX_DIRECTIVE p_mask_arr256[33][64];
-#endif
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Teddy literal matcher: common runtime procedures.
+ */
+
+#ifndef TEDDY_RUNTIME_COMMON_H_
+#define TEDDY_RUNTIME_COMMON_H_
+
+#include "fdr_confirm.h"
+#include "fdr_confirm_runtime.h"
+#include "ue2common.h"
+#include "util/bitutils.h"
+#include "util/simd_utils.h"
+#include "util/uniform_ops.h"
+
+extern const u8 ALIGN_DIRECTIVE p_mask_arr[17][32];
+#if defined(HAVE_AVX2)
+extern const u8 ALIGN_AVX_DIRECTIVE p_mask_arr256[33][64];
+#endif
+
#if defined(HAVE_AVX512VBMI)
static const u8 ALIGN_DIRECTIVE p_sh_mask_arr[80] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,405 +55,405 @@ static const u8 ALIGN_DIRECTIVE p_sh_mask_arr[80] = {
};
#endif
-#ifdef ARCH_64_BIT
-#define TEDDY_CONF_TYPE u64a
-#define TEDDY_FIND_AND_CLEAR_LSB(conf) findAndClearLSB_64(conf)
-#else
-#define TEDDY_CONF_TYPE u32
-#define TEDDY_FIND_AND_CLEAR_LSB(conf) findAndClearLSB_32(conf)
-#endif
-
-#define CHECK_HWLM_TERMINATE_MATCHING \
-do { \
- if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
- return HWLM_TERMINATED; \
- } \
-} while (0);
-
-#define CHECK_FLOOD \
-do { \
- if (unlikely(ptr > tryFloodDetect)) { \
- tryFloodDetect = floodDetect(fdr, a, &ptr, tryFloodDetect, \
- &floodBackoff, &control, iterBytes); \
- CHECK_HWLM_TERMINATE_MATCHING; \
- } \
-} while (0);
-
-/*
- * \brief Copy a block of [0,15] bytes efficiently.
- *
- * This function is a workaround intended to stop some compilers from
- * synthesizing a memcpy function call out of the copy of a small number of
- * bytes that we do in vectoredLoad128.
- */
-static really_inline
-void copyRuntBlock128(u8 *dst, const u8 *src, size_t len) {
- switch (len) {
- case 0:
- break;
- case 1:
- *dst = *src;
- break;
- case 2:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- break;
- case 3:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- dst[2] = src[2];
- break;
- case 4:
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 5:
- case 6:
- case 7:
- /* Perform copy with two overlapping 4-byte chunks. */
- unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 8:
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- default:
- /* Perform copy with two overlapping 8-byte chunks. */
- assert(len < 16);
- unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- }
-}
-
-// Note: p_mask is an output param that initialises a poison mask.
-// *p_mask = load128(p_mask_arr[n] + 16 - m) means:
-// m byte 0xff in the beginning, followed by n byte 0x00,
-// then followed by the rest bytes 0xff.
-// ptr >= lo:
-// no history.
-// for end/short zone, ptr==lo and start_offset==0
-// for start zone, see below
-// lo ptr hi hi
-// |----------|-------|----------------|............|
-// -start 0 -start+offset MIN(avail,16)
-// p_mask ffff..ff0000...........00ffff..........
-// ptr < lo:
-// only start zone.
-// history
-// ptr lo hi hi
-// |----------|-------|----------------|............|
-// 0 start start+offset end(<=16)
-// p_mask ffff.....ffffff..ff0000...........00ffff..........
-static really_inline
-m128 vectoredLoad128(m128 *p_mask, const u8 *ptr, const size_t start_offset,
- const u8 *lo, const u8 *hi,
- const u8 *buf_history, size_t len_history,
- const u32 nMasks) {
- union {
- u8 val8[16];
- m128 val128;
- } u;
- u.val128 = zeroes128();
-
- uintptr_t copy_start;
- uintptr_t copy_len;
-
- if (ptr >= lo) { // short/end/start zone
- uintptr_t start = (uintptr_t)(ptr - lo);
- uintptr_t avail = (uintptr_t)(hi - ptr);
- if (avail >= 16) {
- assert(start_offset - start <= 16);
- *p_mask = loadu128(p_mask_arr[16 - start_offset + start]
- + 16 - start_offset + start);
- return loadu128(ptr);
- }
- assert(start_offset - start <= avail);
- *p_mask = loadu128(p_mask_arr[avail - start_offset + start]
- + 16 - start_offset + start);
- copy_start = 0;
- copy_len = avail;
- } else { // start zone
- uintptr_t need = MIN((uintptr_t)(lo - ptr),
- MIN(len_history, nMasks - 1));
- uintptr_t start = (uintptr_t)(lo - ptr);
- uintptr_t i;
- for (i = start - need; i < start; i++) {
- u.val8[i] = buf_history[len_history - (start - i)];
- }
- uintptr_t end = MIN(16, (uintptr_t)(hi - ptr));
- assert(start + start_offset <= end);
- *p_mask = loadu128(p_mask_arr[end - start - start_offset]
- + 16 - start - start_offset);
- copy_start = start;
- copy_len = end - start;
- }
-
- // Runt block from the buffer.
- copyRuntBlock128(&u.val8[copy_start], &ptr[copy_start], copy_len);
-
- return u.val128;
-}
-
-#if defined(HAVE_AVX2)
-/*
- * \brief Copy a block of [0,31] bytes efficiently.
- *
- * This function is a workaround intended to stop some compilers from
- * synthesizing a memcpy function call out of the copy of a small number of
- * bytes that we do in vectoredLoad256.
- */
-static really_inline
-void copyRuntBlock256(u8 *dst, const u8 *src, size_t len) {
- switch (len) {
- case 0:
- break;
- case 1:
- *dst = *src;
- break;
- case 2:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- break;
- case 3:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- dst[2] = src[2];
- break;
- case 4:
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 5:
- case 6:
- case 7:
- /* Perform copy with two overlapping 4-byte chunks. */
- unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 8:
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- /* Perform copy with two overlapping 8-byte chunks. */
- unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- case 16:
- storeu128(dst, loadu128(src));
- break;
- default:
- /* Perform copy with two overlapping 16-byte chunks. */
- assert(len < 32);
- storeu128(dst + len - 16, loadu128(src + len - 16));
- storeu128(dst, loadu128(src));
- break;
- }
-}
-
-// Note: p_mask is an output param that initialises a poison mask.
-// *p_mask = load256(p_mask_arr256[n] + 32 - m) means:
-// m byte 0xff in the beginning, followed by n byte 0x00,
-// then followed by the rest bytes 0xff.
-// ptr >= lo:
-// no history.
-// for end/short zone, ptr==lo and start_offset==0
-// for start zone, see below
-// lo ptr hi hi
-// |----------|-------|----------------|............|
-// -start 0 -start+offset MIN(avail,32)
-// p_mask ffff..ff0000...........00ffff..........
-// ptr < lo:
-// only start zone.
-// history
-// ptr lo hi hi
-// |----------|-------|----------------|............|
-// 0 start start+offset end(<=32)
-// p_mask ffff.....ffffff..ff0000...........00ffff..........
-static really_inline
-m256 vectoredLoad256(m256 *p_mask, const u8 *ptr, const size_t start_offset,
- const u8 *lo, const u8 *hi,
- const u8 *buf_history, size_t len_history,
- const u32 nMasks) {
- union {
- u8 val8[32];
- m256 val256;
- } u;
- u.val256 = zeroes256();
-
- uintptr_t copy_start;
- uintptr_t copy_len;
-
- if (ptr >= lo) { // short/end/start zone
- uintptr_t start = (uintptr_t)(ptr - lo);
- uintptr_t avail = (uintptr_t)(hi - ptr);
- if (avail >= 32) {
- assert(start_offset - start <= 32);
- *p_mask = loadu256(p_mask_arr256[32 - start_offset + start]
- + 32 - start_offset + start);
- return loadu256(ptr);
- }
- assert(start_offset - start <= avail);
- *p_mask = loadu256(p_mask_arr256[avail - start_offset + start]
- + 32 - start_offset + start);
- copy_start = 0;
- copy_len = avail;
- } else { //start zone
- uintptr_t need = MIN((uintptr_t)(lo - ptr),
- MIN(len_history, nMasks - 1));
- uintptr_t start = (uintptr_t)(lo - ptr);
- uintptr_t i;
- for (i = start - need; i < start; i++) {
- u.val8[i] = buf_history[len_history - (start - i)];
- }
- uintptr_t end = MIN(32, (uintptr_t)(hi - ptr));
- assert(start + start_offset <= end);
- *p_mask = loadu256(p_mask_arr256[end - start - start_offset]
- + 32 - start - start_offset);
- copy_start = start;
- copy_len = end - start;
- }
-
- // Runt block from the buffer.
- copyRuntBlock256(&u.val8[copy_start], &ptr[copy_start], copy_len);
-
- return u.val256;
-}
-#endif // HAVE_AVX2
-
-#if defined(HAVE_AVX512)
-// Note: p_mask is an output param that initialises a poison mask.
-// u64a k = ones_u64a << n' >> m'; // m' < n'
-// *p_mask = set_mask_m512(~k);
-// means p_mask is consist of:
-// (n' - m') poison bytes "0xff" at the beginning,
-// followed by (64 - n') valid bytes "0x00",
-// then followed by the rest m' poison bytes "0xff".
-// ptr >= lo:
-// no history.
-// for end/short zone, ptr==lo and start_offset==0
-// for start zone, see below
-// lo ptr hi hi
-// |----------|-------|----------------|............|
-// -start 0 -start+offset MIN(avail,64)
-// p_mask ffff..ff0000...........00ffff..........
-// ptr < lo:
-// only start zone.
-// history
-// ptr lo hi hi
-// |----------|-------|----------------|............|
-// 0 start start+offset end(<=64)
-// p_mask ffff.....ffffff..ff0000...........00ffff..........
-static really_inline
-m512 vectoredLoad512(m512 *p_mask, const u8 *ptr, const size_t start_offset,
- const u8 *lo, const u8 *hi, const u8 *hbuf, size_t hlen,
- const u32 nMasks) {
- m512 val;
-
- uintptr_t copy_start;
- uintptr_t copy_len;
-
- if (ptr >= lo) { // short/end/start zone
- uintptr_t start = (uintptr_t)(ptr - lo);
- uintptr_t avail = (uintptr_t)(hi - ptr);
- if (avail >= 64) {
- assert(start_offset - start <= 64);
- u64a k = ones_u64a << (start_offset - start);
- *p_mask = set_mask_m512(~k);
- return loadu512(ptr);
- }
- assert(start_offset - start <= avail);
- u64a k = ones_u64a << (64 - avail + start_offset - start)
- >> (64 - avail);
- *p_mask = set_mask_m512(~k);
- copy_start = 0;
- copy_len = avail;
- } else { //start zone
- uintptr_t need = MIN((uintptr_t)(lo - ptr),
- MIN(hlen, nMasks - 1));
- uintptr_t start = (uintptr_t)(lo - ptr);
- u64a j = 0x7fffffffffffffffULL >> (63 - need) << (start - need);
- val = loadu_maskz_m512(j, &hbuf[hlen - start]);
- uintptr_t end = MIN(64, (uintptr_t)(hi - ptr));
- assert(start + start_offset <= end);
- u64a k = ones_u64a << (64 - end + start + start_offset) >> (64 - end);
- *p_mask = set_mask_m512(~k);
- copy_start = start;
- copy_len = end - start;
- }
-
- assert(copy_len < 64);
- assert(copy_len > 0);
- u64a j = ones_u64a >> (64 - copy_len) << copy_start;
- val = loadu_mask_m512(val, j, ptr);
-
- return val;
-}
-#endif // HAVE_AVX512
-
-static really_inline
-u64a getConfVal(const struct FDR_Runtime_Args *a, const u8 *ptr, u32 byte,
+#ifdef ARCH_64_BIT
+#define TEDDY_CONF_TYPE u64a
+#define TEDDY_FIND_AND_CLEAR_LSB(conf) findAndClearLSB_64(conf)
+#else
+#define TEDDY_CONF_TYPE u32
+#define TEDDY_FIND_AND_CLEAR_LSB(conf) findAndClearLSB_32(conf)
+#endif
+
+#define CHECK_HWLM_TERMINATE_MATCHING \
+do { \
+ if (unlikely(control == HWLM_TERMINATE_MATCHING)) { \
+ return HWLM_TERMINATED; \
+ } \
+} while (0);
+
+#define CHECK_FLOOD \
+do { \
+ if (unlikely(ptr > tryFloodDetect)) { \
+ tryFloodDetect = floodDetect(fdr, a, &ptr, tryFloodDetect, \
+ &floodBackoff, &control, iterBytes); \
+ CHECK_HWLM_TERMINATE_MATCHING; \
+ } \
+} while (0);
+
+/*
+ * \brief Copy a block of [0,15] bytes efficiently.
+ *
+ * This function is a workaround intended to stop some compilers from
+ * synthesizing a memcpy function call out of the copy of a small number of
+ * bytes that we do in vectoredLoad128.
+ */
+static really_inline
+void copyRuntBlock128(u8 *dst, const u8 *src, size_t len) {
+ switch (len) {
+ case 0:
+ break;
+ case 1:
+ *dst = *src;
+ break;
+ case 2:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ break;
+ case 3:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ dst[2] = src[2];
+ break;
+ case 4:
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 5:
+ case 6:
+ case 7:
+ /* Perform copy with two overlapping 4-byte chunks. */
+ unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 8:
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ default:
+ /* Perform copy with two overlapping 8-byte chunks. */
+ assert(len < 16);
+ unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ }
+}
+
+// Note: p_mask is an output param that initialises a poison mask.
+// *p_mask = load128(p_mask_arr[n] + 16 - m) means:
+// m byte 0xff in the beginning, followed by n byte 0x00,
+// then followed by the rest bytes 0xff.
+// ptr >= lo:
+// no history.
+// for end/short zone, ptr==lo and start_offset==0
+// for start zone, see below
+// lo ptr hi hi
+// |----------|-------|----------------|............|
+// -start 0 -start+offset MIN(avail,16)
+// p_mask ffff..ff0000...........00ffff..........
+// ptr < lo:
+// only start zone.
+// history
+// ptr lo hi hi
+// |----------|-------|----------------|............|
+// 0 start start+offset end(<=16)
+// p_mask ffff.....ffffff..ff0000...........00ffff..........
+static really_inline
+m128 vectoredLoad128(m128 *p_mask, const u8 *ptr, const size_t start_offset,
+ const u8 *lo, const u8 *hi,
+ const u8 *buf_history, size_t len_history,
+ const u32 nMasks) {
+ union {
+ u8 val8[16];
+ m128 val128;
+ } u;
+ u.val128 = zeroes128();
+
+ uintptr_t copy_start;
+ uintptr_t copy_len;
+
+ if (ptr >= lo) { // short/end/start zone
+ uintptr_t start = (uintptr_t)(ptr - lo);
+ uintptr_t avail = (uintptr_t)(hi - ptr);
+ if (avail >= 16) {
+ assert(start_offset - start <= 16);
+ *p_mask = loadu128(p_mask_arr[16 - start_offset + start]
+ + 16 - start_offset + start);
+ return loadu128(ptr);
+ }
+ assert(start_offset - start <= avail);
+ *p_mask = loadu128(p_mask_arr[avail - start_offset + start]
+ + 16 - start_offset + start);
+ copy_start = 0;
+ copy_len = avail;
+ } else { // start zone
+ uintptr_t need = MIN((uintptr_t)(lo - ptr),
+ MIN(len_history, nMasks - 1));
+ uintptr_t start = (uintptr_t)(lo - ptr);
+ uintptr_t i;
+ for (i = start - need; i < start; i++) {
+ u.val8[i] = buf_history[len_history - (start - i)];
+ }
+ uintptr_t end = MIN(16, (uintptr_t)(hi - ptr));
+ assert(start + start_offset <= end);
+ *p_mask = loadu128(p_mask_arr[end - start - start_offset]
+ + 16 - start - start_offset);
+ copy_start = start;
+ copy_len = end - start;
+ }
+
+ // Runt block from the buffer.
+ copyRuntBlock128(&u.val8[copy_start], &ptr[copy_start], copy_len);
+
+ return u.val128;
+}
+
+#if defined(HAVE_AVX2)
+/*
+ * \brief Copy a block of [0,31] bytes efficiently.
+ *
+ * This function is a workaround intended to stop some compilers from
+ * synthesizing a memcpy function call out of the copy of a small number of
+ * bytes that we do in vectoredLoad256.
+ */
+static really_inline
+void copyRuntBlock256(u8 *dst, const u8 *src, size_t len) {
+ switch (len) {
+ case 0:
+ break;
+ case 1:
+ *dst = *src;
+ break;
+ case 2:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ break;
+ case 3:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ dst[2] = src[2];
+ break;
+ case 4:
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 5:
+ case 6:
+ case 7:
+ /* Perform copy with two overlapping 4-byte chunks. */
+ unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 8:
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* Perform copy with two overlapping 8-byte chunks. */
+ unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ case 16:
+ storeu128(dst, loadu128(src));
+ break;
+ default:
+ /* Perform copy with two overlapping 16-byte chunks. */
+ assert(len < 32);
+ storeu128(dst + len - 16, loadu128(src + len - 16));
+ storeu128(dst, loadu128(src));
+ break;
+ }
+}
+
+// Note: p_mask is an output param that initialises a poison mask.
+// *p_mask = load256(p_mask_arr256[n] + 32 - m) means:
+// m byte 0xff in the beginning, followed by n byte 0x00,
+// then followed by the rest bytes 0xff.
+// ptr >= lo:
+// no history.
+// for end/short zone, ptr==lo and start_offset==0
+// for start zone, see below
+// lo ptr hi hi
+// |----------|-------|----------------|............|
+// -start 0 -start+offset MIN(avail,32)
+// p_mask ffff..ff0000...........00ffff..........
+// ptr < lo:
+// only start zone.
+// history
+// ptr lo hi hi
+// |----------|-------|----------------|............|
+// 0 start start+offset end(<=32)
+// p_mask ffff.....ffffff..ff0000...........00ffff..........
+static really_inline
+m256 vectoredLoad256(m256 *p_mask, const u8 *ptr, const size_t start_offset,
+ const u8 *lo, const u8 *hi,
+ const u8 *buf_history, size_t len_history,
+ const u32 nMasks) {
+ union {
+ u8 val8[32];
+ m256 val256;
+ } u;
+ u.val256 = zeroes256();
+
+ uintptr_t copy_start;
+ uintptr_t copy_len;
+
+ if (ptr >= lo) { // short/end/start zone
+ uintptr_t start = (uintptr_t)(ptr - lo);
+ uintptr_t avail = (uintptr_t)(hi - ptr);
+ if (avail >= 32) {
+ assert(start_offset - start <= 32);
+ *p_mask = loadu256(p_mask_arr256[32 - start_offset + start]
+ + 32 - start_offset + start);
+ return loadu256(ptr);
+ }
+ assert(start_offset - start <= avail);
+ *p_mask = loadu256(p_mask_arr256[avail - start_offset + start]
+ + 32 - start_offset + start);
+ copy_start = 0;
+ copy_len = avail;
+ } else { //start zone
+ uintptr_t need = MIN((uintptr_t)(lo - ptr),
+ MIN(len_history, nMasks - 1));
+ uintptr_t start = (uintptr_t)(lo - ptr);
+ uintptr_t i;
+ for (i = start - need; i < start; i++) {
+ u.val8[i] = buf_history[len_history - (start - i)];
+ }
+ uintptr_t end = MIN(32, (uintptr_t)(hi - ptr));
+ assert(start + start_offset <= end);
+ *p_mask = loadu256(p_mask_arr256[end - start - start_offset]
+ + 32 - start - start_offset);
+ copy_start = start;
+ copy_len = end - start;
+ }
+
+ // Runt block from the buffer.
+ copyRuntBlock256(&u.val8[copy_start], &ptr[copy_start], copy_len);
+
+ return u.val256;
+}
+#endif // HAVE_AVX2
+
+#if defined(HAVE_AVX512)
+// Note: p_mask is an output param that initialises a poison mask.
+// u64a k = ones_u64a << n' >> m'; // m' < n'
+// *p_mask = set_mask_m512(~k);
+// means p_mask is consist of:
+// (n' - m') poison bytes "0xff" at the beginning,
+// followed by (64 - n') valid bytes "0x00",
+// then followed by the rest m' poison bytes "0xff".
+// ptr >= lo:
+// no history.
+// for end/short zone, ptr==lo and start_offset==0
+// for start zone, see below
+// lo ptr hi hi
+// |----------|-------|----------------|............|
+// -start 0 -start+offset MIN(avail,64)
+// p_mask ffff..ff0000...........00ffff..........
+// ptr < lo:
+// only start zone.
+// history
+// ptr lo hi hi
+// |----------|-------|----------------|............|
+// 0 start start+offset end(<=64)
+// p_mask ffff.....ffffff..ff0000...........00ffff..........
+static really_inline
+m512 vectoredLoad512(m512 *p_mask, const u8 *ptr, const size_t start_offset,
+ const u8 *lo, const u8 *hi, const u8 *hbuf, size_t hlen,
+ const u32 nMasks) {
+ m512 val;
+
+ uintptr_t copy_start;
+ uintptr_t copy_len;
+
+ if (ptr >= lo) { // short/end/start zone
+ uintptr_t start = (uintptr_t)(ptr - lo);
+ uintptr_t avail = (uintptr_t)(hi - ptr);
+ if (avail >= 64) {
+ assert(start_offset - start <= 64);
+ u64a k = ones_u64a << (start_offset - start);
+ *p_mask = set_mask_m512(~k);
+ return loadu512(ptr);
+ }
+ assert(start_offset - start <= avail);
+ u64a k = ones_u64a << (64 - avail + start_offset - start)
+ >> (64 - avail);
+ *p_mask = set_mask_m512(~k);
+ copy_start = 0;
+ copy_len = avail;
+ } else { //start zone
+ uintptr_t need = MIN((uintptr_t)(lo - ptr),
+ MIN(hlen, nMasks - 1));
+ uintptr_t start = (uintptr_t)(lo - ptr);
+ u64a j = 0x7fffffffffffffffULL >> (63 - need) << (start - need);
+ val = loadu_maskz_m512(j, &hbuf[hlen - start]);
+ uintptr_t end = MIN(64, (uintptr_t)(hi - ptr));
+ assert(start + start_offset <= end);
+ u64a k = ones_u64a << (64 - end + start + start_offset) >> (64 - end);
+ *p_mask = set_mask_m512(~k);
+ copy_start = start;
+ copy_len = end - start;
+ }
+
+ assert(copy_len < 64);
+ assert(copy_len > 0);
+ u64a j = ones_u64a >> (64 - copy_len) << copy_start;
+ val = loadu_mask_m512(val, j, ptr);
+
+ return val;
+}
+#endif // HAVE_AVX512
+
+static really_inline
+u64a getConfVal(const struct FDR_Runtime_Args *a, const u8 *ptr, u32 byte,
UNUSED CautionReason reason) {
- u64a confVal = 0;
- const u8 *buf = a->buf;
- size_t len = a->len;
- const u8 *confirm_loc = ptr + byte - 7;
+ u64a confVal = 0;
+ const u8 *buf = a->buf;
+ size_t len = a->len;
+ const u8 *confirm_loc = ptr + byte - 7;
#if defined(HAVE_AVX512VBMI)
if (likely(confirm_loc >= buf)) {
#else
- if (likely(reason == NOT_CAUTIOUS || confirm_loc >= buf)) {
+ if (likely(reason == NOT_CAUTIOUS || confirm_loc >= buf)) {
#endif
- confVal = lv_u64a(confirm_loc, buf, buf + len);
- } else { // r == VECTORING, confirm_loc < buf
- u64a histBytes = a->histBytes;
- confVal = lv_u64a_ce(confirm_loc, buf, buf + len);
- // stitch together confVal and history
- u32 overhang = buf - confirm_loc;
- histBytes >>= 64 - (overhang * 8);
- confVal |= histBytes;
- }
- return confVal;
-}
-
-static really_inline
-void do_confWithBit_teddy(TEDDY_CONF_TYPE *conf, u8 bucket, u8 offset,
- const u32 *confBase, CautionReason reason,
- const struct FDR_Runtime_Args *a, const u8 *ptr,
- hwlmcb_rv_t *control, u32 *last_match) {
- do {
- u32 bit = TEDDY_FIND_AND_CLEAR_LSB(conf);
- u32 byte = bit / bucket + offset;
- u32 idx = bit % bucket;
- u32 cf = confBase[idx];
- if (!cf) {
- continue;
- }
- const struct FDRConfirm *fdrc = (const struct FDRConfirm *)
- ((const u8 *)confBase + cf);
- if (!(fdrc->groups & *control)) {
- continue;
- }
- u64a tmp = 0;
- u64a confVal = getConfVal(a, ptr, byte, reason);
- confWithBit(fdrc, a, ptr - a->buf + byte, control,
- last_match, confVal, &tmp, 0);
- } while (unlikely(*conf));
-}
-
-static really_inline
-const m128 *getMaskBase(const struct Teddy *teddy) {
- return (const m128 *)((const u8 *)teddy + ROUNDUP_CL(sizeof(struct Teddy)));
-}
-
-static really_inline
-const u64a *getReinforcedMaskBase(const struct Teddy *teddy, u8 numMask) {
- return (const u64a *)((const u8 *)getMaskBase(teddy)
- + ROUNDUP_CL(2 * numMask * sizeof(m128)));
-}
-
-static really_inline
-const u32 *getConfBase(const struct Teddy *teddy) {
- return (const u32 *)((const u8 *)teddy + teddy->confOffset);
-}
-
-#endif /* TEDDY_RUNTIME_COMMON_H_ */
+ confVal = lv_u64a(confirm_loc, buf, buf + len);
+ } else { // r == VECTORING, confirm_loc < buf
+ u64a histBytes = a->histBytes;
+ confVal = lv_u64a_ce(confirm_loc, buf, buf + len);
+ // stitch together confVal and history
+ u32 overhang = buf - confirm_loc;
+ histBytes >>= 64 - (overhang * 8);
+ confVal |= histBytes;
+ }
+ return confVal;
+}
+
+static really_inline
+void do_confWithBit_teddy(TEDDY_CONF_TYPE *conf, u8 bucket, u8 offset,
+ const u32 *confBase, CautionReason reason,
+ const struct FDR_Runtime_Args *a, const u8 *ptr,
+ hwlmcb_rv_t *control, u32 *last_match) {
+ do {
+ u32 bit = TEDDY_FIND_AND_CLEAR_LSB(conf);
+ u32 byte = bit / bucket + offset;
+ u32 idx = bit % bucket;
+ u32 cf = confBase[idx];
+ if (!cf) {
+ continue;
+ }
+ const struct FDRConfirm *fdrc = (const struct FDRConfirm *)
+ ((const u8 *)confBase + cf);
+ if (!(fdrc->groups & *control)) {
+ continue;
+ }
+ u64a tmp = 0;
+ u64a confVal = getConfVal(a, ptr, byte, reason);
+ confWithBit(fdrc, a, ptr - a->buf + byte, control,
+ last_match, confVal, &tmp, 0);
+ } while (unlikely(*conf));
+}
+
+static really_inline
+const m128 *getMaskBase(const struct Teddy *teddy) {
+ return (const m128 *)((const u8 *)teddy + ROUNDUP_CL(sizeof(struct Teddy)));
+}
+
+static really_inline
+const u64a *getReinforcedMaskBase(const struct Teddy *teddy, u8 numMask) {
+ return (const u64a *)((const u8 *)getMaskBase(teddy)
+ + ROUNDUP_CL(2 * numMask * sizeof(m128)));
+}
+
+static really_inline
+const u32 *getConfBase(const struct Teddy *teddy) {
+ return (const u32 *)((const u8 *)teddy + teddy->confOffset);
+}
+
+#endif /* TEDDY_RUNTIME_COMMON_H_ */
diff --git a/contrib/libs/hyperscan/src/grey.cpp b/contrib/libs/hyperscan/src/grey.cpp
index 5d62fb0d59e..86a93d25aae 100644
--- a/contrib/libs/hyperscan/src/grey.cpp
+++ b/contrib/libs/hyperscan/src/grey.cpp
@@ -34,7 +34,7 @@
#include <string>
#include <vector>
-#define DEFAULT_MAX_HISTORY 110
+#define DEFAULT_MAX_HISTORY 110
using namespace std;
@@ -42,7 +42,7 @@ namespace ue2 {
Grey::Grey(void) :
optimiseComponentTree(true),
- calcComponents(true),
+ calcComponents(true),
performGraphSimplification(true),
prefilterReductions(true),
removeEdgeRedundancy(true),
@@ -51,28 +51,28 @@ Grey::Grey(void) :
allowLitHaig(true),
allowLbr(true),
allowMcClellan(true),
- allowSheng(true),
- allowMcSheng(true),
+ allowSheng(true),
+ allowMcSheng(true),
allowPuff(true),
- allowLiteral(true),
- allowViolet(true),
+ allowLiteral(true),
+ allowViolet(true),
allowExtendedNFA(true), /* bounded repeats of course */
allowLimExNFA(true),
allowAnchoredAcyclic(true),
allowSmallLiteralSet(true),
allowCastle(true),
allowDecoratedLiteral(true),
- allowApproximateMatching(true),
+ allowApproximateMatching(true),
allowNoodle(true),
fdrAllowTeddy(true),
- fdrAllowFlood(true),
- violetAvoidSuffixes(true),
- violetAvoidWeakInfixes(true),
- violetDoubleCut(true),
- violetExtractStrongLiterals(true),
- violetLiteralChains(true),
- violetDoubleCutLiteralLen(3),
- violetEarlyCleanLiteralLen(6),
+ fdrAllowFlood(true),
+ violetAvoidSuffixes(true),
+ violetAvoidWeakInfixes(true),
+ violetDoubleCut(true),
+ violetExtractStrongLiterals(true),
+ violetLiteralChains(true),
+ violetDoubleCutLiteralLen(3),
+ violetEarlyCleanLiteralLen(6),
puffImproveHead(true),
castleExclusive(true),
mergeSEP(true), /* short exhaustible passthroughs */
@@ -101,7 +101,7 @@ Grey::Grey(void) :
minRoseLiteralLength(3),
minRoseNetflowLiteralLength(2),
maxRoseNetflowEdges(50000), /* otherwise no netflow pass. */
- maxEditDistance(16),
+ maxEditDistance(16),
minExtBoundedRepeatSize(32),
goughCopyPropagate(true),
goughRegisterAllocate(true),
@@ -130,7 +130,7 @@ Grey::Grey(void) :
equivalenceEnable(true),
allowSmallWrite(true), // McClellan dfas for small patterns
- allowSmallWriteSheng(false), // allow use of Sheng for SMWR
+ allowSmallWriteSheng(false), // allow use of Sheng for SMWR
smallWriteLargestBuffer(70), // largest buffer that can be
// considered a small write
@@ -138,11 +138,11 @@ Grey::Grey(void) :
// are given to rose &co
smallWriteLargestBufferBad(35),
limitSmallWriteOutfixSize(1048576), // 1 MB
- smallWriteMaxPatterns(10000),
- smallWriteMaxLiterals(10000),
- smallWriteMergeBatchSize(20),
- allowTamarama(true), // Tamarama engine
- tamaChunkSize(100),
+ smallWriteMaxPatterns(10000),
+ smallWriteMaxLiterals(10000),
+ smallWriteMergeBatchSize(20),
+ allowTamarama(true), // Tamarama engine
+ tamaChunkSize(100),
dumpFlags(0),
limitPatternCount(8000000), // 8M patterns
limitPatternLength(16000), // 16K bytes
@@ -159,8 +159,8 @@ Grey::Grey(void) :
limitEngineSize(1073741824), // 1 GB
limitDFASize(1073741824), // 1 GB
limitNFASize(1048576), // 1 MB
- limitLBRSize(1048576), // 1 MB
- limitApproxMatchingVertices(5000)
+ limitLBRSize(1048576), // 1 MB
+ limitApproxMatchingVertices(5000)
{
assert(maxAnchoredRegion < 64); /* a[lm]_log_sum have limited capacity */
}
@@ -220,7 +220,7 @@ void applyGreyOverrides(Grey *g, const string &s) {
} while (0)
G_UPDATE(optimiseComponentTree);
- G_UPDATE(calcComponents);
+ G_UPDATE(calcComponents);
G_UPDATE(performGraphSimplification);
G_UPDATE(prefilterReductions);
G_UPDATE(removeEdgeRedundancy);
@@ -229,11 +229,11 @@ void applyGreyOverrides(Grey *g, const string &s) {
G_UPDATE(allowLitHaig);
G_UPDATE(allowLbr);
G_UPDATE(allowMcClellan);
- G_UPDATE(allowSheng);
- G_UPDATE(allowMcSheng);
+ G_UPDATE(allowSheng);
+ G_UPDATE(allowMcSheng);
G_UPDATE(allowPuff);
- G_UPDATE(allowLiteral);
- G_UPDATE(allowViolet);
+ G_UPDATE(allowLiteral);
+ G_UPDATE(allowViolet);
G_UPDATE(allowExtendedNFA);
G_UPDATE(allowLimExNFA);
G_UPDATE(allowAnchoredAcyclic);
@@ -241,16 +241,16 @@ void applyGreyOverrides(Grey *g, const string &s) {
G_UPDATE(allowCastle);
G_UPDATE(allowDecoratedLiteral);
G_UPDATE(allowNoodle);
- G_UPDATE(allowApproximateMatching);
+ G_UPDATE(allowApproximateMatching);
G_UPDATE(fdrAllowTeddy);
- G_UPDATE(fdrAllowFlood);
- G_UPDATE(violetAvoidSuffixes);
- G_UPDATE(violetAvoidWeakInfixes);
- G_UPDATE(violetDoubleCut);
- G_UPDATE(violetExtractStrongLiterals);
- G_UPDATE(violetLiteralChains);
- G_UPDATE(violetDoubleCutLiteralLen);
- G_UPDATE(violetEarlyCleanLiteralLen);
+ G_UPDATE(fdrAllowFlood);
+ G_UPDATE(violetAvoidSuffixes);
+ G_UPDATE(violetAvoidWeakInfixes);
+ G_UPDATE(violetDoubleCut);
+ G_UPDATE(violetExtractStrongLiterals);
+ G_UPDATE(violetLiteralChains);
+ G_UPDATE(violetDoubleCutLiteralLen);
+ G_UPDATE(violetEarlyCleanLiteralLen);
G_UPDATE(puffImproveHead);
G_UPDATE(castleExclusive);
G_UPDATE(mergeSEP);
@@ -279,7 +279,7 @@ void applyGreyOverrides(Grey *g, const string &s) {
G_UPDATE(minRoseLiteralLength);
G_UPDATE(minRoseNetflowLiteralLength);
G_UPDATE(maxRoseNetflowEdges);
- G_UPDATE(maxEditDistance);
+ G_UPDATE(maxEditDistance);
G_UPDATE(minExtBoundedRepeatSize);
G_UPDATE(goughCopyPropagate);
G_UPDATE(goughRegisterAllocate);
@@ -307,15 +307,15 @@ void applyGreyOverrides(Grey *g, const string &s) {
G_UPDATE(miracleHistoryBonus);
G_UPDATE(equivalenceEnable);
G_UPDATE(allowSmallWrite);
- G_UPDATE(allowSmallWriteSheng);
+ G_UPDATE(allowSmallWriteSheng);
G_UPDATE(smallWriteLargestBuffer);
G_UPDATE(smallWriteLargestBufferBad);
G_UPDATE(limitSmallWriteOutfixSize);
- G_UPDATE(smallWriteMaxPatterns);
- G_UPDATE(smallWriteMaxLiterals);
- G_UPDATE(smallWriteMergeBatchSize);
- G_UPDATE(allowTamarama);
- G_UPDATE(tamaChunkSize);
+ G_UPDATE(smallWriteMaxPatterns);
+ G_UPDATE(smallWriteMaxLiterals);
+ G_UPDATE(smallWriteMergeBatchSize);
+ G_UPDATE(allowTamarama);
+ G_UPDATE(tamaChunkSize);
G_UPDATE(limitPatternCount);
G_UPDATE(limitPatternLength);
G_UPDATE(limitGraphVertices);
@@ -332,7 +332,7 @@ void applyGreyOverrides(Grey *g, const string &s) {
G_UPDATE(limitDFASize);
G_UPDATE(limitNFASize);
G_UPDATE(limitLBRSize);
- G_UPDATE(limitApproxMatchingVertices);
+ G_UPDATE(limitApproxMatchingVertices);
#undef G_UPDATE
if (key == "simple_som") {
@@ -353,8 +353,8 @@ void applyGreyOverrides(Grey *g, const string &s) {
g->allowLitHaig = false;
g->allowMcClellan = false;
g->allowPuff = false;
- g->allowLiteral = false;
- g->allowViolet = false;
+ g->allowLiteral = false;
+ g->allowViolet = false;
g->allowSmallLiteralSet = false;
g->roseMasks = false;
done = true;
@@ -370,8 +370,8 @@ void applyGreyOverrides(Grey *g, const string &s) {
g->allowLitHaig = false;
g->allowMcClellan = true;
g->allowPuff = false;
- g->allowLiteral = false;
- g->allowViolet = false;
+ g->allowLiteral = false;
+ g->allowViolet = false;
g->allowSmallLiteralSet = false;
g->roseMasks = false;
done = true;
@@ -387,8 +387,8 @@ void applyGreyOverrides(Grey *g, const string &s) {
g->allowLitHaig = false;
g->allowMcClellan = true;
g->allowPuff = false;
- g->allowLiteral = false;
- g->allowViolet = false;
+ g->allowLiteral = false;
+ g->allowViolet = false;
g->allowSmallLiteralSet = false;
g->roseMasks = false;
done = true;
diff --git a/contrib/libs/hyperscan/src/grey.h b/contrib/libs/hyperscan/src/grey.h
index 4396411ebb1..ed2f845a4b6 100644
--- a/contrib/libs/hyperscan/src/grey.h
+++ b/contrib/libs/hyperscan/src/grey.h
@@ -41,7 +41,7 @@ struct Grey {
bool optimiseComponentTree;
- bool calcComponents;
+ bool calcComponents;
bool performGraphSimplification;
bool prefilterReductions;
bool removeEdgeRedundancy;
@@ -51,31 +51,31 @@ struct Grey {
bool allowLitHaig;
bool allowLbr;
bool allowMcClellan;
- bool allowSheng;
- bool allowMcSheng;
+ bool allowSheng;
+ bool allowMcSheng;
bool allowPuff;
- bool allowLiteral;
- bool allowViolet;
+ bool allowLiteral;
+ bool allowViolet;
bool allowExtendedNFA;
bool allowLimExNFA;
bool allowAnchoredAcyclic;
bool allowSmallLiteralSet;
bool allowCastle;
bool allowDecoratedLiteral;
- bool allowApproximateMatching;
+ bool allowApproximateMatching;
bool allowNoodle;
bool fdrAllowTeddy;
- bool fdrAllowFlood;
-
- u32 violetAvoidSuffixes; /* 0=never, 1=sometimes, 2=always */
- bool violetAvoidWeakInfixes;
- bool violetDoubleCut;
- bool violetExtractStrongLiterals;
- bool violetLiteralChains;
- u32 violetDoubleCutLiteralLen;
- u32 violetEarlyCleanLiteralLen;
-
+ bool fdrAllowFlood;
+
+ u32 violetAvoidSuffixes; /* 0=never, 1=sometimes, 2=always */
+ bool violetAvoidWeakInfixes;
+ bool violetDoubleCut;
+ bool violetExtractStrongLiterals;
+ bool violetLiteralChains;
+ u32 violetDoubleCutLiteralLen;
+ u32 violetEarlyCleanLiteralLen;
+
bool puffImproveHead;
bool castleExclusive; // enable castle mutual exclusion analysis
@@ -110,7 +110,7 @@ struct Grey {
u32 minRoseLiteralLength;
u32 minRoseNetflowLiteralLength;
u32 maxRoseNetflowEdges;
- u32 maxEditDistance;
+ u32 maxEditDistance;
u32 minExtBoundedRepeatSize; /* to be considered for ng_repeat */
@@ -152,18 +152,18 @@ struct Grey {
// SmallWrite engine
bool allowSmallWrite;
- bool allowSmallWriteSheng;
+ bool allowSmallWriteSheng;
u32 smallWriteLargestBuffer; // largest buffer that can be small write
u32 smallWriteLargestBufferBad;// largest buffer that can be small write
u32 limitSmallWriteOutfixSize; //!< max total size of outfix DFAs
- u32 smallWriteMaxPatterns; // only try small writes if fewer patterns
- u32 smallWriteMaxLiterals; // only try small writes if fewer literals
- u32 smallWriteMergeBatchSize; // number of DFAs to merge in a batch
-
- // Tamarama engine
- bool allowTamarama;
- u32 tamaChunkSize; //!< max chunk size for exclusivity analysis in Tamarama
-
+ u32 smallWriteMaxPatterns; // only try small writes if fewer patterns
+ u32 smallWriteMaxLiterals; // only try small writes if fewer literals
+ u32 smallWriteMergeBatchSize; // number of DFAs to merge in a batch
+
+ // Tamarama engine
+ bool allowTamarama;
+ u32 tamaChunkSize; //!< max chunk size for exclusivity analysis in Tamarama
+
enum DumpFlags {
DUMP_NONE = 0,
DUMP_BASICS = 1 << 0, // Dump basic textual data
@@ -204,9 +204,9 @@ struct Grey {
u32 limitDFASize; //!< max size of a DFA (in bytes)
u32 limitNFASize; //!< max size of an NFA (in bytes)
u32 limitLBRSize; //!< max size of an LBR engine (in bytes)
-
- // Approximate matching limits.
- u32 limitApproxMatchingVertices; //!< max number of vertices per graph
+
+ // Approximate matching limits.
+ u32 limitApproxMatchingVertices; //!< max number of vertices per graph
};
#ifndef RELEASE_BUILD
diff --git a/contrib/libs/hyperscan/src/hs.cpp b/contrib/libs/hyperscan/src/hs.cpp
index 76c3547f9d1..eac588891ca 100644
--- a/contrib/libs/hyperscan/src/hs.cpp
+++ b/contrib/libs/hyperscan/src/hs.cpp
@@ -39,13 +39,13 @@
#include "compiler/error.h"
#include "nfagraph/ng.h"
#include "nfagraph/ng_expr_info.h"
-#include "parser/Parser.h"
+#include "parser/Parser.h"
#include "parser/parse_error.h"
#include "parser/prefilter.h"
-#include "parser/unsupported.h"
+#include "parser/unsupported.h"
#include "util/compile_error.h"
#include "util/cpuid_flags.h"
-#include "util/cpuid_inline.h"
+#include "util/cpuid_inline.h"
#include "util/depth.h"
#include "util/popcount.h"
#include "util/target_info.h"
@@ -121,7 +121,7 @@ bool checkMode(unsigned int mode, hs_compile_error **comp_error) {
static
bool checkPlatform(const hs_platform_info *p, hs_compile_error **comp_error) {
static constexpr u32 HS_TUNE_LAST = HS_TUNE_FAMILY_ICX;
- static constexpr u32 HS_CPU_FEATURES_ALL =
+ static constexpr u32 HS_CPU_FEATURES_ALL =
HS_CPU_FEATURES_AVX2 | HS_CPU_FEATURES_AVX512 |
HS_CPU_FEATURES_AVX512VBMI;
@@ -195,14 +195,14 @@ hs_compile_multi_int(const char *const *expressions, const unsigned *flags,
return HS_COMPILER_ERROR;
}
-#if defined(FAT_RUNTIME)
- if (!check_ssse3()) {
- *db = nullptr;
- *comp_error = generateCompileError("Unsupported architecture", -1);
- return HS_ARCH_ERROR;
- }
-#endif
-
+#if defined(FAT_RUNTIME)
+ if (!check_ssse3()) {
+ *db = nullptr;
+ *comp_error = generateCompileError("Unsupported architecture", -1);
+ return HS_ARCH_ERROR;
+ }
+#endif
+
if (!checkMode(mode, comp_error)) {
*db = nullptr;
assert(*comp_error); // set by checkMode.
@@ -229,9 +229,9 @@ hs_compile_multi_int(const char *const *expressions, const unsigned *flags,
target_t target_info = platform ? target_t(*platform)
: get_current_target();
- try {
- CompileContext cc(isStreaming, isVectored, target_info, g);
- NG ng(cc, elements, somPrecision);
+ try {
+ CompileContext cc(isStreaming, isVectored, target_info, g);
+ NG ng(cc, elements, somPrecision);
for (unsigned int i = 0; i < elements; i++) {
// Add this expression to the compiler
@@ -269,7 +269,7 @@ hs_compile_multi_int(const char *const *expressions, const unsigned *flags,
e.hasIndex ? (int)e.index : -1);
return HS_COMPILER_ERROR;
}
- catch (const std::bad_alloc &) {
+ catch (const std::bad_alloc &) {
*db = nullptr;
*comp_error = const_cast<hs_compile_error_t *>(&hs_enomem);
return HS_COMPILER_ERROR;
@@ -409,10 +409,10 @@ hs_compile_lit_multi_int(const char *const *expressions, const unsigned *flags,
} // namespace ue2
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_compile(const char *expression, unsigned flags,
- unsigned mode,
- const hs_platform_info_t *platform,
- hs_database_t **db, hs_compile_error_t **error) {
+hs_error_t HS_CDECL hs_compile(const char *expression, unsigned flags,
+ unsigned mode,
+ const hs_platform_info_t *platform,
+ hs_database_t **db, hs_compile_error_t **error) {
if (expression == nullptr) {
*db = nullptr;
*error = generateCompileError("Invalid parameter: expression is NULL",
@@ -428,25 +428,25 @@ hs_error_t HS_CDECL hs_compile(const char *expression, unsigned flags,
}
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
- const unsigned *flags, const unsigned *ids,
- unsigned elements, unsigned mode,
- const hs_platform_info_t *platform,
- hs_database_t **db,
- hs_compile_error_t **error) {
+hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
+ const unsigned *flags, const unsigned *ids,
+ unsigned elements, unsigned mode,
+ const hs_platform_info_t *platform,
+ hs_database_t **db,
+ hs_compile_error_t **error) {
const hs_expr_ext * const *ext = nullptr; // unused for this call.
return hs_compile_multi_int(expressions, flags, ids, ext, elements, mode,
platform, db, error, Grey());
}
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_compile_ext_multi(const char * const *expressions,
- const unsigned *flags, const unsigned *ids,
- const hs_expr_ext * const *ext,
- unsigned elements, unsigned mode,
- const hs_platform_info_t *platform,
- hs_database_t **db,
- hs_compile_error_t **error) {
+hs_error_t HS_CDECL hs_compile_ext_multi(const char * const *expressions,
+ const unsigned *flags, const unsigned *ids,
+ const hs_expr_ext * const *ext,
+ unsigned elements, unsigned mode,
+ const hs_platform_info_t *platform,
+ hs_database_t **db,
+ hs_compile_error_t **error) {
return hs_compile_multi_int(expressions, flags, ids, ext, elements, mode,
platform, db, error, Grey());
}
@@ -488,21 +488,21 @@ hs_error_t HS_CDECL hs_compile_lit_multi(const char * const *expressions,
static
hs_error_t hs_expression_info_int(const char *expression, unsigned int flags,
- const hs_expr_ext_t *ext, unsigned int mode,
- hs_expr_info_t **info,
+ const hs_expr_ext_t *ext, unsigned int mode,
+ hs_expr_info_t **info,
hs_compile_error_t **error) {
if (!error) {
// nowhere to write an error, but we can still return an error code.
return HS_COMPILER_ERROR;
}
-#if defined(FAT_RUNTIME)
- if (!check_ssse3()) {
- *error = generateCompileError("Unsupported architecture", -1);
- return HS_ARCH_ERROR;
- }
-#endif
-
+#if defined(FAT_RUNTIME)
+ if (!check_ssse3()) {
+ *error = generateCompileError("Unsupported architecture", -1);
+ return HS_ARCH_ERROR;
+ }
+#endif
+
if (!info) {
*error = generateCompileError("Invalid parameter: info is NULL", -1);
return HS_COMPILER_ERROR;
@@ -533,39 +533,39 @@ hs_error_t hs_expression_info_int(const char *expression, unsigned int flags,
}
ReportManager rm(cc.grey);
- ParsedExpression pe(0, expression, flags, 0, ext);
+ ParsedExpression pe(0, expression, flags, 0, ext);
assert(pe.component);
// Apply prefiltering transformations if desired.
- if (pe.expr.prefilter) {
+ if (pe.expr.prefilter) {
prefilterTree(pe.component, ParseMode(flags));
}
- // Expressions containing zero-width assertions and other extended pcre
- // types aren't supported yet. This call will throw a ParseError
- // exception if the component tree contains such a construct.
- checkUnsupported(*pe.component);
-
- pe.component->checkEmbeddedStartAnchor(true);
- pe.component->checkEmbeddedEndAnchor(true);
-
- auto built_expr = buildGraph(rm, cc, pe);
- unique_ptr<NGHolder> &g = built_expr.g;
- ExpressionInfo &expr = built_expr.expr;
-
+ // Expressions containing zero-width assertions and other extended pcre
+ // types aren't supported yet. This call will throw a ParseError
+ // exception if the component tree contains such a construct.
+ checkUnsupported(*pe.component);
+
+ pe.component->checkEmbeddedStartAnchor(true);
+ pe.component->checkEmbeddedEndAnchor(true);
+
+ auto built_expr = buildGraph(rm, cc, pe);
+ unique_ptr<NGHolder> &g = built_expr.g;
+ ExpressionInfo &expr = built_expr.expr;
+
if (!g) {
DEBUG_PRINTF("NFA build failed, but no exception was thrown.\n");
throw ParseError("Internal error.");
}
- fillExpressionInfo(rm, cc, *g, expr, &local_info);
+ fillExpressionInfo(rm, cc, *g, expr, &local_info);
}
catch (const CompileError &e) {
// Compiler error occurred
*error = generateCompileError(e);
return HS_COMPILER_ERROR;
}
- catch (std::bad_alloc &) {
+ catch (std::bad_alloc &) {
*error = const_cast<hs_compile_error_t *>(&hs_enomem);
return HS_COMPILER_ERROR;
}
@@ -587,26 +587,26 @@ hs_error_t hs_expression_info_int(const char *expression, unsigned int flags,
}
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_expression_info(const char *expression,
- unsigned int flags,
- hs_expr_info_t **info,
- hs_compile_error_t **error) {
- return hs_expression_info_int(expression, flags, nullptr, HS_MODE_BLOCK,
- info, error);
-}
-
-extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
- unsigned int flags,
- const hs_expr_ext_t *ext,
- hs_expr_info_t **info,
- hs_compile_error_t **error) {
- return hs_expression_info_int(expression, flags, ext, HS_MODE_BLOCK, info,
+hs_error_t HS_CDECL hs_expression_info(const char *expression,
+ unsigned int flags,
+ hs_expr_info_t **info,
+ hs_compile_error_t **error) {
+ return hs_expression_info_int(expression, flags, nullptr, HS_MODE_BLOCK,
+ info, error);
+}
+
+extern "C" HS_PUBLIC_API
+hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
+ unsigned int flags,
+ const hs_expr_ext_t *ext,
+ hs_expr_info_t **info,
+ hs_compile_error_t **error) {
+ return hs_expression_info_int(expression, flags, ext, HS_MODE_BLOCK, info,
error);
}
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform) {
+hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform) {
if (!platform) {
return HS_INVALID;
}
@@ -620,12 +620,12 @@ hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform) {
}
extern "C" HS_PUBLIC_API
-hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error) {
-#if defined(FAT_RUNTIME)
- if (!check_ssse3()) {
- return HS_ARCH_ERROR;
- }
-#endif
+hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error) {
+#if defined(FAT_RUNTIME)
+ if (!check_ssse3()) {
+ return HS_ARCH_ERROR;
+ }
+#endif
freeCompileError(error);
return HS_SUCCESS;
}
diff --git a/contrib/libs/hyperscan/src/hs_common.h b/contrib/libs/hyperscan/src/hs_common.h
index 78742290171..93dc1fe8a1c 100644
--- a/contrib/libs/hyperscan/src/hs_common.h
+++ b/contrib/libs/hyperscan/src/hs_common.h
@@ -29,11 +29,11 @@
#ifndef HS_COMMON_H_
#define HS_COMMON_H_
-#if defined(_WIN32)
-#define HS_CDECL __cdecl
-#else
-#define HS_CDECL
-#endif
+#if defined(_WIN32)
+#define HS_CDECL __cdecl
+#else
+#define HS_CDECL
+#endif
#include <stdlib.h>
/**
@@ -81,7 +81,7 @@ typedef int hs_error_t;
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_free_database(hs_database_t *db);
+hs_error_t HS_CDECL hs_free_database(hs_database_t *db);
/**
* Serialize a pattern database to a stream of bytes.
@@ -105,8 +105,8 @@ hs_error_t HS_CDECL hs_free_database(hs_database_t *db);
* @ref HS_SUCCESS on success, @ref HS_NOMEM if the byte array cannot be
* allocated, other values may be returned if errors are detected.
*/
-hs_error_t HS_CDECL hs_serialize_database(const hs_database_t *db, char **bytes,
- size_t *length);
+hs_error_t HS_CDECL hs_serialize_database(const hs_database_t *db, char **bytes,
+ size_t *length);
/**
* Reconstruct a pattern database from a stream of bytes previously generated
@@ -134,16 +134,16 @@ hs_error_t HS_CDECL hs_serialize_database(const hs_database_t *db, char **bytes,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
- const size_t length,
- hs_database_t **db);
+hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
+ const size_t length,
+ hs_database_t **db);
/**
* Reconstruct a pattern database from a stream of bytes previously generated
* by @ref hs_serialize_database() at a given memory location.
*
* This function (unlike @ref hs_deserialize_database()) will write the
- * reconstructed database to the memory location given in the @p db parameter.
+ * reconstructed database to the memory location given in the @p db parameter.
* The amount of space required at this location can be determined with the
* @ref hs_serialized_database_size() function.
*
@@ -166,9 +166,9 @@ hs_error_t HS_CDECL hs_deserialize_database(const char *bytes,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
- const size_t length,
- hs_database_t *db);
+hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
+ const size_t length,
+ hs_database_t *db);
/**
* Provides the size of the stream state allocated by a single stream opened
@@ -184,8 +184,8 @@ hs_error_t HS_CDECL hs_deserialize_database_at(const char *bytes,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_stream_size(const hs_database_t *database,
- size_t *stream_size);
+hs_error_t HS_CDECL hs_stream_size(const hs_database_t *database,
+ size_t *stream_size);
/**
* Provides the size of the given database in bytes.
@@ -200,8 +200,8 @@ hs_error_t HS_CDECL hs_stream_size(const hs_database_t *database,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_database_size(const hs_database_t *database,
- size_t *database_size);
+hs_error_t HS_CDECL hs_database_size(const hs_database_t *database,
+ size_t *database_size);
/**
* Utility function for reporting the size that would be required by a
@@ -227,9 +227,9 @@ hs_error_t HS_CDECL hs_database_size(const hs_database_t *database,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_serialized_database_size(const char *bytes,
- const size_t length,
- size_t *deserialized_size);
+hs_error_t HS_CDECL hs_serialized_database_size(const char *bytes,
+ const size_t length,
+ size_t *deserialized_size);
/**
* Utility function providing information about a database.
@@ -246,8 +246,8 @@ hs_error_t HS_CDECL hs_serialized_database_size(const char *bytes,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_database_info(const hs_database_t *database,
- char **info);
+hs_error_t HS_CDECL hs_database_info(const hs_database_t *database,
+ char **info);
/**
* Utility function providing information about a serialized database.
@@ -268,8 +268,8 @@ hs_error_t HS_CDECL hs_database_info(const hs_database_t *database,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_serialized_database_info(const char *bytes,
- size_t length, char **info);
+hs_error_t HS_CDECL hs_serialized_database_info(const char *bytes,
+ size_t length, char **info);
/**
* The type of the callback function that will be used by Hyperscan to allocate
@@ -285,7 +285,7 @@ hs_error_t HS_CDECL hs_serialized_database_info(const char *bytes,
* @return
* A pointer to the region of memory allocated, or NULL on error.
*/
-typedef void *(HS_CDECL *hs_alloc_t)(size_t size);
+typedef void *(HS_CDECL *hs_alloc_t)(size_t size);
/**
* The type of the callback function that will be used by Hyperscan to free
@@ -294,7 +294,7 @@ typedef void *(HS_CDECL *hs_alloc_t)(size_t size);
* @param ptr
* The region of memory to be freed.
*/
-typedef void (HS_CDECL *hs_free_t)(void *ptr);
+typedef void (HS_CDECL *hs_free_t)(void *ptr);
/**
* Set the allocate and free functions used by Hyperscan for allocating
@@ -322,8 +322,8 @@ typedef void (HS_CDECL *hs_free_t)(void *ptr);
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t alloc_func,
- hs_free_t free_func);
+hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t alloc_func,
+ hs_free_t free_func);
/**
* Set the allocate and free functions used by Hyperscan for allocating memory
@@ -355,8 +355,8 @@ hs_error_t HS_CDECL hs_set_allocator(hs_alloc_t alloc_func,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t alloc_func,
- hs_free_t free_func);
+hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t alloc_func,
+ hs_free_t free_func);
/**
* Set the allocate and free functions used by Hyperscan for allocating memory
@@ -382,8 +382,8 @@ hs_error_t HS_CDECL hs_set_database_allocator(hs_alloc_t alloc_func,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t alloc_func,
- hs_free_t free_func);
+hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t alloc_func,
+ hs_free_t free_func);
/**
* Set the allocate and free functions used by Hyperscan for allocating memory
@@ -409,8 +409,8 @@ hs_error_t HS_CDECL hs_set_misc_allocator(hs_alloc_t alloc_func,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t alloc_func,
- hs_free_t free_func);
+hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t alloc_func,
+ hs_free_t free_func);
/**
* Set the allocate and free functions used by Hyperscan for allocating memory
@@ -436,8 +436,8 @@ hs_error_t HS_CDECL hs_set_scratch_allocator(hs_alloc_t alloc_func,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_set_stream_allocator(hs_alloc_t alloc_func,
- hs_free_t free_func);
+hs_error_t HS_CDECL hs_set_stream_allocator(hs_alloc_t alloc_func,
+ hs_free_t free_func);
/**
* Utility function for identifying this release version.
@@ -447,26 +447,26 @@ hs_error_t HS_CDECL hs_set_stream_allocator(hs_alloc_t alloc_func,
* date of the build. It is allocated statically, so it does not need to
* be freed by the caller.
*/
-const char * HS_CDECL hs_version(void);
-
-/**
- * Utility function to test the current system architecture.
- *
- * Hyperscan requires the Supplemental Streaming SIMD Extensions 3 instruction
- * set. This function can be called on any x86 platform to determine if the
- * system provides the required instruction set.
- *
- * This function does not test for more advanced features if Hyperscan has
- * been built for a more specific architecture, for example the AVX2
- * instruction set.
- *
- * @return
- * @ref HS_SUCCESS on success, @ref HS_ARCH_ERROR if system does not
- * support Hyperscan.
- */
-hs_error_t HS_CDECL hs_valid_platform(void);
-
-/**
+const char * HS_CDECL hs_version(void);
+
+/**
+ * Utility function to test the current system architecture.
+ *
+ * Hyperscan requires the Supplemental Streaming SIMD Extensions 3 instruction
+ * set. This function can be called on any x86 platform to determine if the
+ * system provides the required instruction set.
+ *
+ * This function does not test for more advanced features if Hyperscan has
+ * been built for a more specific architecture, for example the AVX2
+ * instruction set.
+ *
+ * @return
+ * @ref HS_SUCCESS on success, @ref HS_ARCH_ERROR if system does not
+ * support Hyperscan.
+ */
+hs_error_t HS_CDECL hs_valid_platform(void);
+
+/**
* @defgroup HS_ERROR hs_error_t values
*
* @{
@@ -479,10 +479,10 @@ hs_error_t HS_CDECL hs_valid_platform(void);
/**
* A parameter passed to this function was invalid.
- *
- * This error is only returned in cases where the function can detect an
- * invalid parameter -- it cannot be relied upon to detect (for example)
- * pointers to freed memory or other invalid data.
+ *
+ * This error is only returned in cases where the function can detect an
+ * invalid parameter -- it cannot be relied upon to detect (for example)
+ * pointers to freed memory or other invalid data.
*/
#define HS_INVALID (-1)
@@ -535,48 +535,48 @@ hs_error_t HS_CDECL hs_valid_platform(void);
*/
#define HS_BAD_ALLOC (-9)
-/**
- * The scratch region was already in use.
- *
- * This error is returned when Hyperscan is able to detect that the scratch
- * region given is already in use by another Hyperscan API call.
- *
- * A separate scratch region, allocated with @ref hs_alloc_scratch() or @ref
- * hs_clone_scratch(), is required for every concurrent caller of the Hyperscan
- * API.
- *
- * For example, this error might be returned when @ref hs_scan() has been
- * called inside a callback delivered by a currently-executing @ref hs_scan()
- * call using the same scratch region.
- *
- * Note: Not all concurrent uses of scratch regions may be detected. This error
- * is intended as a best-effort debugging tool, not a guarantee.
- */
-#define HS_SCRATCH_IN_USE (-10)
-
-/**
- * Unsupported CPU architecture.
- *
- * This error is returned when Hyperscan is able to detect that the current
- * system does not support the required instruction set.
- *
- * At a minimum, Hyperscan requires Supplemental Streaming SIMD Extensions 3
- * (SSSE3).
- */
-#define HS_ARCH_ERROR (-11)
-
-/**
- * Provided buffer was too small.
- *
- * This error indicates that there was insufficient space in the buffer. The
- * call should be repeated with a larger provided buffer.
- *
- * Note: in this situation, it is normal for the amount of space required to be
- * returned in the same manner as the used space would have been returned if the
- * call was successful.
- */
-#define HS_INSUFFICIENT_SPACE (-12)
-
+/**
+ * The scratch region was already in use.
+ *
+ * This error is returned when Hyperscan is able to detect that the scratch
+ * region given is already in use by another Hyperscan API call.
+ *
+ * A separate scratch region, allocated with @ref hs_alloc_scratch() or @ref
+ * hs_clone_scratch(), is required for every concurrent caller of the Hyperscan
+ * API.
+ *
+ * For example, this error might be returned when @ref hs_scan() has been
+ * called inside a callback delivered by a currently-executing @ref hs_scan()
+ * call using the same scratch region.
+ *
+ * Note: Not all concurrent uses of scratch regions may be detected. This error
+ * is intended as a best-effort debugging tool, not a guarantee.
+ */
+#define HS_SCRATCH_IN_USE (-10)
+
+/**
+ * Unsupported CPU architecture.
+ *
+ * This error is returned when Hyperscan is able to detect that the current
+ * system does not support the required instruction set.
+ *
+ * At a minimum, Hyperscan requires Supplemental Streaming SIMD Extensions 3
+ * (SSSE3).
+ */
+#define HS_ARCH_ERROR (-11)
+
+/**
+ * Provided buffer was too small.
+ *
+ * This error indicates that there was insufficient space in the buffer. The
+ * call should be repeated with a larger provided buffer.
+ *
+ * Note: in this situation, it is normal for the amount of space required to be
+ * returned in the same manner as the used space would have been returned if the
+ * call was successful.
+ */
+#define HS_INSUFFICIENT_SPACE (-12)
+
/**
* Unexpected internal error.
*
diff --git a/contrib/libs/hyperscan/src/hs_compile.h b/contrib/libs/hyperscan/src/hs_compile.h
index 4c000bd502a..b318c29db15 100644
--- a/contrib/libs/hyperscan/src/hs_compile.h
+++ b/contrib/libs/hyperscan/src/hs_compile.h
@@ -98,12 +98,12 @@ extern "C"
* The library was unable to allocate temporary storage used during
* compilation time.
*
- * - *Allocator returned misaligned memory*
- *
- * The memory allocator (either malloc() or the allocator set with @ref
- * hs_set_allocator()) did not correctly return memory suitably aligned
- * for the largest representable data type on this platform.
- *
+ * - *Allocator returned misaligned memory*
+ *
+ * The memory allocator (either malloc() or the allocator set with @ref
+ * hs_set_allocator()) did not correctly return memory suitably aligned
+ * for the largest representable data type on this platform.
+ *
* - *Internal error*
*
* An unexpected error occurred: if this error is reported, please contact
@@ -164,28 +164,28 @@ typedef struct hs_platform_info {
/**
* A type containing information related to an expression that is returned by
- * @ref hs_expression_info() or @ref hs_expression_ext_info.
+ * @ref hs_expression_info() or @ref hs_expression_ext_info.
*/
typedef struct hs_expr_info {
/**
* The minimum length in bytes of a match for the pattern.
- *
- * Note: in some cases when using advanced features to suppress matches
- * (such as extended parameters or the @ref HS_FLAG_SINGLEMATCH flag) this
- * may represent a conservative lower bound for the true minimum length of
- * a match.
+ *
+ * Note: in some cases when using advanced features to suppress matches
+ * (such as extended parameters or the @ref HS_FLAG_SINGLEMATCH flag) this
+ * may represent a conservative lower bound for the true minimum length of
+ * a match.
*/
unsigned int min_width;
/**
* The maximum length in bytes of a match for the pattern. If the pattern
- * has an unbounded maximum length, this will be set to the maximum value
- * of an unsigned int (UINT_MAX).
- *
- * Note: in some cases when using advanced features to suppress matches
- * (such as extended parameters or the @ref HS_FLAG_SINGLEMATCH flag) this
- * may represent a conservative upper bound for the true maximum length of
- * a match.
+ * has an unbounded maximum length, this will be set to the maximum value
+ * of an unsigned int (UINT_MAX).
+ *
+ * Note: in some cases when using advanced features to suppress matches
+ * (such as extended parameters or the @ref HS_FLAG_SINGLEMATCH flag) this
+ * may represent a conservative upper bound for the true maximum length of
+ * a match.
*/
unsigned int max_width;
@@ -217,8 +217,8 @@ typedef struct hs_expr_info {
/**
* A structure containing additional parameters related to an expression,
- * passed in at build time to @ref hs_compile_ext_multi() or @ref
- * hs_expression_ext_info.
+ * passed in at build time to @ref hs_compile_ext_multi() or @ref
+ * hs_expression_ext_info.
*
* These parameters allow the set of matches produced by a pattern to be
* constrained at compile time, rather than relying on the application to
@@ -251,20 +251,20 @@ typedef struct hs_expr_ext {
* @ref HS_EXT_FLAG_MIN_LENGTH flag in the hs_expr_ext::flags field.
*/
unsigned long long min_length;
-
- /**
- * Allow patterns to approximately match within this edit distance. To use
- * this parameter, set the @ref HS_EXT_FLAG_EDIT_DISTANCE flag in the
- * hs_expr_ext::flags field.
- */
- unsigned edit_distance;
-
- /**
- * Allow patterns to approximately match within this Hamming distance. To
- * use this parameter, set the @ref HS_EXT_FLAG_HAMMING_DISTANCE flag in the
- * hs_expr_ext::flags field.
- */
- unsigned hamming_distance;
+
+ /**
+ * Allow patterns to approximately match within this edit distance. To use
+ * this parameter, set the @ref HS_EXT_FLAG_EDIT_DISTANCE flag in the
+ * hs_expr_ext::flags field.
+ */
+ unsigned edit_distance;
+
+ /**
+ * Allow patterns to approximately match within this Hamming distance. To
+ * use this parameter, set the @ref HS_EXT_FLAG_HAMMING_DISTANCE flag in the
+ * hs_expr_ext::flags field.
+ */
+ unsigned hamming_distance;
} hs_expr_ext_t;
/**
@@ -285,12 +285,12 @@ typedef struct hs_expr_ext {
/** Flag indicating that the hs_expr_ext::min_length field is used. */
#define HS_EXT_FLAG_MIN_LENGTH 4ULL
-/** Flag indicating that the hs_expr_ext::edit_distance field is used. */
-#define HS_EXT_FLAG_EDIT_DISTANCE 8ULL
-
-/** Flag indicating that the hs_expr_ext::hamming_distance field is used. */
-#define HS_EXT_FLAG_HAMMING_DISTANCE 16ULL
-
+/** Flag indicating that the hs_expr_ext::edit_distance field is used. */
+#define HS_EXT_FLAG_EDIT_DISTANCE 8ULL
+
+/** Flag indicating that the hs_expr_ext::hamming_distance field is used. */
+#define HS_EXT_FLAG_HAMMING_DISTANCE 16ULL
+
/** @} */
/**
@@ -303,9 +303,9 @@ typedef struct hs_expr_ext {
* @param expression
* The NULL-terminated expression to parse. Note that this string must
* represent ONLY the pattern to be matched, with no delimiters or flags;
- * any global flags should be specified with the @p flags argument. For
+ * any global flags should be specified with the @p flags argument. For
* example, the expression `/abc?def/i` should be compiled by providing
- * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
+ * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
* flags.
*
* @param flags
@@ -357,10 +357,10 @@ typedef struct hs_expr_ext {
* HS_COMPILER_ERROR on failure, with details provided in the error
* parameter.
*/
-hs_error_t HS_CDECL hs_compile(const char *expression, unsigned int flags,
- unsigned int mode,
- const hs_platform_info_t *platform,
- hs_database_t **db, hs_compile_error_t **error);
+hs_error_t HS_CDECL hs_compile(const char *expression, unsigned int flags,
+ unsigned int mode,
+ const hs_platform_info_t *platform,
+ hs_database_t **db, hs_compile_error_t **error);
/**
* The multiple regular expression compiler.
@@ -376,8 +376,8 @@ hs_error_t HS_CDECL hs_compile(const char *expression, unsigned int flags,
* hs_compile()) these strings must contain only the pattern to be
* matched, with no delimiters or flags. For example, the expression
* `/abc?def/i` should be compiled by providing `abc?def` as the first
- * string in the @p expressions array, and @ref HS_FLAG_CASELESS as the
- * first value in the @p flags array.
+ * string in the @p expressions array, and @ref HS_FLAG_CASELESS as the
+ * first value in the @p flags array.
*
* @param flags
* Array of flags which modify the behaviour of each expression. Multiple
@@ -436,20 +436,20 @@ hs_error_t HS_CDECL hs_compile(const char *expression, unsigned int flags,
*
* @return
* @ref HS_SUCCESS is returned on successful compilation; @ref
- * HS_COMPILER_ERROR on failure, with details provided in the @p error
+ * HS_COMPILER_ERROR on failure, with details provided in the @p error
* parameter.
*
*/
-hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
- const unsigned int *flags,
- const unsigned int *ids,
- unsigned int elements, unsigned int mode,
- const hs_platform_info_t *platform,
- hs_database_t **db,
- hs_compile_error_t **error);
+hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
+ const unsigned int *flags,
+ const unsigned int *ids,
+ unsigned int elements, unsigned int mode,
+ const hs_platform_info_t *platform,
+ hs_database_t **db,
+ hs_compile_error_t **error);
/**
- * The multiple regular expression compiler with extended parameter support.
+ * The multiple regular expression compiler with extended parameter support.
*
* This function call compiles a group of expressions into a database in the
* same way as @ref hs_compile_multi(), but allows additional parameters to be
@@ -460,8 +460,8 @@ hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
* hs_compile()) these strings must contain only the pattern to be
* matched, with no delimiters or flags. For example, the expression
* `/abc?def/i` should be compiled by providing `abc?def` as the first
- * string in the @p expressions array, and @ref HS_FLAG_CASELESS as the
- * first value in the @p flags array.
+ * string in the @p expressions array, and @ref HS_FLAG_CASELESS as the
+ * first value in the @p flags array.
*
* @param flags
* Array of flags which modify the behaviour of each expression. Multiple
@@ -527,11 +527,11 @@ hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
*
* @return
* @ref HS_SUCCESS is returned on successful compilation; @ref
- * HS_COMPILER_ERROR on failure, with details provided in the @p error
+ * HS_COMPILER_ERROR on failure, with details provided in the @p error
* parameter.
*
*/
-hs_error_t HS_CDECL hs_compile_ext_multi(const char *const *expressions,
+hs_error_t HS_CDECL hs_compile_ext_multi(const char *const *expressions,
const unsigned int *flags,
const unsigned int *ids,
const hs_expr_ext_t *const *ext,
@@ -707,30 +707,30 @@ hs_error_t HS_CDECL hs_compile_lit_multi(const char * const *expressions,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error);
+hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error);
/**
* Utility function providing information about a regular expression. The
* information provided in @ref hs_expr_info_t includes the minimum and maximum
* width of a pattern match.
*
- * Note: successful analysis of an expression with this function does not imply
- * that compilation of the same expression (via @ref hs_compile(), @ref
- * hs_compile_multi() or @ref hs_compile_ext_multi()) would succeed. This
- * function may return @ref HS_SUCCESS for regular expressions that Hyperscan
- * cannot compile.
- *
- * Note: some per-pattern flags (such as @ref HS_FLAG_ALLOWEMPTY, @ref
- * HS_FLAG_SOM_LEFTMOST) are accepted by this call, but as they do not affect
- * the properties returned in the @ref hs_expr_info_t structure, they will not
- * affect the outcome of this function.
- *
+ * Note: successful analysis of an expression with this function does not imply
+ * that compilation of the same expression (via @ref hs_compile(), @ref
+ * hs_compile_multi() or @ref hs_compile_ext_multi()) would succeed. This
+ * function may return @ref HS_SUCCESS for regular expressions that Hyperscan
+ * cannot compile.
+ *
+ * Note: some per-pattern flags (such as @ref HS_FLAG_ALLOWEMPTY, @ref
+ * HS_FLAG_SOM_LEFTMOST) are accepted by this call, but as they do not affect
+ * the properties returned in the @ref hs_expr_info_t structure, they will not
+ * affect the outcome of this function.
+ *
* @param expression
* The NULL-terminated expression to parse. Note that this string must
* represent ONLY the pattern to be matched, with no delimiters or flags;
- * any global flags should be specified with the @p flags argument. For
+ * any global flags should be specified with the @p flags argument. For
* example, the expression `/abc?def/i` should be compiled by providing
- * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
+ * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
* flags.
*
* @param flags
@@ -770,84 +770,84 @@ hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error);
* HS_COMPILER_ERROR on failure, with details provided in the error
* parameter.
*/
-hs_error_t HS_CDECL hs_expression_info(const char *expression,
- unsigned int flags,
- hs_expr_info_t **info,
- hs_compile_error_t **error);
+hs_error_t HS_CDECL hs_expression_info(const char *expression,
+ unsigned int flags,
+ hs_expr_info_t **info,
+ hs_compile_error_t **error);
/**
- * Utility function providing information about a regular expression, with
- * extended parameter support. The information provided in @ref hs_expr_info_t
- * includes the minimum and maximum width of a pattern match.
- *
- * Note: successful analysis of an expression with this function does not imply
- * that compilation of the same expression (via @ref hs_compile(), @ref
- * hs_compile_multi() or @ref hs_compile_ext_multi()) would succeed. This
- * function may return @ref HS_SUCCESS for regular expressions that Hyperscan
- * cannot compile.
- *
- * Note: some per-pattern flags (such as @ref HS_FLAG_ALLOWEMPTY, @ref
- * HS_FLAG_SOM_LEFTMOST) are accepted by this call, but as they do not affect
- * the properties returned in the @ref hs_expr_info_t structure, they will not
- * affect the outcome of this function.
- *
- * @param expression
- * The NULL-terminated expression to parse. Note that this string must
- * represent ONLY the pattern to be matched, with no delimiters or flags;
- * any global flags should be specified with the @p flags argument. For
- * example, the expression `/abc?def/i` should be compiled by providing
- * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
- * flags.
- *
- * @param flags
- * Flags which modify the behaviour of the expression. Multiple flags may
- * be used by ORing them together. Valid values are:
- * - HS_FLAG_CASELESS - Matching will be performed case-insensitively.
- * - HS_FLAG_DOTALL - Matching a `.` will not exclude newlines.
- * - HS_FLAG_MULTILINE - `^` and `$` anchors match any newlines in data.
- * - HS_FLAG_SINGLEMATCH - Only one match will be generated by the
- * expression per stream.
- * - HS_FLAG_ALLOWEMPTY - Allow expressions which can match against an
- * empty string, such as `.*`.
- * - HS_FLAG_UTF8 - Treat this pattern as a sequence of UTF-8 characters.
- * - HS_FLAG_UCP - Use Unicode properties for character classes.
- * - HS_FLAG_PREFILTER - Compile pattern in prefiltering mode.
- * - HS_FLAG_SOM_LEFTMOST - Report the leftmost start of match offset
- * when a match is found.
+ * Utility function providing information about a regular expression, with
+ * extended parameter support. The information provided in @ref hs_expr_info_t
+ * includes the minimum and maximum width of a pattern match.
+ *
+ * Note: successful analysis of an expression with this function does not imply
+ * that compilation of the same expression (via @ref hs_compile(), @ref
+ * hs_compile_multi() or @ref hs_compile_ext_multi()) would succeed. This
+ * function may return @ref HS_SUCCESS for regular expressions that Hyperscan
+ * cannot compile.
+ *
+ * Note: some per-pattern flags (such as @ref HS_FLAG_ALLOWEMPTY, @ref
+ * HS_FLAG_SOM_LEFTMOST) are accepted by this call, but as they do not affect
+ * the properties returned in the @ref hs_expr_info_t structure, they will not
+ * affect the outcome of this function.
+ *
+ * @param expression
+ * The NULL-terminated expression to parse. Note that this string must
+ * represent ONLY the pattern to be matched, with no delimiters or flags;
+ * any global flags should be specified with the @p flags argument. For
+ * example, the expression `/abc?def/i` should be compiled by providing
+ * `abc?def` as the @p expression, and @ref HS_FLAG_CASELESS as the @a
+ * flags.
+ *
+ * @param flags
+ * Flags which modify the behaviour of the expression. Multiple flags may
+ * be used by ORing them together. Valid values are:
+ * - HS_FLAG_CASELESS - Matching will be performed case-insensitively.
+ * - HS_FLAG_DOTALL - Matching a `.` will not exclude newlines.
+ * - HS_FLAG_MULTILINE - `^` and `$` anchors match any newlines in data.
+ * - HS_FLAG_SINGLEMATCH - Only one match will be generated by the
+ * expression per stream.
+ * - HS_FLAG_ALLOWEMPTY - Allow expressions which can match against an
+ * empty string, such as `.*`.
+ * - HS_FLAG_UTF8 - Treat this pattern as a sequence of UTF-8 characters.
+ * - HS_FLAG_UCP - Use Unicode properties for character classes.
+ * - HS_FLAG_PREFILTER - Compile pattern in prefiltering mode.
+ * - HS_FLAG_SOM_LEFTMOST - Report the leftmost start of match offset
+ * when a match is found.
* - HS_FLAG_COMBINATION - Parse the expression in logical combination
* syntax.
* - HS_FLAG_QUIET - Ignore match reporting for this expression. Used for
* the sub-expressions in logical combinations.
- *
- * @param ext
- * A pointer to a filled @ref hs_expr_ext_t structure that defines
- * extended behaviour for this pattern. NULL may be specified if no
- * extended parameters are needed.
- *
- * @param info
- * On success, a pointer to the pattern information will be returned in
- * this parameter, or NULL on failure. This structure is allocated using
- * the allocator supplied in @ref hs_set_allocator() (or malloc() if no
- * allocator was set) and should be freed by the caller.
- *
- * @param error
- * If the call fails, a pointer to a @ref hs_compile_error_t will be
- * returned, providing details of the error condition. The caller is
- * responsible for deallocating the buffer using the @ref
- * hs_free_compile_error() function.
- *
- * @return
- * @ref HS_SUCCESS is returned on successful compilation; @ref
- * HS_COMPILER_ERROR on failure, with details provided in the error
- * parameter.
- */
-hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
- unsigned int flags,
- const hs_expr_ext_t *ext,
- hs_expr_info_t **info,
- hs_compile_error_t **error);
-
-/**
+ *
+ * @param ext
+ * A pointer to a filled @ref hs_expr_ext_t structure that defines
+ * extended behaviour for this pattern. NULL may be specified if no
+ * extended parameters are needed.
+ *
+ * @param info
+ * On success, a pointer to the pattern information will be returned in
+ * this parameter, or NULL on failure. This structure is allocated using
+ * the allocator supplied in @ref hs_set_allocator() (or malloc() if no
+ * allocator was set) and should be freed by the caller.
+ *
+ * @param error
+ * If the call fails, a pointer to a @ref hs_compile_error_t will be
+ * returned, providing details of the error condition. The caller is
+ * responsible for deallocating the buffer using the @ref
+ * hs_free_compile_error() function.
+ *
+ * @return
+ * @ref HS_SUCCESS is returned on successful compilation; @ref
+ * HS_COMPILER_ERROR on failure, with details provided in the error
+ * parameter.
+ */
+hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
+ unsigned int flags,
+ const hs_expr_ext_t *ext,
+ hs_expr_info_t **info,
+ hs_compile_error_t **error);
+
+/**
* Populates the platform information based on the current host.
*
* @param platform
@@ -857,7 +857,7 @@ hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform);
+hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform);
/**
* @defgroup HS_PATTERN_FLAG Pattern flags
@@ -1026,14 +1026,14 @@ hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform);
*/
#define HS_CPU_FEATURES_AVX2 (1ULL << 2)
-/**
- * CPU features flag - Intel(R) Advanced Vector Extensions 512 (Intel(R) AVX512)
- *
- * Setting this flag indicates that the target platform supports AVX512
- * instructions, specifically AVX-512BW. Using AVX512 implies the use of AVX2.
- */
-#define HS_CPU_FEATURES_AVX512 (1ULL << 3)
-
+/**
+ * CPU features flag - Intel(R) Advanced Vector Extensions 512 (Intel(R) AVX512)
+ *
+ * Setting this flag indicates that the target platform supports AVX512
+ * instructions, specifically AVX-512BW. Using AVX512 implies the use of AVX2.
+ */
+#define HS_CPU_FEATURES_AVX512 (1ULL << 3)
+
/**
* CPU features flag - Intel(R) Advanced Vector Extensions 512
* Vector Byte Manipulation Instructions (Intel(R) AVX512VBMI)
@@ -1099,30 +1099,30 @@ hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform);
*/
#define HS_TUNE_FAMILY_BDW 5
-/**
- * Tuning Parameter - Intel(R) microarchitecture code name Skylake
- *
- * This indicates that the compiled database should be tuned for the
- * Skylake microarchitecture.
- */
-#define HS_TUNE_FAMILY_SKL 6
-
-/**
- * Tuning Parameter - Intel(R) microarchitecture code name Skylake Server
- *
- * This indicates that the compiled database should be tuned for the
- * Skylake Server microarchitecture.
- */
-#define HS_TUNE_FAMILY_SKX 7
-
-/**
- * Tuning Parameter - Intel(R) microarchitecture code name Goldmont
- *
- * This indicates that the compiled database should be tuned for the
- * Goldmont microarchitecture.
- */
-#define HS_TUNE_FAMILY_GLM 8
-
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Skylake
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Skylake microarchitecture.
+ */
+#define HS_TUNE_FAMILY_SKL 6
+
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Skylake Server
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Skylake Server microarchitecture.
+ */
+#define HS_TUNE_FAMILY_SKX 7
+
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Goldmont
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Goldmont microarchitecture.
+ */
+#define HS_TUNE_FAMILY_GLM 8
+
/**
* Tuning Parameter - Intel(R) microarchitecture code name Icelake
*
diff --git a/contrib/libs/hyperscan/src/hs_runtime.h b/contrib/libs/hyperscan/src/hs_runtime.h
index bb012a5d077..6d34b6c4847 100644
--- a/contrib/libs/hyperscan/src/hs_runtime.h
+++ b/contrib/libs/hyperscan/src/hs_runtime.h
@@ -101,7 +101,7 @@ typedef struct hs_scratch hs_scratch_t;
* - If the start of match value lies outside this horizon (possible only
* when the SOM_HORIZON value is not @ref HS_MODE_SOM_HORIZON_LARGE),
- * the @p from value will be set to @ref HS_OFFSET_PAST_HORIZON.
+ * the @p from value will be set to @ref HS_OFFSET_PAST_HORIZON.
* - This argument will be set to zero if the Start of Match flag is not
* enabled for the given pattern.
@@ -145,8 +145,8 @@ typedef int (HS_CDECL *match_event_handler)(unsigned int id,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db, unsigned int flags,
- hs_stream_t **stream);
+hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db, unsigned int flags,
+ hs_stream_t **stream);
/**
* Write data to be scanned to the opened stream.
@@ -185,20 +185,20 @@ hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db, unsigned int flags,
* match callback indicated that scanning should stop; other values on
* error.
*/
-hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
- unsigned int length, unsigned int flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent, void *ctxt);
+hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
+ unsigned int length, unsigned int flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent, void *ctxt);
/**
* Close a stream.
*
- * This function completes matching on the given stream and frees the memory
- * associated with the stream state. After this call, the stream pointed to by
- * @p id is invalid and can no longer be used. To reuse the stream state after
- * completion, rather than closing it, the @ref hs_reset_stream function can be
- * used.
- *
+ * This function completes matching on the given stream and frees the memory
+ * associated with the stream state. After this call, the stream pointed to by
+ * @p id is invalid and can no longer be used. To reuse the stream state after
+ * completion, rather than closing it, the @ref hs_reset_stream function can be
+ * used.
+ *
* This function must be called for any stream created with @ref
* hs_open_stream(), even if scanning has been terminated by a non-zero return
* from the match callback function.
@@ -216,7 +216,7 @@ hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
*
* @param scratch
* A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
- * allowed to be NULL only if the @p onEvent callback is also NULL.
+ * allowed to be NULL only if the @p onEvent callback is also NULL.
*
* @param onEvent
* Pointer to a match event callback function. If a NULL pointer is given,
@@ -229,8 +229,8 @@ hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
* @return
* Returns @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
- match_event_handler onEvent, void *ctxt);
+hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
+ match_event_handler onEvent, void *ctxt);
/**
* Reset a stream to an initial state.
@@ -257,7 +257,7 @@ hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
*
* @param scratch
* A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
- * allowed to be NULL only if the @p onEvent callback is also NULL.
+ * allowed to be NULL only if the @p onEvent callback is also NULL.
*
* @param onEvent
* Pointer to a match event callback function. If a NULL pointer is given,
@@ -270,9 +270,9 @@ hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, unsigned int flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent, void *context);
+hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, unsigned int flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent, void *context);
/**
* Duplicate the given stream. The new stream will have the same state as the
@@ -288,12 +288,12 @@ hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, unsigned int flags,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
- const hs_stream_t *from_id);
+hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
+ const hs_stream_t *from_id);
/**
* Duplicate the given 'from' stream state onto the 'to' stream. The 'to' stream
- * will first be reset (reporting any EOD matches if a non-NULL @p onEvent
+ * will first be reset (reporting any EOD matches if a non-NULL @p onEvent
* callback handler is provided).
*
* Note: the 'to' stream and the 'from' stream must be open against the same
@@ -308,7 +308,121 @@ hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
*
* @param scratch
* A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
- * allowed to be NULL only if the @p onEvent callback is also NULL.
+ * allowed to be NULL only if the @p onEvent callback is also NULL.
+ *
+ * @param onEvent
+ * Pointer to a match event callback function. If a NULL pointer is given,
+ * no matches will be returned.
+ *
+ * @param context
+ * The user defined pointer which will be passed to the callback function
+ * when a match occurs.
+ *
+ * @return
+ * @ref HS_SUCCESS on success, other values on failure.
+ */
+hs_error_t HS_CDECL hs_reset_and_copy_stream(hs_stream_t *to_id,
+ const hs_stream_t *from_id,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context);
+
+/**
+ * Creates a compressed representation of the provided stream in the buffer
+ * provided. This compressed representation can be converted back into a stream
+ * state by using @ref hs_expand_stream() or @ref hs_reset_and_expand_stream().
+ * The size of the compressed representation will be placed into @p used_space.
+ *
+ * If there is not sufficient space in the buffer to hold the compressed
+ * representation, @ref HS_INSUFFICIENT_SPACE will be returned and @p used_space
+ * will be populated with the amount of space required.
+ *
+ * Note: this function does not close the provided stream, you may continue to
+ * use the stream or to free it with @ref hs_close_stream().
+ *
+ * @param stream
+ * The stream (as created by @ref hs_open_stream()) to be compressed.
+ *
+ * @param buf
+ * Buffer to write the compressed representation into. Note: if the call is
+ * just being used to determine the amount of space required, it is allowed
+ * to pass NULL here and @p buf_space as 0.
+ *
+ * @param buf_space
+ * The number of bytes in @p buf. If buf_space is too small, the call will
+ * fail with @ref HS_INSUFFICIENT_SPACE.
+ *
+ * @param used_space
+ * Pointer to where the amount of used space will be written to. The used
+ * buffer space is always less than or equal to @p buf_space. If the call
+ * fails with @ref HS_INSUFFICIENT_SPACE, this pointer will be used to
+ * write out the amount of buffer space required.
+ *
+ * @return
+ * @ref HS_SUCCESS on success, @ref HS_INSUFFICIENT_SPACE if the provided
+ * buffer is too small.
+ */
+hs_error_t HS_CDECL hs_compress_stream(const hs_stream_t *stream, char *buf,
+ size_t buf_space, size_t *used_space);
+
+/**
+ * Decompresses a compressed representation created by @ref hs_compress_stream()
+ * into a new stream.
+ *
+ * Note: @p buf must correspond to a complete compressed representation created
+ * by @ref hs_compress_stream() of a stream that was opened against @p db. It is
+ * not always possible to detect misuse of this API and behaviour is undefined
+ * if these properties are not satisfied.
+ *
+ * @param db
+ * The compiled pattern database that the compressed stream was opened
+ * against.
+ *
+ * @param stream
+ * On success, a pointer to the expanded @ref hs_stream_t will be
+ * returned; NULL on failure.
+ *
+ * @param buf
+ * A compressed representation of a stream. These compressed forms are
+ * created by @ref hs_compress_stream().
+ *
+ * @param buf_size
+ * The size in bytes of the compressed representation.
+ *
+ * @return
+ * @ref HS_SUCCESS on success, other values on failure.
+ */
+hs_error_t HS_CDECL hs_expand_stream(const hs_database_t *db,
+ hs_stream_t **stream, const char *buf,
+ size_t buf_size);
+
+/**
+ * Decompresses a compressed representation created by @ref hs_compress_stream()
+ * on top of the 'to' stream. The 'to' stream will first be reset (reporting
+ * any EOD matches if a non-NULL @p onEvent callback handler is provided).
+ *
+ * Note: the 'to' stream must be opened against the same database as the
+ * compressed stream.
+ *
+ * Note: @p buf must correspond to a complete compressed representation created
+ * by @ref hs_compress_stream() of a stream that was opened against @p db. It is
+ * not always possible to detect misuse of this API and behaviour is undefined
+ * if these properties are not satisfied.
+ *
+ * @param to_stream
+ * A pointer to a valid stream state. A pointer to the expanded @ref
+ * hs_stream_t will be returned; NULL on failure.
+ *
+ * @param buf
+ * A compressed representation of a stream. These compressed forms are
+ * created by @ref hs_compress_stream().
+ *
+ * @param buf_size
+ * The size in bytes of the compressed representation.
+ *
+ * @param scratch
+ * A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
+ * allowed to be NULL only if the @p onEvent callback is also NULL.
*
* @param onEvent
* Pointer to a match event callback function. If a NULL pointer is given,
@@ -321,127 +435,13 @@ hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_reset_and_copy_stream(hs_stream_t *to_id,
- const hs_stream_t *from_id,
- hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context);
+hs_error_t HS_CDECL hs_reset_and_expand_stream(hs_stream_t *to_stream,
+ const char *buf, size_t buf_size,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context);
/**
- * Creates a compressed representation of the provided stream in the buffer
- * provided. This compressed representation can be converted back into a stream
- * state by using @ref hs_expand_stream() or @ref hs_reset_and_expand_stream().
- * The size of the compressed representation will be placed into @p used_space.
- *
- * If there is not sufficient space in the buffer to hold the compressed
- * representation, @ref HS_INSUFFICIENT_SPACE will be returned and @p used_space
- * will be populated with the amount of space required.
- *
- * Note: this function does not close the provided stream, you may continue to
- * use the stream or to free it with @ref hs_close_stream().
- *
- * @param stream
- * The stream (as created by @ref hs_open_stream()) to be compressed.
- *
- * @param buf
- * Buffer to write the compressed representation into. Note: if the call is
- * just being used to determine the amount of space required, it is allowed
- * to pass NULL here and @p buf_space as 0.
- *
- * @param buf_space
- * The number of bytes in @p buf. If buf_space is too small, the call will
- * fail with @ref HS_INSUFFICIENT_SPACE.
- *
- * @param used_space
- * Pointer to where the amount of used space will be written to. The used
- * buffer space is always less than or equal to @p buf_space. If the call
- * fails with @ref HS_INSUFFICIENT_SPACE, this pointer will be used to
- * write out the amount of buffer space required.
- *
- * @return
- * @ref HS_SUCCESS on success, @ref HS_INSUFFICIENT_SPACE if the provided
- * buffer is too small.
- */
-hs_error_t HS_CDECL hs_compress_stream(const hs_stream_t *stream, char *buf,
- size_t buf_space, size_t *used_space);
-
-/**
- * Decompresses a compressed representation created by @ref hs_compress_stream()
- * into a new stream.
- *
- * Note: @p buf must correspond to a complete compressed representation created
- * by @ref hs_compress_stream() of a stream that was opened against @p db. It is
- * not always possible to detect misuse of this API and behaviour is undefined
- * if these properties are not satisfied.
- *
- * @param db
- * The compiled pattern database that the compressed stream was opened
- * against.
- *
- * @param stream
- * On success, a pointer to the expanded @ref hs_stream_t will be
- * returned; NULL on failure.
- *
- * @param buf
- * A compressed representation of a stream. These compressed forms are
- * created by @ref hs_compress_stream().
- *
- * @param buf_size
- * The size in bytes of the compressed representation.
- *
- * @return
- * @ref HS_SUCCESS on success, other values on failure.
- */
-hs_error_t HS_CDECL hs_expand_stream(const hs_database_t *db,
- hs_stream_t **stream, const char *buf,
- size_t buf_size);
-
-/**
- * Decompresses a compressed representation created by @ref hs_compress_stream()
- * on top of the 'to' stream. The 'to' stream will first be reset (reporting
- * any EOD matches if a non-NULL @p onEvent callback handler is provided).
- *
- * Note: the 'to' stream must be opened against the same database as the
- * compressed stream.
- *
- * Note: @p buf must correspond to a complete compressed representation created
- * by @ref hs_compress_stream() of a stream that was opened against @p db. It is
- * not always possible to detect misuse of this API and behaviour is undefined
- * if these properties are not satisfied.
- *
- * @param to_stream
- * A pointer to a valid stream state. A pointer to the expanded @ref
- * hs_stream_t will be returned; NULL on failure.
- *
- * @param buf
- * A compressed representation of a stream. These compressed forms are
- * created by @ref hs_compress_stream().
- *
- * @param buf_size
- * The size in bytes of the compressed representation.
- *
- * @param scratch
- * A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
- * allowed to be NULL only if the @p onEvent callback is also NULL.
- *
- * @param onEvent
- * Pointer to a match event callback function. If a NULL pointer is given,
- * no matches will be returned.
- *
- * @param context
- * The user defined pointer which will be passed to the callback function
- * when a match occurs.
- *
- * @return
- * @ref HS_SUCCESS on success, other values on failure.
- */
-hs_error_t HS_CDECL hs_reset_and_expand_stream(hs_stream_t *to_stream,
- const char *buf, size_t buf_size,
- hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context);
-
-/**
* The block (non-streaming) regular expression scanner.
*
* This is the function call in which the actual pattern matching takes place
@@ -476,10 +476,10 @@ hs_error_t HS_CDECL hs_reset_and_expand_stream(hs_stream_t *to_stream,
* match callback indicated that scanning should stop; other values on
* error.
*/
-hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
- unsigned int length, unsigned int flags,
- hs_scratch_t *scratch, match_event_handler onEvent,
- void *context);
+hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
+ unsigned int length, unsigned int flags,
+ hs_scratch_t *scratch, match_event_handler onEvent,
+ void *context);
/**
* The vectored regular expression scanner.
@@ -498,7 +498,7 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
*
* @param count
* Number of data blocks to scan. This should correspond to the size of
- * of the @p data and @p length arrays.
+ * of the @p data and @p length arrays.
*
* @param flags
* Flags modifying the behaviour of this function. This parameter is
@@ -519,12 +519,12 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
* Returns @ref HS_SUCCESS on success; @ref HS_SCAN_TERMINATED if the match
* callback indicated that scanning should stop; other values on error.
*/
-hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
- const char *const *data,
- const unsigned int *length,
- unsigned int count, unsigned int flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent, void *context);
+hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
+ const char *const *data,
+ const unsigned int *length,
+ unsigned int count, unsigned int flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent, void *context);
/**
* Allocate a "scratch" space for use by Hyperscan.
@@ -552,8 +552,8 @@ hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
* allocation fails. Other errors may be returned if invalid parameters
* are specified.
*/
-hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
- hs_scratch_t **scratch);
+hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
+ hs_scratch_t **scratch);
/**
* Allocate a scratch space that is a clone of an existing scratch space.
@@ -573,8 +573,8 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
* @ref HS_SUCCESS on success; @ref HS_NOMEM if the allocation fails.
* Other errors may be returned if invalid parameters are specified.
*/
-hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
- hs_scratch_t **dest);
+hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
+ hs_scratch_t **dest);
/**
* Provides the size of the given scratch space.
@@ -590,8 +590,8 @@ hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch,
- size_t *scratch_size);
+hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch,
+ size_t *scratch_size);
/**
* Free a scratch block previously allocated by @ref hs_alloc_scratch() or @ref
@@ -606,7 +606,7 @@ hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch,
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
-hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch);
+hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch);
/**
* Callback 'from' return value, indicating that the start of this match was
diff --git a/contrib/libs/hyperscan/src/hs_valid_platform.c b/contrib/libs/hyperscan/src/hs_valid_platform.c
index e278740d0cf..59ad3f3ab86 100644
--- a/contrib/libs/hyperscan/src/hs_valid_platform.c
+++ b/contrib/libs/hyperscan/src/hs_valid_platform.c
@@ -1,41 +1,41 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "hs_common.h"
-#include "util/cpuid_flags.h"
-#include "util/cpuid_inline.h"
-
-HS_PUBLIC_API
-hs_error_t HS_CDECL hs_valid_platform(void) {
- /* Hyperscan requires SSSE3, anything else is a bonus */
- if (check_ssse3()) {
- return HS_SUCCESS;
- } else {
- return HS_ARCH_ERROR;
- }
-}
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "hs_common.h"
+#include "util/cpuid_flags.h"
+#include "util/cpuid_inline.h"
+
+HS_PUBLIC_API
+hs_error_t HS_CDECL hs_valid_platform(void) {
+ /* Hyperscan requires SSSE3, anything else is a bonus */
+ if (check_ssse3()) {
+ return HS_SUCCESS;
+ } else {
+ return HS_ARCH_ERROR;
+ }
+}
diff --git a/contrib/libs/hyperscan/src/hs_version.c b/contrib/libs/hyperscan/src/hs_version.c
index e561b2350d2..04cf46f3f6f 100644
--- a/contrib/libs/hyperscan/src/hs_version.c
+++ b/contrib/libs/hyperscan/src/hs_version.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,6 +31,6 @@
#include "hs_version.h"
HS_PUBLIC_API
-const char * HS_CDECL hs_version(void) {
+const char * HS_CDECL hs_version(void) {
return HS_VERSION_STRING;
}
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm.c b/contrib/libs/hyperscan/src/hwlm/hwlm.c
index 666bb808030..8cf585a98ca 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm.c
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@
#include "fdr/fdr.h"
#include "nfa/accel.h"
#include "nfa/shufti.h"
-#include "nfa/truffle.h"
+#include "nfa/truffle.h"
#include "nfa/vermicelli.h"
#include <string.h>
@@ -65,13 +65,13 @@ const u8 *run_hwlm_accel(const union AccelAux *aux, const u8 *ptr,
case ACCEL_SHUFTI:
DEBUG_PRINTF("single shufti\n");
return shuftiExec(aux->shufti.lo, aux->shufti.hi, ptr, end);
- case ACCEL_TRUFFLE:
- DEBUG_PRINTF("truffle\n");
- return truffleExec(aux->truffle.mask1, aux->truffle.mask2, ptr, end);
+ case ACCEL_TRUFFLE:
+ DEBUG_PRINTF("truffle\n");
+ return truffleExec(aux->truffle.mask1, aux->truffle.mask2, ptr, end);
default:
/* no acceleration, fall through and return current ptr */
- DEBUG_PRINTF("no accel; %u\n", (int)aux->accel_type);
- assert(aux->accel_type == ACCEL_NONE);
+ DEBUG_PRINTF("no accel; %u\n", (int)aux->accel_type);
+ assert(aux->accel_type == ACCEL_NONE);
return ptr;
}
}
@@ -170,10 +170,10 @@ void do_accel_streaming(const union AccelAux *aux, const u8 *hbuf, size_t hlen,
}
hwlm_error_t hwlmExec(const struct HWLM *t, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb, struct hs_scratch *scratch,
+ size_t start, HWLMCallback cb, struct hs_scratch *scratch,
hwlm_group_t groups) {
- assert(t);
-
+ assert(t);
+
DEBUG_PRINTF("buf len=%zu, start=%zu, groups=%llx\n", len, start, groups);
if (!groups) {
DEBUG_PRINTF("groups all off\n");
@@ -184,26 +184,26 @@ hwlm_error_t hwlmExec(const struct HWLM *t, const u8 *buf, size_t len,
if (t->type == HWLM_ENGINE_NOOD) {
DEBUG_PRINTF("calling noodExec\n");
- return noodExec(HWLM_C_DATA(t), buf, len, start, cb, scratch);
+ return noodExec(HWLM_C_DATA(t), buf, len, start, cb, scratch);
+ }
+
+ assert(t->type == HWLM_ENGINE_FDR);
+ const union AccelAux *aa = &t->accel0;
+ if ((groups & ~t->accel1_groups) == 0) {
+ DEBUG_PRINTF("using hq accel %hhu\n", t->accel1.accel_type);
+ aa = &t->accel1;
}
-
- assert(t->type == HWLM_ENGINE_FDR);
- const union AccelAux *aa = &t->accel0;
- if ((groups & ~t->accel1_groups) == 0) {
- DEBUG_PRINTF("using hq accel %hhu\n", t->accel1.accel_type);
- aa = &t->accel1;
- }
- do_accel_block(aa, buf, len, &start);
- DEBUG_PRINTF("calling frankie (groups=%08llx, start=%zu)\n", groups, start);
- return fdrExec(HWLM_C_DATA(t), buf, len, start, cb, scratch, groups);
+ do_accel_block(aa, buf, len, &start);
+ DEBUG_PRINTF("calling frankie (groups=%08llx, start=%zu)\n", groups, start);
+ return fdrExec(HWLM_C_DATA(t), buf, len, start, cb, scratch, groups);
}
-hwlm_error_t hwlmExecStreaming(const struct HWLM *t, size_t len, size_t start,
- HWLMCallback cb, struct hs_scratch *scratch,
- hwlm_group_t groups) {
- assert(t);
- assert(scratch);
-
+hwlm_error_t hwlmExecStreaming(const struct HWLM *t, size_t len, size_t start,
+ HWLMCallback cb, struct hs_scratch *scratch,
+ hwlm_group_t groups) {
+ assert(t);
+ assert(scratch);
+
const u8 *hbuf = scratch->core_info.hbuf;
const size_t hlen = scratch->core_info.hlen;
const u8 *buf = scratch->core_info.buf;
@@ -222,21 +222,21 @@ hwlm_error_t hwlmExecStreaming(const struct HWLM *t, size_t len, size_t start,
// If we've been handed a start offset, we can use a block mode scan at
// that offset.
if (start) {
- return noodExec(HWLM_C_DATA(t), buf, len, start, cb, scratch);
+ return noodExec(HWLM_C_DATA(t), buf, len, start, cb, scratch);
} else {
return noodExecStreaming(HWLM_C_DATA(t), hbuf, hlen, buf, len, cb,
- scratch);
+ scratch);
}
}
-
- assert(t->type == HWLM_ENGINE_FDR);
- const union AccelAux *aa = &t->accel0;
- if ((groups & ~t->accel1_groups) == 0) {
- DEBUG_PRINTF("using hq accel %hhu\n", t->accel1.accel_type);
- aa = &t->accel1;
- }
- do_accel_streaming(aa, hbuf, hlen, buf, len, &start);
- DEBUG_PRINTF("calling frankie (groups=%08llx, start=%zu)\n", groups, start);
- return fdrExecStreaming(HWLM_C_DATA(t), hbuf, hlen, buf, len, start, cb,
- scratch, groups);
+
+ assert(t->type == HWLM_ENGINE_FDR);
+ const union AccelAux *aa = &t->accel0;
+ if ((groups & ~t->accel1_groups) == 0) {
+ DEBUG_PRINTF("using hq accel %hhu\n", t->accel1.accel_type);
+ aa = &t->accel1;
+ }
+ do_accel_streaming(aa, hbuf, hlen, buf, len, &start);
+ DEBUG_PRINTF("calling frankie (groups=%08llx, start=%zu)\n", groups, start);
+ return fdrExecStreaming(HWLM_C_DATA(t), hbuf, hlen, buf, len, start, cb,
+ scratch, groups);
}
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm.h b/contrib/libs/hyperscan/src/hwlm/hwlm.h
index 4f21ccf0384..224ecf6bf9f 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm.h
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -71,17 +71,17 @@ typedef hwlm_group_t hwlmcb_rv_t;
* designed for a different architecture). */
#define HWLM_ERROR_UNKNOWN 2
-/** \brief Max length of the literal passed to HWLM. */
-#define HWLM_LITERAL_MAX_LEN 8
-
+/** \brief Max length of the literal passed to HWLM. */
+#define HWLM_LITERAL_MAX_LEN 8
+
struct hs_scratch;
struct HWLM;
/** \brief The type for an HWLM callback.
*
- * This callback receives an end-of-match offset, the ID of the match and
- * the context pointer that was passed into \ref hwlmExec or
- * \ref hwlmExecStreaming.
+ * This callback receives an end-of-match offset, the ID of the match and
+ * the context pointer that was passed into \ref hwlmExec or
+ * \ref hwlmExecStreaming.
*
* A callback return of \ref HWLM_TERMINATE_MATCHING will stop matching.
*
@@ -95,8 +95,8 @@ struct HWLM;
* belonging to the literal which was active at the when the end match location
* was first reached.
*/
-typedef hwlmcb_rv_t (*HWLMCallback)(size_t end, u32 id,
- struct hs_scratch *scratch);
+typedef hwlmcb_rv_t (*HWLMCallback)(size_t end, u32 id,
+ struct hs_scratch *scratch);
/** \brief Match strings in table.
*
@@ -107,36 +107,36 @@ typedef hwlmcb_rv_t (*HWLMCallback)(size_t end, u32 id,
* Returns \ref HWLM_TERMINATED if scanning is cancelled due to the callback
* returning \ref HWLM_TERMINATE_MATCHING.
*
- * \p start is the first offset at which a match may start. Note: match
- * starts may include masks overhanging the main literal.
+ * \p start is the first offset at which a match may start. Note: match
+ * starts may include masks overhanging the main literal.
*
* The underlying engine may choose not to report any match which starts before
* the first possible match of a literal which is in the initial group mask.
*/
hwlm_error_t hwlmExec(const struct HWLM *tab, const u8 *buf, size_t len,
- size_t start, HWLMCallback callback,
- struct hs_scratch *scratch, hwlm_group_t groups);
+ size_t start, HWLMCallback callback,
+ struct hs_scratch *scratch, hwlm_group_t groups);
/** \brief As for \ref hwlmExec, but a streaming case across two buffers.
*
* \p len is the length of the main buffer to be scanned.
*
* \p start is an advisory hint representing the first offset at which a match
- * may start. Some underlying literal matches may not respect it. Note: match
- * starts may include masks overhanging the main literal.
+ * may start. Some underlying literal matches may not respect it. Note: match
+ * starts may include masks overhanging the main literal.
+ *
+ * \p scratch is used to access the history buffer, history length and
+ * the main buffer.
*
- * \p scratch is used to access the history buffer, history length and
- * the main buffer.
- *
* Two buffers/lengths are provided. Matches that occur entirely within
* the history buffer will not be reported by this function. The offsets
* reported for the main buffer are relative to the start of that buffer (a
* match at byte 10 of the main buffer is reported as 10). Matches that start
* in the history buffer will have starts reported with 'negative' values.
*/
-hwlm_error_t hwlmExecStreaming(const struct HWLM *tab, size_t len, size_t start,
- HWLMCallback callback,
- struct hs_scratch *scratch, hwlm_group_t groups);
+hwlm_error_t hwlmExecStreaming(const struct HWLM *tab, size_t len, size_t start,
+ HWLMCallback callback,
+ struct hs_scratch *scratch, hwlm_group_t groups);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm_build.cpp b/contrib/libs/hyperscan/src/hwlm/hwlm_build.cpp
index 2a9b9d79f6b..1b332815290 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm_build.cpp
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm_build.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,24 +29,24 @@
/** \file
* \brief Hamster Wheel Literal Matcher: build code.
*/
-
-#include "hwlm_build.h"
-
+
+#include "hwlm_build.h"
+
#include "grey.h"
#include "hwlm.h"
#include "hwlm_internal.h"
-#include "hwlm_literal.h"
+#include "hwlm_literal.h"
#include "noodle_engine.h"
#include "noodle_build.h"
-#include "scratch.h"
+#include "scratch.h"
#include "ue2common.h"
#include "fdr/fdr_compile.h"
-#include "fdr/fdr_compile_internal.h"
-#include "fdr/fdr_engine_description.h"
-#include "fdr/teddy_engine_description.h"
+#include "fdr/fdr_compile_internal.h"
+#include "fdr/fdr_engine_description.h"
+#include "fdr/teddy_engine_description.h"
#include "util/compile_context.h"
#include "util/compile_error.h"
-#include "util/make_unique.h"
+#include "util/make_unique.h"
#include "util/ue2string.h"
#include <cassert>
@@ -57,27 +57,27 @@ using namespace std;
namespace ue2 {
-HWLMProto::HWLMProto(u8 engType_in, vector<hwlmLiteral> lits_in)
- : engType(engType_in), lits(move(lits_in)) {}
+HWLMProto::HWLMProto(u8 engType_in, vector<hwlmLiteral> lits_in)
+ : engType(engType_in), lits(move(lits_in)) {}
-HWLMProto::HWLMProto(u8 engType_in,
- unique_ptr<FDREngineDescription> eng_in,
- vector<hwlmLiteral> lits_in,
- map<u32, vector<u32>> bucketToLits_in,
- bool make_small_in)
- : engType(engType_in), fdrEng(move(eng_in)), lits(move(lits_in)),
- bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
+HWLMProto::HWLMProto(u8 engType_in,
+ unique_ptr<FDREngineDescription> eng_in,
+ vector<hwlmLiteral> lits_in,
+ map<u32, vector<u32>> bucketToLits_in,
+ bool make_small_in)
+ : engType(engType_in), fdrEng(move(eng_in)), lits(move(lits_in)),
+ bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
-HWLMProto::HWLMProto(u8 engType_in,
- unique_ptr<TeddyEngineDescription> eng_in,
- vector<hwlmLiteral> lits_in,
- map<u32, vector<u32>> bucketToLits_in,
- bool make_small_in)
- : engType(engType_in), teddyEng(move(eng_in)),
- lits(move(lits_in)),
- bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
+HWLMProto::HWLMProto(u8 engType_in,
+ unique_ptr<TeddyEngineDescription> eng_in,
+ vector<hwlmLiteral> lits_in,
+ map<u32, vector<u32>> bucketToLits_in,
+ bool make_small_in)
+ : engType(engType_in), teddyEng(move(eng_in)),
+ lits(move(lits_in)),
+ bucketToLits(move(bucketToLits_in)), make_small(make_small_in) {}
-HWLMProto::~HWLMProto() {}
+HWLMProto::~HWLMProto() {}
static
void dumpLits(UNUSED const vector<hwlmLiteral> &lits) {
@@ -115,55 +115,55 @@ bool isNoodleable(const vector<hwlmLiteral> &lits,
return false;
}
- return true;
-}
-
-bytecode_ptr<HWLM> hwlmBuild(const HWLMProto &proto, const CompileContext &cc,
- UNUSED hwlm_group_t expected_groups) {
- size_t engSize = 0;
- shared_ptr<void> eng;
-
- const auto &lits = proto.lits;
- DEBUG_PRINTF("building table with %zu strings\n", lits.size());
-
- if (proto.engType == HWLM_ENGINE_NOOD) {
- DEBUG_PRINTF("build noodle table\n");
- const hwlmLiteral &lit = lits.front();
- auto noodle = noodBuildTable(lit);
- if (noodle) {
- engSize = noodle.size();
+ return true;
+}
+
+bytecode_ptr<HWLM> hwlmBuild(const HWLMProto &proto, const CompileContext &cc,
+ UNUSED hwlm_group_t expected_groups) {
+ size_t engSize = 0;
+ shared_ptr<void> eng;
+
+ const auto &lits = proto.lits;
+ DEBUG_PRINTF("building table with %zu strings\n", lits.size());
+
+ if (proto.engType == HWLM_ENGINE_NOOD) {
+ DEBUG_PRINTF("build noodle table\n");
+ const hwlmLiteral &lit = lits.front();
+ auto noodle = noodBuildTable(lit);
+ if (noodle) {
+ engSize = noodle.size();
}
- eng = move(noodle);
- } else {
- DEBUG_PRINTF("building a new deal\n");
- auto fdr = fdrBuildTable(proto, cc.grey);
- if (fdr) {
- engSize = fdr.size();
- }
- eng = move(fdr);
+ eng = move(noodle);
+ } else {
+ DEBUG_PRINTF("building a new deal\n");
+ auto fdr = fdrBuildTable(proto, cc.grey);
+ if (fdr) {
+ engSize = fdr.size();
+ }
+ eng = move(fdr);
}
- if (!eng) {
- return nullptr;
+ if (!eng) {
+ return nullptr;
}
- assert(engSize);
- if (engSize > cc.grey.limitLiteralMatcherSize) {
- throw ResourceLimitError();
- }
-
- const size_t hwlm_len = ROUNDUP_CL(sizeof(HWLM)) + engSize;
- auto h = make_zeroed_bytecode_ptr<HWLM>(hwlm_len, 64);
-
- h->type = proto.engType;
- memcpy(HWLM_DATA(h.get()), eng.get(), engSize);
-
- return h;
+ assert(engSize);
+ if (engSize > cc.grey.limitLiteralMatcherSize) {
+ throw ResourceLimitError();
+ }
+
+ const size_t hwlm_len = ROUNDUP_CL(sizeof(HWLM)) + engSize;
+ auto h = make_zeroed_bytecode_ptr<HWLM>(hwlm_len, 64);
+
+ h->type = proto.engType;
+ memcpy(HWLM_DATA(h.get()), eng.get(), engSize);
+
+ return h;
}
-unique_ptr<HWLMProto>
-hwlmBuildProto(vector<hwlmLiteral> &lits, bool make_small,
- const CompileContext &cc) {
+unique_ptr<HWLMProto>
+hwlmBuildProto(vector<hwlmLiteral> &lits, bool make_small,
+ const CompileContext &cc) {
assert(!lits.empty());
dumpLits(lits);
@@ -193,25 +193,25 @@ hwlmBuildProto(vector<hwlmLiteral> &lits, bool make_small,
}
}
- unique_ptr<HWLMProto> proto;
+ unique_ptr<HWLMProto> proto;
DEBUG_PRINTF("building table with %zu strings\n", lits.size());
assert(everyoneHasGroups(lits));
- if (isNoodleable(lits, cc)) {
+ if (isNoodleable(lits, cc)) {
DEBUG_PRINTF("build noodle table\n");
- proto = ue2::make_unique<HWLMProto>(HWLM_ENGINE_NOOD, lits);
+ proto = ue2::make_unique<HWLMProto>(HWLM_ENGINE_NOOD, lits);
} else {
DEBUG_PRINTF("building a new deal\n");
- proto = fdrBuildProto(HWLM_ENGINE_FDR, lits, make_small,
- cc.target_info, cc.grey);
- if (!proto) {
- return nullptr;
+ proto = fdrBuildProto(HWLM_ENGINE_FDR, lits, make_small,
+ cc.target_info, cc.grey);
+ if (!proto) {
+ return nullptr;
}
}
- return proto;
+ return proto;
}
size_t hwlmSize(const HWLM *h) {
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm_build.h b/contrib/libs/hyperscan/src/hwlm/hwlm_build.h
index 6b61cc1f0da..91f227dce4b 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm_build.h
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm_build.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,9 +36,9 @@
#include "hwlm.h"
#include "hwlm_literal.h"
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
-#include <map>
+#include <map>
#include <memory>
#include <vector>
@@ -46,62 +46,62 @@ struct HWLM;
namespace ue2 {
-class FDREngineDescription;
-class TeddyEngineDescription;
+class FDREngineDescription;
+class TeddyEngineDescription;
struct CompileContext;
struct Grey;
-/** \brief Class representing a literal matcher prototype. */
-struct HWLMProto {
- /**
- * \brief Engine type to distinguish noodle from FDR and Teddy.
- */
- u8 engType;
-
- /**
- * \brief FDR engine description.
- */
- std::unique_ptr<FDREngineDescription> fdrEng;
-
- /**
- * \brief Teddy engine description.
- */
- std::unique_ptr<TeddyEngineDescription> teddyEng;
-
- /**
- * \brief HWLM literals passed from Rose.
- */
- std::vector<hwlmLiteral> lits;
-
- /**
- * \brief Bucket assignment info in FDR and Teddy
- */
- std::map<u32, std::vector<u32>> bucketToLits;
-
- /**
- * \brief Flag to optimise matcher for small size from Rose.
- */
- bool make_small = false;
-
- HWLMProto(u8 engType_in, std::vector<hwlmLiteral> lits_in);
-
- HWLMProto(u8 engType_in, std::unique_ptr<FDREngineDescription> eng_in,
- std::vector<hwlmLiteral> lits_in,
- std::map<u32, std::vector<u32>> bucketToLits_in,
- bool make_small_in);
-
- HWLMProto(u8 engType_in, std::unique_ptr<TeddyEngineDescription> eng_in,
- std::vector<hwlmLiteral> lits_in,
- std::map<u32, std::vector<u32>> bucketToLits_in,
- bool make_small_in);
-
- ~HWLMProto();
+/** \brief Class representing a literal matcher prototype. */
+struct HWLMProto {
+ /**
+ * \brief Engine type to distinguish noodle from FDR and Teddy.
+ */
+ u8 engType;
+
+ /**
+ * \brief FDR engine description.
+ */
+ std::unique_ptr<FDREngineDescription> fdrEng;
+
+ /**
+ * \brief Teddy engine description.
+ */
+ std::unique_ptr<TeddyEngineDescription> teddyEng;
+
+ /**
+ * \brief HWLM literals passed from Rose.
+ */
+ std::vector<hwlmLiteral> lits;
+
+ /**
+ * \brief Bucket assignment info in FDR and Teddy
+ */
+ std::map<u32, std::vector<u32>> bucketToLits;
+
+ /**
+ * \brief Flag to optimise matcher for small size from Rose.
+ */
+ bool make_small = false;
+
+ HWLMProto(u8 engType_in, std::vector<hwlmLiteral> lits_in);
+
+ HWLMProto(u8 engType_in, std::unique_ptr<FDREngineDescription> eng_in,
+ std::vector<hwlmLiteral> lits_in,
+ std::map<u32, std::vector<u32>> bucketToLits_in,
+ bool make_small_in);
+
+ HWLMProto(u8 engType_in, std::unique_ptr<TeddyEngineDescription> eng_in,
+ std::vector<hwlmLiteral> lits_in,
+ std::map<u32, std::vector<u32>> bucketToLits_in,
+ bool make_small_in);
+
+ ~HWLMProto();
};
/** \brief Build an \ref HWLM literal matcher runtime structure for a group of
* literals.
*
- * \param proto Literal matcher prototype.
+ * \param proto Literal matcher prototype.
* \param cc Compile context.
* \param expected_groups FIXME: document me!
*
@@ -109,13 +109,13 @@ struct HWLMProto {
* may result in a nullptr return value, or a std::bad_alloc exception being
* thrown.
*/
-bytecode_ptr<HWLM> hwlmBuild(const HWLMProto &proto, const CompileContext &cc,
- hwlm_group_t expected_groups = HWLM_ALL_GROUPS);
+bytecode_ptr<HWLM> hwlmBuild(const HWLMProto &proto, const CompileContext &cc,
+ hwlm_group_t expected_groups = HWLM_ALL_GROUPS);
+
+std::unique_ptr<HWLMProto>
+hwlmBuildProto(std::vector<hwlmLiteral> &lits, bool make_small,
+ const CompileContext &cc);
-std::unique_ptr<HWLMProto>
-hwlmBuildProto(std::vector<hwlmLiteral> &lits, bool make_small,
- const CompileContext &cc);
-
/**
* Returns an estimate of the number of repeated characters on the end of a
* literal that will make a literal set of size \a numLiterals suffer
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm_literal.cpp b/contrib/libs/hyperscan/src/hwlm/hwlm_literal.cpp
index baf774d35d9..692f7c6c0e4 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm_literal.cpp
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm_literal.cpp
@@ -34,7 +34,7 @@
#include "util/compare.h" // for ourisalpha
#include "util/ue2string.h" // for escapeString
-#include <algorithm>
+#include <algorithm>
#include <iomanip>
#include <sstream>
@@ -86,21 +86,21 @@ hwlmLiteral::hwlmLiteral(const std::string &s_in, bool nocase_in,
const vector<u8> &msk_in, const vector<u8> &cmp_in)
: s(s_in), id(id_in), nocase(nocase_in), noruns(noruns_in),
groups(groups_in), msk(msk_in), cmp(cmp_in) {
- assert(s.size() <= HWLM_LITERAL_MAX_LEN);
+ assert(s.size() <= HWLM_LITERAL_MAX_LEN);
assert(msk.size() <= HWLM_MASKLEN);
assert(msk.size() == cmp.size());
- // If we've been handled a nocase literal, all letter characters must be
- // upper-case.
- if (nocase) {
- upperString(s);
- }
-
- DEBUG_PRINTF("literal '%s'%s, msk=%s, cmp=%s\n", escapeString(s).c_str(),
- nocase ? " (nocase)" : "", dumpMask(msk).c_str(),
+ // If we've been handled a nocase literal, all letter characters must be
+ // upper-case.
+ if (nocase) {
+ upperString(s);
+ }
+
+ DEBUG_PRINTF("literal '%s'%s, msk=%s, cmp=%s\n", escapeString(s).c_str(),
+ nocase ? " (nocase)" : "", dumpMask(msk).c_str(),
dumpMask(cmp).c_str());
-
+
// Mask and compare vectors MUST be the same size.
assert(msk.size() == cmp.size());
@@ -108,7 +108,7 @@ hwlmLiteral::hwlmLiteral(const std::string &s_in, bool nocase_in,
assert(maskIsConsistent(s, nocase, msk, cmp));
// In the name of good hygiene, zap msk/cmp if msk is all zeroes.
- if (all_of(begin(msk), end(msk), [](u8 val) { return val == 0; })) {
+ if (all_of(begin(msk), end(msk), [](u8 val) { return val == 0; })) {
msk.clear();
cmp.clear();
}
diff --git a/contrib/libs/hyperscan/src/hwlm/hwlm_literal.h b/contrib/libs/hyperscan/src/hwlm/hwlm_literal.h
index 6d709157faa..598de81471e 100644
--- a/contrib/libs/hyperscan/src/hwlm/hwlm_literal.h
+++ b/contrib/libs/hyperscan/src/hwlm/hwlm_literal.h
@@ -37,7 +37,7 @@
#include "ue2common.h"
#include <string>
-#include <tuple>
+#include <tuple>
#include <vector>
namespace ue2 {
@@ -45,8 +45,8 @@ namespace ue2 {
/** \brief Max length of the hwlmLiteral::msk and hwlmLiteral::cmp vectors. */
#define HWLM_MASKLEN 8
-#define INVALID_LIT_ID ~0U
-
+#define INVALID_LIT_ID ~0U
+
/** \brief Class representing a literal, fed to \ref hwlmBuild. */
struct hwlmLiteral {
std::string s; //!< \brief The literal itself.
@@ -66,21 +66,21 @@ struct hwlmLiteral {
* can be quashed by the literal matcher. */
bool noruns;
- /** \brief included literal id. */
- u32 included_id = INVALID_LIT_ID;
-
- /** \brief Squash mask for FDR's confirm mask for included literals.
- *
- * In FDR confirm, if we have included literal in another bucket,
- * we can use this mask to squash the bit for the bucket in FDR confirm
- * mask and then run programs of included literal directly and avoid
- * confirm work.
- *
- * This value is calculated in FDR compile code once bucket assignment is
- * completed
- */
- u8 squash = 0;
-
+ /** \brief included literal id. */
+ u32 included_id = INVALID_LIT_ID;
+
+ /** \brief Squash mask for FDR's confirm mask for included literals.
+ *
+ * In FDR confirm, if we have included literal in another bucket,
+ * we can use this mask to squash the bit for the bucket in FDR confirm
+ * mask and then run programs of included literal directly and avoid
+ * confirm work.
+ *
+ * This value is calculated in FDR compile code once bucket assignment is
+ * completed
+ */
+ u8 squash = 0;
+
/** \brief Set of groups that literal belongs to.
*
* Use \ref HWLM_ALL_GROUPS for a literal that could match regardless of
@@ -120,27 +120,27 @@ struct hwlmLiteral {
hwlmLiteral(const std::string &s_in, bool nocase_in, bool noruns_in,
u32 id_in, hwlm_group_t groups_in,
const std::vector<u8> &msk_in, const std::vector<u8> &cmp_in);
-
+
/** \brief Simple constructor: no group information, no msk/cmp.
*
* This constructor is only used in internal unit test. */
- hwlmLiteral(const std::string &s_in, bool nocase_in, u32 id_in)
- : hwlmLiteral(s_in, nocase_in, false, id_in, HWLM_ALL_GROUPS, {}, {}) {}
+ hwlmLiteral(const std::string &s_in, bool nocase_in, u32 id_in)
+ : hwlmLiteral(s_in, nocase_in, false, id_in, HWLM_ALL_GROUPS, {}, {}) {}
};
-inline
-bool operator<(const hwlmLiteral &a, const hwlmLiteral &b) {
- return std::tie(a.id, a.s, a.nocase, a.noruns, a.groups, a.msk, a.cmp) <
- std::tie(b.id, b.s, b.nocase, b.noruns, b.groups, b.msk, b.cmp);
-}
-
-inline
-bool operator==(const hwlmLiteral &a, const hwlmLiteral &b) {
- return a.id == b.id && a.s == b.s && a.nocase == b.nocase &&
- a.noruns == b.noruns && a.groups == b.groups && a.msk == b.msk &&
- a.cmp == b.cmp;
-}
-
+inline
+bool operator<(const hwlmLiteral &a, const hwlmLiteral &b) {
+ return std::tie(a.id, a.s, a.nocase, a.noruns, a.groups, a.msk, a.cmp) <
+ std::tie(b.id, b.s, b.nocase, b.noruns, b.groups, b.msk, b.cmp);
+}
+
+inline
+bool operator==(const hwlmLiteral &a, const hwlmLiteral &b) {
+ return a.id == b.id && a.s == b.s && a.nocase == b.nocase &&
+ a.noruns == b.noruns && a.groups == b.groups && a.msk == b.msk &&
+ a.cmp == b.cmp;
+}
+
/**
* Consistency test; returns false if the given msk/cmp test can never match
* the literal string s.
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_build.cpp b/contrib/libs/hyperscan/src/hwlm/noodle_build.cpp
index 4bd3af01035..a0128d0ad78 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_build.cpp
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_build.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,53 +26,53 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Noodle literal matcher: build code.
*/
#include "noodle_build.h"
-
-#include "hwlm_literal.h"
+
+#include "hwlm_literal.h"
#include "noodle_internal.h"
-#include "util/bitutils.h"
+#include "util/bitutils.h"
#include "util/compare.h"
#include "util/verify_types.h"
-#include "ue2common.h"
+#include "ue2common.h"
+
+#include <cstring> // for memcpy
+#include <vector>
+
+using std::vector;
-#include <cstring> // for memcpy
-#include <vector>
-
-using std::vector;
-
namespace ue2 {
static
-u64a make_u64a_mask(const vector<u8> &v) {
- assert(v.size() <= sizeof(u64a));
- if (v.size() > sizeof(u64a)) {
- throw std::exception();
- }
-
- u64a mask = 0;
- size_t len = v.size();
- unsigned char *m = (unsigned char *)&mask;
- DEBUG_PRINTF("making mask len %zu\n", len);
- memcpy(m, &v[0], len);
- return mask;
-}
-
-static
-size_t findNoodFragOffset(const hwlmLiteral &lit) {
- const auto &s = lit.s;
- const size_t len = lit.s.length();
-
+u64a make_u64a_mask(const vector<u8> &v) {
+ assert(v.size() <= sizeof(u64a));
+ if (v.size() > sizeof(u64a)) {
+ throw std::exception();
+ }
+
+ u64a mask = 0;
+ size_t len = v.size();
+ unsigned char *m = (unsigned char *)&mask;
+ DEBUG_PRINTF("making mask len %zu\n", len);
+ memcpy(m, &v[0], len);
+ return mask;
+}
+
+static
+size_t findNoodFragOffset(const hwlmLiteral &lit) {
+ const auto &s = lit.s;
+ const size_t len = lit.s.length();
+
size_t offset = 0;
for (size_t i = 0; i + 1 < len; i++) {
int diff = 0;
- const char c = s[i];
- const char d = s[i + 1];
- if (lit.nocase && ourisalpha(c)) {
+ const char c = s[i];
+ const char d = s[i + 1];
+ if (lit.nocase && ourisalpha(c)) {
diff = (mytoupper(c) != mytoupper(d));
} else {
diff = (c != d);
@@ -85,60 +85,60 @@ size_t findNoodFragOffset(const hwlmLiteral &lit) {
return offset;
}
-bytecode_ptr<noodTable> noodBuildTable(const hwlmLiteral &lit) {
- const auto &s = lit.s;
-
- size_t mask_len = std::max(s.length(), lit.msk.size());
- DEBUG_PRINTF("mask is %zu bytes\n", lit.msk.size());
- assert(mask_len <= 8);
- assert(lit.msk.size() == lit.cmp.size());
-
- vector<u8> n_msk(mask_len);
- vector<u8> n_cmp(mask_len);
-
- for (unsigned i = mask_len - lit.msk.size(), j = 0; i < mask_len;
- i++, j++) {
- DEBUG_PRINTF("m[%u] %hhx c[%u] %hhx\n", i, lit.msk[j], i, lit.cmp[j]);
- n_msk[i] = lit.msk[j];
- n_cmp[i] = lit.cmp[j];
- }
-
- size_t s_off = mask_len - s.length();
- for (unsigned i = s_off; i < mask_len; i++) {
- u8 c = s[i - s_off];
- u8 si_msk = lit.nocase && ourisalpha(c) ? (u8)CASE_CLEAR : (u8)0xff;
- n_msk[i] |= si_msk;
- n_cmp[i] |= c & si_msk;
- assert((n_cmp[i] & si_msk) == c);
- DEBUG_PRINTF("m[%u] %hhx c[%u] %hhx '%c'\n", i, n_msk[i], i, n_cmp[i],
- ourisprint(c) ? (char)c : '.');
- }
-
- auto n = make_zeroed_bytecode_ptr<noodTable>(sizeof(noodTable));
+bytecode_ptr<noodTable> noodBuildTable(const hwlmLiteral &lit) {
+ const auto &s = lit.s;
+
+ size_t mask_len = std::max(s.length(), lit.msk.size());
+ DEBUG_PRINTF("mask is %zu bytes\n", lit.msk.size());
+ assert(mask_len <= 8);
+ assert(lit.msk.size() == lit.cmp.size());
+
+ vector<u8> n_msk(mask_len);
+ vector<u8> n_cmp(mask_len);
+
+ for (unsigned i = mask_len - lit.msk.size(), j = 0; i < mask_len;
+ i++, j++) {
+ DEBUG_PRINTF("m[%u] %hhx c[%u] %hhx\n", i, lit.msk[j], i, lit.cmp[j]);
+ n_msk[i] = lit.msk[j];
+ n_cmp[i] = lit.cmp[j];
+ }
+
+ size_t s_off = mask_len - s.length();
+ for (unsigned i = s_off; i < mask_len; i++) {
+ u8 c = s[i - s_off];
+ u8 si_msk = lit.nocase && ourisalpha(c) ? (u8)CASE_CLEAR : (u8)0xff;
+ n_msk[i] |= si_msk;
+ n_cmp[i] |= c & si_msk;
+ assert((n_cmp[i] & si_msk) == c);
+ DEBUG_PRINTF("m[%u] %hhx c[%u] %hhx '%c'\n", i, n_msk[i], i, n_cmp[i],
+ ourisprint(c) ? (char)c : '.');
+ }
+
+ auto n = make_zeroed_bytecode_ptr<noodTable>(sizeof(noodTable));
assert(n);
- DEBUG_PRINTF("size of nood %zu\n", sizeof(noodTable));
-
- size_t key_offset = findNoodFragOffset(lit);
-
- n->id = lit.id;
- n->single = s.length() == 1 ? 1 : 0;
- n->key_offset = verify_u8(s.length() - key_offset);
- n->nocase = lit.nocase ? 1 : 0;
- n->key0 = s[key_offset];
- if (n->single) {
- n->key1 = 0;
- } else {
- n->key1 = s[key_offset + 1];
- }
- n->msk = make_u64a_mask(n_msk);
- n->cmp = make_u64a_mask(n_cmp);
- n->msk_len = mask_len;
+ DEBUG_PRINTF("size of nood %zu\n", sizeof(noodTable));
+
+ size_t key_offset = findNoodFragOffset(lit);
+
+ n->id = lit.id;
+ n->single = s.length() == 1 ? 1 : 0;
+ n->key_offset = verify_u8(s.length() - key_offset);
+ n->nocase = lit.nocase ? 1 : 0;
+ n->key0 = s[key_offset];
+ if (n->single) {
+ n->key1 = 0;
+ } else {
+ n->key1 = s[key_offset + 1];
+ }
+ n->msk = make_u64a_mask(n_msk);
+ n->cmp = make_u64a_mask(n_cmp);
+ n->msk_len = mask_len;
return n;
}
-size_t noodSize(const noodTable *) {
- return sizeof(noodTable);
+size_t noodSize(const noodTable *) {
+ return sizeof(noodTable);
}
} // namespace ue2
@@ -150,17 +150,17 @@ namespace ue2 {
void noodPrintStats(const noodTable *n, FILE *f) {
fprintf(f, "Noodle table\n");
- fprintf(f, "Key Offset: %u\n", n->key_offset);
- fprintf(f, "Msk: %llx Cmp: %llx MskLen %u\n",
- n->msk >> 8 * (8 - n->msk_len), n->cmp >> 8 * (8 - n->msk_len),
- n->msk_len);
+ fprintf(f, "Key Offset: %u\n", n->key_offset);
+ fprintf(f, "Msk: %llx Cmp: %llx MskLen %u\n",
+ n->msk >> 8 * (8 - n->msk_len), n->cmp >> 8 * (8 - n->msk_len),
+ n->msk_len);
fprintf(f, "String: ");
- for (u32 i = 0; i < n->msk_len; i++) {
- const u8 *m = (const u8 *)&n->cmp;
- if (isgraph(m[i]) && m[i] != '\\') {
- fprintf(f, "%c", m[i]);
+ for (u32 i = 0; i < n->msk_len; i++) {
+ const u8 *m = (const u8 *)&n->cmp;
+ if (isgraph(m[i]) && m[i] != '\\') {
+ fprintf(f, "%c", m[i]);
} else {
- fprintf(f, "\\x%02hhx", m[i]);
+ fprintf(f, "\\x%02hhx", m[i]);
}
}
fprintf(f, "\n");
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_build.h b/contrib/libs/hyperscan/src/hwlm/noodle_build.h
index c721e7485f5..b5725f0827a 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_build.h
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_build.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,20 +30,20 @@
* \brief Noodle literal matcher: build code.
*/
-#ifndef NOODLE_BUILD_H
-#define NOODLE_BUILD_H
+#ifndef NOODLE_BUILD_H
+#define NOODLE_BUILD_H
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
struct noodTable;
namespace ue2 {
-struct hwlmLiteral;
-
+struct hwlmLiteral;
+
/** \brief Construct a Noodle matcher for the given literal. */
-bytecode_ptr<noodTable> noodBuildTable(const hwlmLiteral &lit);
+bytecode_ptr<noodTable> noodBuildTable(const hwlmLiteral &lit);
size_t noodSize(const noodTable *n);
@@ -61,5 +61,5 @@ void noodPrintStats(const noodTable *n, FILE *f);
#endif // DUMP_SUPPORT
-#endif /* NOODLE_BUILD_H */
+#endif /* NOODLE_BUILD_H */
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_engine.c b/contrib/libs/hyperscan/src/hwlm/noodle_engine.c
index 5ecbee679af..d4f6902a2d8 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_engine.c
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_engine.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,15 +32,15 @@
#include "hwlm.h"
#include "noodle_engine.h"
#include "noodle_internal.h"
-#include "scratch.h"
+#include "scratch.h"
#include "ue2common.h"
-#include "util/arch.h"
+#include "util/arch.h"
#include "util/bitutils.h"
#include "util/compare.h"
-#include "util/intrinsics.h"
-#include "util/join.h"
+#include "util/intrinsics.h"
+#include "util/join.h"
#include "util/masked_move.h"
-#include "util/partial_store.h"
+#include "util/partial_store.h"
#include "util/simd_utils.h"
#include <ctype.h>
@@ -51,28 +51,28 @@
struct cb_info {
HWLMCallback cb; //!< callback function called on match
u32 id; //!< ID to pass to callback on match
- struct hs_scratch *scratch; //!< scratch to pass to callback
+ struct hs_scratch *scratch; //!< scratch to pass to callback
size_t offsetAdj; //!< used in streaming mode
};
-#if defined(HAVE_AVX512)
-#define CHUNKSIZE 64
-#define MASK_TYPE m512
-#define Z_BITS 64
-#define Z_TYPE u64a
-#elif defined(HAVE_AVX2)
-#define CHUNKSIZE 32
-#define MASK_TYPE m256
-#define Z_BITS 32
-#define Z_TYPE u32
-#else
-#define CHUNKSIZE 16
-#define MASK_TYPE m128
-#define Z_BITS 32
-#define Z_TYPE u32
-#endif
-
-
+#if defined(HAVE_AVX512)
+#define CHUNKSIZE 64
+#define MASK_TYPE m512
+#define Z_BITS 64
+#define Z_TYPE u64a
+#elif defined(HAVE_AVX2)
+#define CHUNKSIZE 32
+#define MASK_TYPE m256
+#define Z_BITS 32
+#define Z_TYPE u32
+#else
+#define CHUNKSIZE 16
+#define MASK_TYPE m128
+#define Z_BITS 32
+#define Z_TYPE u32
+#endif
+
+
#define RETURN_IF_TERMINATED(x) \
{ \
if ((x) == HWLM_TERMINATED) { \
@@ -83,10 +83,10 @@ struct cb_info {
#define SINGLE_ZSCAN() \
do { \
while (unlikely(z)) { \
- Z_TYPE pos = JOIN(findAndClearLSB_, Z_BITS)(&z); \
+ Z_TYPE pos = JOIN(findAndClearLSB_, Z_BITS)(&z); \
size_t matchPos = d - buf + pos; \
- DEBUG_PRINTF("match pos %zu\n", matchPos); \
- hwlmcb_rv_t rv = final(n, buf, len, 1, cbi, matchPos); \
+ DEBUG_PRINTF("match pos %zu\n", matchPos); \
+ hwlmcb_rv_t rv = final(n, buf, len, 1, cbi, matchPos); \
RETURN_IF_TERMINATED(rv); \
} \
} while (0)
@@ -94,10 +94,10 @@ struct cb_info {
#define DOUBLE_ZSCAN() \
do { \
while (unlikely(z)) { \
- Z_TYPE pos = JOIN(findAndClearLSB_, Z_BITS)(&z); \
+ Z_TYPE pos = JOIN(findAndClearLSB_, Z_BITS)(&z); \
size_t matchPos = d - buf + pos - 1; \
- DEBUG_PRINTF("match pos %zu\n", matchPos); \
- hwlmcb_rv_t rv = final(n, buf, len, 0, cbi, matchPos); \
+ DEBUG_PRINTF("match pos %zu\n", matchPos); \
+ hwlmcb_rv_t rv = final(n, buf, len, 0, cbi, matchPos); \
RETURN_IF_TERMINATED(rv); \
} \
} while (0)
@@ -111,37 +111,37 @@ u8 caseClear8(u8 x, bool noCase) {
// is used only for single chars with case insensitivity used correctly,
// so it can go straight to the callback if we get this far.
static really_inline
-hwlm_error_t final(const struct noodTable *n, const u8 *buf, UNUSED size_t len,
- char single, const struct cb_info *cbi, size_t pos) {
- if (single) {
- if (n->msk_len == 1) {
- goto match;
+hwlm_error_t final(const struct noodTable *n, const u8 *buf, UNUSED size_t len,
+ char single, const struct cb_info *cbi, size_t pos) {
+ if (single) {
+ if (n->msk_len == 1) {
+ goto match;
}
}
- assert(len >= n->msk_len);
- u64a v =
- partial_load_u64a(buf + pos + n->key_offset - n->msk_len, n->msk_len);
- DEBUG_PRINTF("v %016llx msk %016llx cmp %016llx\n", v, n->msk, n->cmp);
- if ((v & n->msk) != n->cmp) {
- /* mask didn't match */
- return HWLM_SUCCESS;
- }
-
-match:
- pos -= cbi->offsetAdj;
- DEBUG_PRINTF("match @ %zu\n", pos + n->key_offset);
- hwlmcb_rv_t rv = cbi->cb(pos + n->key_offset - 1, cbi->id, cbi->scratch);
+ assert(len >= n->msk_len);
+ u64a v =
+ partial_load_u64a(buf + pos + n->key_offset - n->msk_len, n->msk_len);
+ DEBUG_PRINTF("v %016llx msk %016llx cmp %016llx\n", v, n->msk, n->cmp);
+ if ((v & n->msk) != n->cmp) {
+ /* mask didn't match */
+ return HWLM_SUCCESS;
+ }
+
+match:
+ pos -= cbi->offsetAdj;
+ DEBUG_PRINTF("match @ %zu\n", pos + n->key_offset);
+ hwlmcb_rv_t rv = cbi->cb(pos + n->key_offset - 1, cbi->id, cbi->scratch);
if (rv == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATED;
}
return HWLM_SUCCESS;
}
-#if defined(HAVE_AVX512)
-#define CHUNKSIZE 64
-#define MASK_TYPE m512
-#include "noodle_engine_avx512.c"
-#elif defined(HAVE_AVX2)
+#if defined(HAVE_AVX512)
+#define CHUNKSIZE 64
+#define MASK_TYPE m512
+#include "noodle_engine_avx512.c"
+#elif defined(HAVE_AVX2)
#define CHUNKSIZE 32
#define MASK_TYPE m256
#include "noodle_engine_avx2.c"
@@ -152,43 +152,43 @@ match:
#endif
static really_inline
-hwlm_error_t scanSingleMain(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start, bool noCase,
- const struct cb_info *cbi) {
+hwlm_error_t scanSingleMain(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start, bool noCase,
+ const struct cb_info *cbi) {
- const MASK_TYPE mask1 = getMask(n->key0, noCase);
+ const MASK_TYPE mask1 = getMask(n->key0, noCase);
const MASK_TYPE caseMask = getCaseMask();
- size_t offset = start + n->msk_len - 1;
- size_t end = len;
- assert(offset < end);
-
-#if !defined(HAVE_AVX512)
- hwlm_error_t rv;
-
- if (end - offset < CHUNKSIZE) {
- rv = scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, offset,
- end);
+ size_t offset = start + n->msk_len - 1;
+ size_t end = len;
+ assert(offset < end);
+
+#if !defined(HAVE_AVX512)
+ hwlm_error_t rv;
+
+ if (end - offset < CHUNKSIZE) {
+ rv = scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, offset,
+ end);
return rv;
}
- if (end - offset == CHUNKSIZE) {
- rv = scanSingleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
- cbi, offset, end);
+ if (end - offset == CHUNKSIZE) {
+ rv = scanSingleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
+ cbi, offset, end);
return rv;
}
uintptr_t data = (uintptr_t)buf;
- uintptr_t s2Start = ROUNDUP_N(data + offset, CHUNKSIZE) - data;
+ uintptr_t s2Start = ROUNDUP_N(data + offset, CHUNKSIZE) - data;
uintptr_t last = data + end;
uintptr_t s2End = ROUNDDOWN_N(last, CHUNKSIZE) - data;
- uintptr_t s3Start = end - CHUNKSIZE;
+ uintptr_t s3Start = end - CHUNKSIZE;
- if (offset != s2Start) {
+ if (offset != s2Start) {
// first scan out to the fast scan starting point
DEBUG_PRINTF("stage 1: -> %zu\n", s2Start);
- rv = scanSingleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
- cbi, offset, s2Start);
+ rv = scanSingleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
+ cbi, offset, s2Start);
RETURN_IF_TERMINATED(rv);
}
@@ -196,70 +196,70 @@ hwlm_error_t scanSingleMain(const struct noodTable *n, const u8 *buf,
// scan as far as we can, bounded by the last point this key can
// possibly match
DEBUG_PRINTF("fast: ~ %zu -> %zu\n", s2Start, s2End);
- rv = scanSingleFast(n, buf, len, noCase, caseMask, mask1, cbi, s2Start,
- s2End);
+ rv = scanSingleFast(n, buf, len, noCase, caseMask, mask1, cbi, s2Start,
+ s2End);
RETURN_IF_TERMINATED(rv);
}
// if we are done bail out
- if (s2End == len) {
+ if (s2End == len) {
return HWLM_SUCCESS;
}
- DEBUG_PRINTF("stage 3: %zu -> %zu\n", s2End, len);
- rv = scanSingleUnaligned(n, buf, len, s3Start, noCase, caseMask, mask1, cbi,
- s2End, len);
+ DEBUG_PRINTF("stage 3: %zu -> %zu\n", s2End, len);
+ rv = scanSingleUnaligned(n, buf, len, s3Start, noCase, caseMask, mask1, cbi,
+ s2End, len);
return rv;
-#else // HAVE_AVX512
- return scanSingle512(n, buf, len, noCase, caseMask, mask1, cbi, offset,
- end);
-#endif
+#else // HAVE_AVX512
+ return scanSingle512(n, buf, len, noCase, caseMask, mask1, cbi, offset,
+ end);
+#endif
}
static really_inline
-hwlm_error_t scanDoubleMain(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start, bool noCase,
+hwlm_error_t scanDoubleMain(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start, bool noCase,
const struct cb_info *cbi) {
// we stop scanning for the key-fragment when the rest of the key can't
// possibly fit in the remaining buffer
- size_t end = len - n->key_offset + 2;
+ size_t end = len - n->key_offset + 2;
+
+ // the first place the key can match
+ size_t offset = start + n->msk_len - n->key_offset;
- // the first place the key can match
- size_t offset = start + n->msk_len - n->key_offset;
-
const MASK_TYPE caseMask = getCaseMask();
- const MASK_TYPE mask1 = getMask(n->key0, noCase);
- const MASK_TYPE mask2 = getMask(n->key1, noCase);
-
-#if !defined(HAVE_AVX512)
- hwlm_error_t rv;
-
- if (end - offset < CHUNKSIZE) {
- rv = scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
- offset, end);
+ const MASK_TYPE mask1 = getMask(n->key0, noCase);
+ const MASK_TYPE mask2 = getMask(n->key1, noCase);
+
+#if !defined(HAVE_AVX512)
+ hwlm_error_t rv;
+
+ if (end - offset < CHUNKSIZE) {
+ rv = scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
+ offset, end);
return rv;
}
- if (end - offset == CHUNKSIZE) {
- rv = scanDoubleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
- mask2, cbi, offset, end);
+ if (end - offset == CHUNKSIZE) {
+ rv = scanDoubleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
+ mask2, cbi, offset, end);
return rv;
}
uintptr_t data = (uintptr_t)buf;
- uintptr_t s2Start = ROUNDUP_N(data + offset, CHUNKSIZE) - data;
+ uintptr_t s2Start = ROUNDUP_N(data + offset, CHUNKSIZE) - data;
uintptr_t s1End = s2Start + 1;
uintptr_t last = data + end;
uintptr_t s2End = ROUNDDOWN_N(last, CHUNKSIZE) - data;
uintptr_t s3Start = end - CHUNKSIZE;
- uintptr_t off = offset;
+ uintptr_t off = offset;
- if (s2Start != off) {
+ if (s2Start != off) {
// first scan out to the fast scan starting point plus one char past to
// catch the key on the overlap
- DEBUG_PRINTF("stage 1: %zu -> %zu\n", off, s2Start);
- rv = scanDoubleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
- mask2, cbi, off, s1End);
+ DEBUG_PRINTF("stage 1: %zu -> %zu\n", off, s2Start);
+ rv = scanDoubleUnaligned(n, buf, len, offset, noCase, caseMask, mask1,
+ mask2, cbi, off, s1End);
RETURN_IF_TERMINATED(rv);
}
off = s1End;
@@ -273,8 +273,8 @@ hwlm_error_t scanDoubleMain(const struct noodTable *n, const u8 *buf,
// scan as far as we can, bounded by the last point this key can
// possibly match
DEBUG_PRINTF("fast: ~ %zu -> %zu\n", s2Start, s3Start);
- rv = scanDoubleFast(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
- s2Start, s2End);
+ rv = scanDoubleFast(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
+ s2Start, s2End);
RETURN_IF_TERMINATED(rv);
off = s2End;
}
@@ -285,158 +285,158 @@ hwlm_error_t scanDoubleMain(const struct noodTable *n, const u8 *buf,
}
DEBUG_PRINTF("stage 3: %zu -> %zu\n", s3Start, end);
- rv = scanDoubleUnaligned(n, buf, len, s3Start, noCase, caseMask, mask1,
- mask2, cbi, off, end);
+ rv = scanDoubleUnaligned(n, buf, len, s3Start, noCase, caseMask, mask1,
+ mask2, cbi, off, end);
return rv;
-#else // AVX512
- return scanDouble512(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
- offset, end);
-#endif // AVX512
+#else // AVX512
+ return scanDouble512(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
+ offset, end);
+#endif // AVX512
}
static really_inline
-hwlm_error_t scanSingleNoCase(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start,
+hwlm_error_t scanSingleNoCase(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start,
const struct cb_info *cbi) {
- return scanSingleMain(n, buf, len, start, 1, cbi);
+ return scanSingleMain(n, buf, len, start, 1, cbi);
}
static really_inline
-hwlm_error_t scanSingleCase(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start,
+hwlm_error_t scanSingleCase(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start,
const struct cb_info *cbi) {
- return scanSingleMain(n, buf, len, start, 0, cbi);
+ return scanSingleMain(n, buf, len, start, 0, cbi);
}
// Single-character specialisation, used when keyLen = 1
static really_inline
-hwlm_error_t scanSingle(const struct noodTable *n, const u8 *buf, size_t len,
- size_t start, bool noCase, const struct cb_info *cbi) {
- if (!ourisalpha(n->key0)) {
+hwlm_error_t scanSingle(const struct noodTable *n, const u8 *buf, size_t len,
+ size_t start, bool noCase, const struct cb_info *cbi) {
+ if (!ourisalpha(n->key0)) {
noCase = 0; // force noCase off if we don't have an alphabetic char
}
// kinda ugly, but this forces constant propagation
if (noCase) {
- return scanSingleNoCase(n, buf, len, start, cbi);
+ return scanSingleNoCase(n, buf, len, start, cbi);
} else {
- return scanSingleCase(n, buf, len, start, cbi);
+ return scanSingleCase(n, buf, len, start, cbi);
}
}
static really_inline
-hwlm_error_t scanDoubleNoCase(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start,
+hwlm_error_t scanDoubleNoCase(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start,
const struct cb_info *cbi) {
- return scanDoubleMain(n, buf, len, start, 1, cbi);
+ return scanDoubleMain(n, buf, len, start, 1, cbi);
}
static really_inline
-hwlm_error_t scanDoubleCase(const struct noodTable *n, const u8 *buf,
- size_t len, size_t start,
+hwlm_error_t scanDoubleCase(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t start,
const struct cb_info *cbi) {
- return scanDoubleMain(n, buf, len, start, 0, cbi);
+ return scanDoubleMain(n, buf, len, start, 0, cbi);
}
static really_inline
-hwlm_error_t scanDouble(const struct noodTable *n, const u8 *buf, size_t len,
- size_t start, bool noCase, const struct cb_info *cbi) {
+hwlm_error_t scanDouble(const struct noodTable *n, const u8 *buf, size_t len,
+ size_t start, bool noCase, const struct cb_info *cbi) {
// kinda ugly, but this forces constant propagation
if (noCase) {
- return scanDoubleNoCase(n, buf, len, start, cbi);
+ return scanDoubleNoCase(n, buf, len, start, cbi);
} else {
- return scanDoubleCase(n, buf, len, start, cbi);
+ return scanDoubleCase(n, buf, len, start, cbi);
}
}
// main entry point for the scan code
static really_inline
-hwlm_error_t scan(const struct noodTable *n, const u8 *buf, size_t len,
- size_t start, char single, bool noCase,
- const struct cb_info *cbi) {
- if (len - start < n->msk_len) {
+hwlm_error_t scan(const struct noodTable *n, const u8 *buf, size_t len,
+ size_t start, char single, bool noCase,
+ const struct cb_info *cbi) {
+ if (len - start < n->msk_len) {
// can't find string of length keyLen in a shorter buffer
return HWLM_SUCCESS;
}
- if (single) {
- return scanSingle(n, buf, len, start, noCase, cbi);
+ if (single) {
+ return scanSingle(n, buf, len, start, noCase, cbi);
} else {
- return scanDouble(n, buf, len, start, noCase, cbi);
+ return scanDouble(n, buf, len, start, noCase, cbi);
}
}
/** \brief Block-mode scanner. */
hwlm_error_t noodExec(const struct noodTable *n, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb,
- struct hs_scratch *scratch) {
+ size_t start, HWLMCallback cb,
+ struct hs_scratch *scratch) {
assert(n && buf);
- struct cb_info cbi = {cb, n->id, scratch, 0};
- DEBUG_PRINTF("nood scan of %zu bytes for %*s @ %p\n", len, n->msk_len,
- (const char *)&n->cmp, buf);
-
- return scan(n, buf, len, start, n->single, n->nocase, &cbi);
+ struct cb_info cbi = {cb, n->id, scratch, 0};
+ DEBUG_PRINTF("nood scan of %zu bytes for %*s @ %p\n", len, n->msk_len,
+ (const char *)&n->cmp, buf);
+
+ return scan(n, buf, len, start, n->single, n->nocase, &cbi);
}
/** \brief Streaming-mode scanner. */
hwlm_error_t noodExecStreaming(const struct noodTable *n, const u8 *hbuf,
size_t hlen, const u8 *buf, size_t len,
- HWLMCallback cb, struct hs_scratch *scratch) {
+ HWLMCallback cb, struct hs_scratch *scratch) {
assert(n);
- if (len + hlen < n->msk_len) {
- DEBUG_PRINTF("not enough bytes for a match\n");
- return HWLM_SUCCESS;
- }
-
- struct cb_info cbi = {cb, n->id, scratch, 0};
- DEBUG_PRINTF("nood scan of %zu bytes (%zu hlen) for %*s @ %p\n", len, hlen,
- n->msk_len, (const char *)&n->cmp, buf);
-
- if (hlen && n->msk_len > 1) {
- /*
- * we have history, so build up a buffer from enough of the history
- * buffer plus what we've been given to scan. Since this is relatively
- * short, just check against msk+cmp per byte offset for matches.
- */
+ if (len + hlen < n->msk_len) {
+ DEBUG_PRINTF("not enough bytes for a match\n");
+ return HWLM_SUCCESS;
+ }
+
+ struct cb_info cbi = {cb, n->id, scratch, 0};
+ DEBUG_PRINTF("nood scan of %zu bytes (%zu hlen) for %*s @ %p\n", len, hlen,
+ n->msk_len, (const char *)&n->cmp, buf);
+
+ if (hlen && n->msk_len > 1) {
+ /*
+ * we have history, so build up a buffer from enough of the history
+ * buffer plus what we've been given to scan. Since this is relatively
+ * short, just check against msk+cmp per byte offset for matches.
+ */
assert(hbuf);
- u8 ALIGN_DIRECTIVE temp_buf[HWLM_LITERAL_MAX_LEN * 2];
- memset(temp_buf, 0, sizeof(temp_buf));
-
- assert(n->msk_len);
- size_t tl1 = MIN((size_t)n->msk_len - 1, hlen);
- size_t tl2 = MIN((size_t)n->msk_len - 1, len);
-
- assert(tl1 + tl2 <= sizeof(temp_buf));
- assert(tl1 + tl2 >= n->msk_len);
- assert(tl1 <= sizeof(u64a));
- assert(tl2 <= sizeof(u64a));
- DEBUG_PRINTF("using %zu bytes of hist and %zu bytes of buf\n", tl1, tl2);
-
- unaligned_store_u64a(temp_buf,
- partial_load_u64a(hbuf + hlen - tl1, tl1));
- unaligned_store_u64a(temp_buf + tl1, partial_load_u64a(buf, tl2));
-
- for (size_t i = 0; i <= tl1 + tl2 - n->msk_len; i++) {
- u64a v = unaligned_load_u64a(temp_buf + i);
- if ((v & n->msk) == n->cmp) {
- size_t m_end = -tl1 + i + n->msk_len - 1;
- DEBUG_PRINTF("match @ %zu (i %zu)\n", m_end, i);
- hwlmcb_rv_t rv = cb(m_end, n->id, scratch);
- if (rv == HWLM_TERMINATE_MATCHING) {
- return HWLM_TERMINATED;
- }
- }
+ u8 ALIGN_DIRECTIVE temp_buf[HWLM_LITERAL_MAX_LEN * 2];
+ memset(temp_buf, 0, sizeof(temp_buf));
+
+ assert(n->msk_len);
+ size_t tl1 = MIN((size_t)n->msk_len - 1, hlen);
+ size_t tl2 = MIN((size_t)n->msk_len - 1, len);
+
+ assert(tl1 + tl2 <= sizeof(temp_buf));
+ assert(tl1 + tl2 >= n->msk_len);
+ assert(tl1 <= sizeof(u64a));
+ assert(tl2 <= sizeof(u64a));
+ DEBUG_PRINTF("using %zu bytes of hist and %zu bytes of buf\n", tl1, tl2);
+
+ unaligned_store_u64a(temp_buf,
+ partial_load_u64a(hbuf + hlen - tl1, tl1));
+ unaligned_store_u64a(temp_buf + tl1, partial_load_u64a(buf, tl2));
+
+ for (size_t i = 0; i <= tl1 + tl2 - n->msk_len; i++) {
+ u64a v = unaligned_load_u64a(temp_buf + i);
+ if ((v & n->msk) == n->cmp) {
+ size_t m_end = -tl1 + i + n->msk_len - 1;
+ DEBUG_PRINTF("match @ %zu (i %zu)\n", m_end, i);
+ hwlmcb_rv_t rv = cb(m_end, n->id, scratch);
+ if (rv == HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATED;
+ }
+ }
}
}
assert(buf);
cbi.offsetAdj = 0;
- return scan(n, buf, len, 0, n->single, n->nocase, &cbi);
+ return scan(n, buf, len, 0, n->single, n->nocase, &cbi);
}
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_engine.h b/contrib/libs/hyperscan/src/hwlm/noodle_engine.h
index be02286e8fa..64422c41f0c 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_engine.h
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_engine.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -41,17 +41,17 @@ extern "C"
#endif
struct noodTable;
-struct hs_scratch;
+struct hs_scratch;
/** \brief Block-mode scanner. */
hwlm_error_t noodExec(const struct noodTable *n, const u8 *buf, size_t len,
- size_t start, HWLMCallback cb,
- struct hs_scratch *scratch);
+ size_t start, HWLMCallback cb,
+ struct hs_scratch *scratch);
/** \brief Streaming-mode scanner. */
hwlm_error_t noodExecStreaming(const struct noodTable *n, const u8 *hbuf,
size_t hlen, const u8 *buf, size_t len,
- HWLMCallback cb, struct hs_scratch *scratch);
+ HWLMCallback cb, struct hs_scratch *scratch);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx2.c b/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx2.c
index dbac7fd90e0..5edc646af13 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx2.c
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,11 +38,11 @@ static really_inline m256 getCaseMask(void) {
}
static really_inline
-hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
- size_t len, size_t offset, bool noCase,
- m256 caseMask, m256 mask1,
- const struct cb_info *cbi, size_t start,
- size_t end) {
+hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t offset, bool noCase,
+ m256 caseMask, m256 mask1,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
const u8 *d = buf + offset;
DEBUG_PRINTF("start %zu end %zu offset %zu\n", start, end, offset);
const size_t l = end - start;
@@ -67,11 +67,11 @@ hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
- size_t len, size_t offset, bool noCase,
- m256 caseMask, m256 mask1, m256 mask2,
- const struct cb_info *cbi, size_t start,
- size_t end) {
+hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t offset, bool noCase,
+ m256 caseMask, m256 mask1, m256 mask2,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
const u8 *d = buf + offset;
DEBUG_PRINTF("start %zu end %zu offset %zu\n", start, end, offset);
size_t l = end - start;
@@ -101,8 +101,8 @@ hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
// alignment boundary if needed and to finish off data that the aligned scan
// function can't handle (due to small/unaligned chunk at end)
static really_inline
-hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m256 caseMask, m256 mask1,
+hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m256 caseMask, m256 mask1,
const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start;
@@ -118,9 +118,9 @@ hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
if (l < 4) {
u8 *vp = (u8*)&v;
switch (l) {
- case 3: vp[2] = d[2]; // fallthrough
- case 2: vp[1] = d[1]; // fallthrough
- case 1: vp[0] = d[0]; // fallthrough
+ case 3: vp[2] = d[2]; // fallthrough
+ case 2: vp[1] = d[1]; // fallthrough
+ case 1: vp[0] = d[0]; // fallthrough
}
} else {
v = masked_move256_len(d, l);
@@ -141,10 +141,10 @@ hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m256 caseMask, m256 mask1,
- m256 mask2, const struct cb_info *cbi,
- size_t start, size_t end) {
+hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m256 caseMask, m256 mask1,
+ m256 mask2, const struct cb_info *cbi,
+ size_t start, size_t end) {
const u8 *d = buf + start;
size_t l = end - start;
if (!l) {
@@ -157,9 +157,9 @@ hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
if (l < 4) {
u8 *vp = (u8*)&v;
switch (l) {
- case 3: vp[2] = d[2]; // fallthrough
- case 2: vp[1] = d[1]; // fallthrough
- case 1: vp[0] = d[0]; // fallthrough
+ case 3: vp[2] = d[2]; // fallthrough
+ case 2: vp[1] = d[1]; // fallthrough
+ case 1: vp[0] = d[0]; // fallthrough
}
} else {
v = masked_move256_len(d, l);
@@ -182,8 +182,8 @@ hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m256 caseMask, m256 mask1,
+hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m256 caseMask, m256 mask1,
const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start, *e = buf + end;
@@ -203,9 +203,9 @@ hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m256 caseMask, m256 mask1,
- m256 mask2, const struct cb_info *cbi, size_t start,
+hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m256 caseMask, m256 mask1,
+ m256 mask2, const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start, *e = buf + end;
DEBUG_PRINTF("start %zu end %zu \n", start, end);
@@ -220,7 +220,7 @@ hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
u32 z0 = movemask256(eq256(mask1, v));
u32 z1 = movemask256(eq256(mask2, v));
u32 z = (lastz0 | (z0 << 1)) & z1;
- lastz0 = z0 >> 31;
+ lastz0 = z0 >> 31;
// On large packet buffers, this prefetch appears to get us about 2%.
__builtin_prefetch(d + 128);
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx512.c b/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx512.c
index 9bf445821a2..8cac1b15c22 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx512.c
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_engine_avx512.c
@@ -1,191 +1,191 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/* noodle scan parts for AVX512 */
-
-static really_inline
-m512 getMask(u8 c, bool noCase) {
- u8 k = caseClear8(c, noCase);
- return set64x8(k);
-}
-
-static really_inline
-m512 getCaseMask(void) {
- return set64x8(CASE_CLEAR);
-}
-
-// The short scan routine. It is used both to scan data up to an
-// alignment boundary if needed and to finish off data that the aligned scan
-// function can't handle (due to small/unaligned chunk at end)
-static really_inline
-hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m512 caseMask, m512 mask1,
- const struct cb_info *cbi, size_t start,
- size_t end) {
- const u8 *d = buf + start;
- ptrdiff_t scan_len = end - start;
- DEBUG_PRINTF("scan_len %zu\n", scan_len);
- assert(scan_len <= 64);
- if (!scan_len) {
- return HWLM_SUCCESS;
- }
-
- __mmask64 k = (~0ULL) >> (64 - scan_len);
- DEBUG_PRINTF("load mask 0x%016llx\n", k);
-
- m512 v = loadu_maskz_m512(k, d);
-
- if (noCase) {
- v = and512(v, caseMask);
- }
-
- // reuse the load mask to indicate valid bytes
- u64a z = masked_eq512mask(k, mask1, v);
-
- SINGLE_ZSCAN();
-
- return HWLM_SUCCESS;
-}
-
-static really_inline
-hwlm_error_t scanSingle512(const struct noodTable *n, const u8 *buf, size_t len,
- bool noCase, m512 caseMask, m512 mask1,
- const struct cb_info *cbi, size_t start,
- size_t end) {
- const u8 *d = buf + start;
- const u8 *e = buf + end;
- DEBUG_PRINTF("start %p end %p \n", d, e);
- assert(d < e);
- if (d + 64 >= e) {
- goto tail;
- }
-
- // peel off first part to cacheline boundary
- const u8 *d1 = ROUNDUP_PTR(d, 64);
- if (scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, start,
- d1 - buf) == HWLM_TERMINATED) {
- return HWLM_TERMINATED;
- }
- d = d1;
-
- for (; d + 64 < e; d += 64) {
- DEBUG_PRINTF("d %p e %p \n", d, e);
- m512 v = noCase ? and512(load512(d), caseMask) : load512(d);
-
- u64a z = eq512mask(mask1, v);
- __builtin_prefetch(d + 128);
-
- SINGLE_ZSCAN();
- }
-
-tail:
- DEBUG_PRINTF("d %p e %p \n", d, e);
- // finish off tail
-
- return scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, d - buf,
- e - buf);
-}
-
-static really_inline
-hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m512 caseMask, m512 mask1,
- m512 mask2, const struct cb_info *cbi,
- u64a *lastz0, size_t start, size_t end) {
- DEBUG_PRINTF("start %zu end %zu last 0x%016llx\n", start, end, *lastz0);
- const u8 *d = buf + start;
- ptrdiff_t scan_len = end - start;
- if (!scan_len) {
- return HWLM_SUCCESS;
- }
- assert(scan_len <= 64);
- __mmask64 k = (~0ULL) >> (64 - scan_len);
- DEBUG_PRINTF("load mask 0x%016llx scan_len %zu\n", k, scan_len);
-
- m512 v = loadu_maskz_m512(k, d);
- if (noCase) {
- v = and512(v, caseMask);
- }
-
- u64a z0 = masked_eq512mask(k, mask1, v);
- u64a z1 = masked_eq512mask(k, mask2, v);
- u64a z = (*lastz0 | (z0 << 1)) & z1;
- DEBUG_PRINTF("z 0x%016llx\n", z);
-
- DOUBLE_ZSCAN();
- *lastz0 = z0 >> (scan_len - 1);
- return HWLM_SUCCESS;
-}
-
-static really_inline
-hwlm_error_t scanDouble512(const struct noodTable *n, const u8 *buf, size_t len,
- bool noCase, m512 caseMask, m512 mask1, m512 mask2,
- const struct cb_info *cbi, size_t start,
- size_t end) {
- const u8 *d = buf + start;
- const u8 *e = buf + end;
- u64a lastz0 = 0;
- DEBUG_PRINTF("start %zu end %zu \n", start, end);
- assert(d < e);
- if (d + 64 >= e) {
- goto tail;
- }
-
- // peel off first part to cacheline boundary
- const u8 *d1 = ROUNDUP_PTR(d, 64);
- if (scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
- &lastz0, start, d1 - buf) == HWLM_TERMINATED) {
- return HWLM_TERMINATED;
- }
- d = d1;
-
- for (; d + 64 < e; d += 64) {
- DEBUG_PRINTF("d %p e %p 0x%016llx\n", d, e, lastz0);
- m512 v = noCase ? and512(load512(d), caseMask) : load512(d);
-
- /* we have to pull the masks out of the AVX registers because we can't
- byte shift between the lanes */
- u64a z0 = eq512mask(mask1, v);
- u64a z1 = eq512mask(mask2, v);
- u64a z = (lastz0 | (z0 << 1)) & z1;
- lastz0 = z0 >> 63;
-
- // On large packet buffers, this prefetch appears to get us about 2%.
- __builtin_prefetch(d + 256);
-
- DEBUG_PRINTF("z 0x%016llx\n", z);
-
- DOUBLE_ZSCAN();
- }
-
-tail:
- DEBUG_PRINTF("d %p e %p off %zu \n", d, e, d - buf);
- // finish off tail
-
- return scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
- &lastz0, d - buf, end);
-}
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/* noodle scan parts for AVX512 */
+
+static really_inline
+m512 getMask(u8 c, bool noCase) {
+ u8 k = caseClear8(c, noCase);
+ return set64x8(k);
+}
+
+static really_inline
+m512 getCaseMask(void) {
+ return set64x8(CASE_CLEAR);
+}
+
+// The short scan routine. It is used both to scan data up to an
+// alignment boundary if needed and to finish off data that the aligned scan
+// function can't handle (due to small/unaligned chunk at end)
+static really_inline
+hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m512 caseMask, m512 mask1,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
+ const u8 *d = buf + start;
+ ptrdiff_t scan_len = end - start;
+ DEBUG_PRINTF("scan_len %zu\n", scan_len);
+ assert(scan_len <= 64);
+ if (!scan_len) {
+ return HWLM_SUCCESS;
+ }
+
+ __mmask64 k = (~0ULL) >> (64 - scan_len);
+ DEBUG_PRINTF("load mask 0x%016llx\n", k);
+
+ m512 v = loadu_maskz_m512(k, d);
+
+ if (noCase) {
+ v = and512(v, caseMask);
+ }
+
+ // reuse the load mask to indicate valid bytes
+ u64a z = masked_eq512mask(k, mask1, v);
+
+ SINGLE_ZSCAN();
+
+ return HWLM_SUCCESS;
+}
+
+static really_inline
+hwlm_error_t scanSingle512(const struct noodTable *n, const u8 *buf, size_t len,
+ bool noCase, m512 caseMask, m512 mask1,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
+ const u8 *d = buf + start;
+ const u8 *e = buf + end;
+ DEBUG_PRINTF("start %p end %p \n", d, e);
+ assert(d < e);
+ if (d + 64 >= e) {
+ goto tail;
+ }
+
+ // peel off first part to cacheline boundary
+ const u8 *d1 = ROUNDUP_PTR(d, 64);
+ if (scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, start,
+ d1 - buf) == HWLM_TERMINATED) {
+ return HWLM_TERMINATED;
+ }
+ d = d1;
+
+ for (; d + 64 < e; d += 64) {
+ DEBUG_PRINTF("d %p e %p \n", d, e);
+ m512 v = noCase ? and512(load512(d), caseMask) : load512(d);
+
+ u64a z = eq512mask(mask1, v);
+ __builtin_prefetch(d + 128);
+
+ SINGLE_ZSCAN();
+ }
+
+tail:
+ DEBUG_PRINTF("d %p e %p \n", d, e);
+ // finish off tail
+
+ return scanSingleShort(n, buf, len, noCase, caseMask, mask1, cbi, d - buf,
+ e - buf);
+}
+
+static really_inline
+hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m512 caseMask, m512 mask1,
+ m512 mask2, const struct cb_info *cbi,
+ u64a *lastz0, size_t start, size_t end) {
+ DEBUG_PRINTF("start %zu end %zu last 0x%016llx\n", start, end, *lastz0);
+ const u8 *d = buf + start;
+ ptrdiff_t scan_len = end - start;
+ if (!scan_len) {
+ return HWLM_SUCCESS;
+ }
+ assert(scan_len <= 64);
+ __mmask64 k = (~0ULL) >> (64 - scan_len);
+ DEBUG_PRINTF("load mask 0x%016llx scan_len %zu\n", k, scan_len);
+
+ m512 v = loadu_maskz_m512(k, d);
+ if (noCase) {
+ v = and512(v, caseMask);
+ }
+
+ u64a z0 = masked_eq512mask(k, mask1, v);
+ u64a z1 = masked_eq512mask(k, mask2, v);
+ u64a z = (*lastz0 | (z0 << 1)) & z1;
+ DEBUG_PRINTF("z 0x%016llx\n", z);
+
+ DOUBLE_ZSCAN();
+ *lastz0 = z0 >> (scan_len - 1);
+ return HWLM_SUCCESS;
+}
+
+static really_inline
+hwlm_error_t scanDouble512(const struct noodTable *n, const u8 *buf, size_t len,
+ bool noCase, m512 caseMask, m512 mask1, m512 mask2,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
+ const u8 *d = buf + start;
+ const u8 *e = buf + end;
+ u64a lastz0 = 0;
+ DEBUG_PRINTF("start %zu end %zu \n", start, end);
+ assert(d < e);
+ if (d + 64 >= e) {
+ goto tail;
+ }
+
+ // peel off first part to cacheline boundary
+ const u8 *d1 = ROUNDUP_PTR(d, 64);
+ if (scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
+ &lastz0, start, d1 - buf) == HWLM_TERMINATED) {
+ return HWLM_TERMINATED;
+ }
+ d = d1;
+
+ for (; d + 64 < e; d += 64) {
+ DEBUG_PRINTF("d %p e %p 0x%016llx\n", d, e, lastz0);
+ m512 v = noCase ? and512(load512(d), caseMask) : load512(d);
+
+ /* we have to pull the masks out of the AVX registers because we can't
+ byte shift between the lanes */
+ u64a z0 = eq512mask(mask1, v);
+ u64a z1 = eq512mask(mask2, v);
+ u64a z = (lastz0 | (z0 << 1)) & z1;
+ lastz0 = z0 >> 63;
+
+ // On large packet buffers, this prefetch appears to get us about 2%.
+ __builtin_prefetch(d + 256);
+
+ DEBUG_PRINTF("z 0x%016llx\n", z);
+
+ DOUBLE_ZSCAN();
+ }
+
+tail:
+ DEBUG_PRINTF("d %p e %p off %zu \n", d, e, d - buf);
+ // finish off tail
+
+ return scanDoubleShort(n, buf, len, noCase, caseMask, mask1, mask2, cbi,
+ &lastz0, d - buf, end);
+}
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_engine_sse.c b/contrib/libs/hyperscan/src/hwlm/noodle_engine_sse.c
index 0fc33bc342e..7cd53d7cedc 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_engine_sse.c
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_engine_sse.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,8 +38,8 @@ static really_inline m128 getCaseMask(void) {
}
static really_inline
-hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m128 caseMask, m128 mask1,
+hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m128 caseMask, m128 mask1,
const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start;
@@ -67,11 +67,11 @@ hwlm_error_t scanSingleShort(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
- size_t len, size_t offset, bool noCase,
- m128 caseMask, m128 mask1,
- const struct cb_info *cbi, size_t start,
- size_t end) {
+hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t offset, bool noCase,
+ m128 caseMask, m128 mask1,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
const u8 *d = buf + offset;
DEBUG_PRINTF("start %zu end %zu offset %zu\n", start, end, offset);
const size_t l = end - start;
@@ -97,10 +97,10 @@ hwlm_error_t scanSingleUnaligned(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m128 caseMask, m128 mask1,
- m128 mask2, const struct cb_info *cbi,
- size_t start, size_t end) {
+hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m128 caseMask, m128 mask1,
+ m128 mask2, const struct cb_info *cbi,
+ size_t start, size_t end) {
const u8 *d = buf + start;
size_t l = end - start;
if (!l) {
@@ -115,8 +115,8 @@ hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
v = and128(v, caseMask);
}
- u32 z = movemask128(and128(lshiftbyte_m128(eq128(mask1, v), 1),
- eq128(mask2, v)));
+ u32 z = movemask128(and128(lshiftbyte_m128(eq128(mask1, v), 1),
+ eq128(mask2, v)));
// mask out where we can't match
u32 mask = (0xFFFF >> (16 - l));
@@ -128,11 +128,11 @@ hwlm_error_t scanDoubleShort(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
- size_t len, size_t offset, bool noCase,
- m128 caseMask, m128 mask1, m128 mask2,
- const struct cb_info *cbi, size_t start,
- size_t end) {
+hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
+ size_t len, size_t offset, bool noCase,
+ m128 caseMask, m128 mask1, m128 mask2,
+ const struct cb_info *cbi, size_t start,
+ size_t end) {
const u8 *d = buf + offset;
DEBUG_PRINTF("start %zu end %zu offset %zu\n", start, end, offset);
size_t l = end - start;
@@ -143,8 +143,8 @@ hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
v = and128(v, caseMask);
}
- u32 z = movemask128(and128(lshiftbyte_m128(eq128(mask1, v), 1),
- eq128(mask2, v)));
+ u32 z = movemask128(and128(lshiftbyte_m128(eq128(mask1, v), 1),
+ eq128(mask2, v)));
// mask out where we can't match
u32 buf_off = start - offset;
@@ -158,8 +158,8 @@ hwlm_error_t scanDoubleUnaligned(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m128 caseMask, m128 mask1,
+hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m128 caseMask, m128 mask1,
const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start, *e = buf + end;
@@ -179,9 +179,9 @@ hwlm_error_t scanSingleFast(const struct noodTable *n, const u8 *buf,
}
static really_inline
-hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
- size_t len, bool noCase, m128 caseMask, m128 mask1,
- m128 mask2, const struct cb_info *cbi, size_t start,
+hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
+ size_t len, bool noCase, m128 caseMask, m128 mask1,
+ m128 mask2, const struct cb_info *cbi, size_t start,
size_t end) {
const u8 *d = buf + start, *e = buf + end;
assert(d < e);
@@ -191,8 +191,8 @@ hwlm_error_t scanDoubleFast(const struct noodTable *n, const u8 *buf,
m128 v = noCase ? and128(load128(d), caseMask) : load128(d);
m128 z1 = eq128(mask1, v);
m128 z2 = eq128(mask2, v);
- u32 z = movemask128(and128(palignr(z1, lastz1, 15), z2));
- lastz1 = z1;
+ u32 z = movemask128(and128(palignr(z1, lastz1, 15), z2));
+ lastz1 = z1;
// On large packet buffers, this prefetch appears to get us about 2%.
__builtin_prefetch(d + 128);
diff --git a/contrib/libs/hyperscan/src/hwlm/noodle_internal.h b/contrib/libs/hyperscan/src/hwlm/noodle_internal.h
index 6a4b65e9368..8f76f177e1e 100644
--- a/contrib/libs/hyperscan/src/hwlm/noodle_internal.h
+++ b/contrib/libs/hyperscan/src/hwlm/noodle_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,22 +30,22 @@
* \brief Data structures for Noodle literal matcher engine.
*/
-#ifndef NOODLE_INTERNAL_H
-#define NOODLE_INTERNAL_H
+#ifndef NOODLE_INTERNAL_H
+#define NOODLE_INTERNAL_H
#include "ue2common.h"
struct noodTable {
u32 id;
- u64a msk;
- u64a cmp;
- u8 msk_len;
- u8 key_offset;
- u8 nocase;
- u8 single;
- u8 key0;
- u8 key1;
+ u64a msk;
+ u64a cmp;
+ u8 msk_len;
+ u8 key_offset;
+ u8 nocase;
+ u8 single;
+ u8 key0;
+ u8 key1;
};
-#endif /* NOODLE_INTERNAL_H */
+#endif /* NOODLE_INTERNAL_H */
diff --git a/contrib/libs/hyperscan/src/nfa/accel.c b/contrib/libs/hyperscan/src/nfa/accel.c
index 3260b7bd3a1..2bc60945f96 100644
--- a/contrib/libs/hyperscan/src/nfa/accel.c
+++ b/contrib/libs/hyperscan/src/nfa/accel.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -81,18 +81,18 @@ const u8 *run_accel(const union AccelAux *accel, const u8 *c, const u8 *c_end) {
c_end - 1);
break;
- case ACCEL_DVERM_MASKED:
- DEBUG_PRINTF("accel dverm masked %p %p\n", c, c_end);
- if (c + 16 + 1 >= c_end) {
- return c;
- }
-
- /* need to stop one early to get an accurate end state */
- rv = vermicelliDoubleMaskedExec(accel->dverm.c1, accel->dverm.c2,
- accel->dverm.m1, accel->dverm.m2,
- c, c_end - 1);
- break;
-
+ case ACCEL_DVERM_MASKED:
+ DEBUG_PRINTF("accel dverm masked %p %p\n", c, c_end);
+ if (c + 16 + 1 >= c_end) {
+ return c;
+ }
+
+ /* need to stop one early to get an accurate end state */
+ rv = vermicelliDoubleMaskedExec(accel->dverm.c1, accel->dverm.c2,
+ accel->dverm.m1, accel->dverm.m2,
+ c, c_end - 1);
+ break;
+
case ACCEL_SHUFTI:
DEBUG_PRINTF("accel shufti %p %p\n", c, c_end);
if (c + 15 >= c_end) {
@@ -129,7 +129,7 @@ const u8 *run_accel(const union AccelAux *accel, const u8 *c, const u8 *c_end) {
rv = c_end;
break;
-
+
default:
assert(!"not here");
return c;
@@ -140,7 +140,7 @@ const u8 *run_accel(const union AccelAux *accel, const u8 *c, const u8 *c_end) {
rv = MAX(c + accel->generic.offset, rv);
rv -= accel->generic.offset;
- DEBUG_PRINTF("advanced %zd\n", rv - c);
-
+ DEBUG_PRINTF("advanced %zd\n", rv - c);
+
return rv;
}
diff --git a/contrib/libs/hyperscan/src/nfa/accel.h b/contrib/libs/hyperscan/src/nfa/accel.h
index a91abe0d2c8..3a03d05967a 100644
--- a/contrib/libs/hyperscan/src/nfa/accel.h
+++ b/contrib/libs/hyperscan/src/nfa/accel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -60,8 +60,8 @@ enum AccelType {
ACCEL_SHUFTI,
ACCEL_DSHUFTI,
ACCEL_TRUFFLE,
- ACCEL_RED_TAPE,
- ACCEL_DVERM_MASKED,
+ ACCEL_RED_TAPE,
+ ACCEL_DVERM_MASKED,
};
/** \brief Structure for accel framework. */
@@ -81,25 +81,25 @@ union AccelAux {
u8 offset;
u8 c1; // uppercase if nocase
u8 c2; // uppercase if nocase
- u8 m1; // masked variant
- u8 m2; // masked variant
+ u8 m1; // masked variant
+ u8 m2; // masked variant
} dverm;
struct {
u8 accel_type;
u8 offset;
- u8 c; // uppercase if nocase
- u8 len;
- } mverm;
- struct {
- u8 accel_type;
- u8 offset;
- u8 c; // uppercase if nocase
- u8 len1;
- u8 len2;
- } mdverm;
- struct {
- u8 accel_type;
- u8 offset;
+ u8 c; // uppercase if nocase
+ u8 len;
+ } mverm;
+ struct {
+ u8 accel_type;
+ u8 offset;
+ u8 c; // uppercase if nocase
+ u8 len1;
+ u8 len2;
+ } mdverm;
+ struct {
+ u8 accel_type;
+ u8 offset;
m128 lo;
m128 hi;
} shufti;
diff --git a/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.cpp b/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.cpp
index dbd31e6033f..ae71e141a24 100644
--- a/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.cpp
+++ b/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.cpp
@@ -1,607 +1,607 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "accel_dfa_build_strat.h"
-
-#include "accel.h"
-#include "grey.h"
-#include "nfagraph/ng_limex_accel.h"
-#include "shufticompile.h"
-#include "trufflecompile.h"
-#include "util/accel_scheme.h"
-#include "util/charreach.h"
-#include "util/container.h"
-#include "util/dump_charclass.h"
-#include "util/small_vector.h"
-#include "util/verify_types.h"
-
-#include <sstream>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#define PATHS_LIMIT 500
-
-using namespace std;
-
-namespace ue2 {
-
-namespace {
-struct path {
- small_vector<CharReach, MAX_ACCEL_DEPTH + 1> reach;
- dstate_id_t dest = DEAD_STATE;
- explicit path(dstate_id_t base) : dest(base) {}
-};
-};
-
-template<typename Container>
-void dump_paths(const Container &paths) {
- for (UNUSED const path &p : paths) {
- DEBUG_PRINTF("[%s] -> %u\n", describeClasses(p.reach).c_str(), p.dest);
- }
- DEBUG_PRINTF("%zu paths\n", paths.size());
-}
-
-static
-vector<CharReach> reverse_alpha_remapping(const raw_dfa &rdfa) {
- vector<CharReach> rv(rdfa.alpha_size - 1); /* TOP not required */
-
- for (u32 i = 0; i < N_CHARS; i++) {
- rv.at(rdfa.alpha_remap[i]).set(i);
- }
-
- return rv;
-}
-
-static
-bool is_useful_path(const vector<path> &good, const path &p) {
- for (const auto &g : good) {
- assert(g.dest == p.dest);
- assert(g.reach.size() <= p.reach.size());
- auto git = g.reach.rbegin();
- auto pit = p.reach.rbegin();
-
- for (; git != g.reach.rend(); ++git, ++pit) {
- if (!pit->isSubsetOf(*git)) {
- goto next;
- }
- }
- DEBUG_PRINTF("better: [%s] -> %u\n", describeClasses(g.reach).c_str(),
- g.dest);
-
- return false;
- next:;
- }
-
- return true;
-}
-
-static
-path append(const path &orig, const CharReach &cr, u32 new_dest) {
- path p(new_dest);
- p.reach = orig.reach;
- p.reach.push_back(cr);
-
- return p;
-}
-
-static
-void extend(const raw_dfa &rdfa, const vector<CharReach> &rev_map,
- const path &p, unordered_map<u32, vector<path>> &all,
- vector<path> &out) {
- const dstate &s = rdfa.states[p.dest];
-
- if (!p.reach.empty() && p.reach.back().none()) {
- out.push_back(p);
- return;
- }
-
- if (!s.reports.empty()) {
- if (generates_callbacks(rdfa.kind)) {
- out.push_back(p);
- return;
- } else {
- path pp = append(p, CharReach(), p.dest);
- all[p.dest].push_back(pp);
- out.push_back(move(pp));
- }
- }
-
- if (!s.reports_eod.empty()) {
- path pp = append(p, CharReach(), p.dest);
- all[p.dest].push_back(pp);
- out.push_back(move(pp));
- }
-
- flat_map<u32, CharReach> dest;
- for (u32 i = 0; i < rev_map.size(); i++) {
- u32 succ = s.next[i];
- dest[succ] |= rev_map[i];
- }
-
- for (const auto &e : dest) {
- path pp = append(p, e.second, e.first);
- if (!is_useful_path(all[e.first], pp)) {
- DEBUG_PRINTF("not useful: [%s] -> %u\n",
- describeClasses(pp.reach).c_str(), pp.dest);
- continue;
- }
-
- DEBUG_PRINTF("----good: [%s] -> %u\n",
- describeClasses(pp.reach).c_str(), pp.dest);
- all[e.first].push_back(pp);
- out.push_back(move(pp));
- }
-}
-
-static
-vector<vector<CharReach>> generate_paths(const raw_dfa &rdfa,
- dstate_id_t base, u32 len) {
- const vector<CharReach> rev_map = reverse_alpha_remapping(rdfa);
- vector<path> paths{path(base)};
- unordered_map<u32, vector<path>> all;
- all[base].push_back(path(base));
- for (u32 i = 0; i < len && paths.size() < PATHS_LIMIT; i++) {
- vector<path> next_gen;
- for (const auto &p : paths) {
- extend(rdfa, rev_map, p, all, next_gen);
- }
-
- paths = move(next_gen);
- }
-
- dump_paths(paths);
-
- vector<vector<CharReach>> rv;
- rv.reserve(paths.size());
- for (auto &p : paths) {
- rv.push_back(vector<CharReach>(std::make_move_iterator(p.reach.begin()),
- std::make_move_iterator(p.reach.end())));
- }
- return rv;
-}
-
-static
-AccelScheme look_for_offset_accel(const raw_dfa &rdfa, dstate_id_t base,
- u32 max_allowed_accel_offset) {
- DEBUG_PRINTF("looking for accel for %hu\n", base);
- vector<vector<CharReach>> paths =
- generate_paths(rdfa, base, max_allowed_accel_offset + 1);
- AccelScheme as = findBestAccelScheme(paths, CharReach(), true);
- DEBUG_PRINTF("found %s + %u\n", describeClass(as.cr).c_str(), as.offset);
- return as;
-}
-
-static UNUSED
-bool better(const AccelScheme &a, const AccelScheme &b) {
- if (!a.double_byte.empty() && b.double_byte.empty()) {
- return true;
- }
-
- if (!b.double_byte.empty()) {
- return false;
- }
-
- return a.cr.count() < b.cr.count();
-}
-
-static
-bool double_byte_ok(const AccelScheme &info) {
- return !info.double_byte.empty() &&
- info.double_cr.count() < info.double_byte.size() &&
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "accel_dfa_build_strat.h"
+
+#include "accel.h"
+#include "grey.h"
+#include "nfagraph/ng_limex_accel.h"
+#include "shufticompile.h"
+#include "trufflecompile.h"
+#include "util/accel_scheme.h"
+#include "util/charreach.h"
+#include "util/container.h"
+#include "util/dump_charclass.h"
+#include "util/small_vector.h"
+#include "util/verify_types.h"
+
+#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#define PATHS_LIMIT 500
+
+using namespace std;
+
+namespace ue2 {
+
+namespace {
+struct path {
+ small_vector<CharReach, MAX_ACCEL_DEPTH + 1> reach;
+ dstate_id_t dest = DEAD_STATE;
+ explicit path(dstate_id_t base) : dest(base) {}
+};
+};
+
+template<typename Container>
+void dump_paths(const Container &paths) {
+ for (UNUSED const path &p : paths) {
+ DEBUG_PRINTF("[%s] -> %u\n", describeClasses(p.reach).c_str(), p.dest);
+ }
+ DEBUG_PRINTF("%zu paths\n", paths.size());
+}
+
+static
+vector<CharReach> reverse_alpha_remapping(const raw_dfa &rdfa) {
+ vector<CharReach> rv(rdfa.alpha_size - 1); /* TOP not required */
+
+ for (u32 i = 0; i < N_CHARS; i++) {
+ rv.at(rdfa.alpha_remap[i]).set(i);
+ }
+
+ return rv;
+}
+
+static
+bool is_useful_path(const vector<path> &good, const path &p) {
+ for (const auto &g : good) {
+ assert(g.dest == p.dest);
+ assert(g.reach.size() <= p.reach.size());
+ auto git = g.reach.rbegin();
+ auto pit = p.reach.rbegin();
+
+ for (; git != g.reach.rend(); ++git, ++pit) {
+ if (!pit->isSubsetOf(*git)) {
+ goto next;
+ }
+ }
+ DEBUG_PRINTF("better: [%s] -> %u\n", describeClasses(g.reach).c_str(),
+ g.dest);
+
+ return false;
+ next:;
+ }
+
+ return true;
+}
+
+static
+path append(const path &orig, const CharReach &cr, u32 new_dest) {
+ path p(new_dest);
+ p.reach = orig.reach;
+ p.reach.push_back(cr);
+
+ return p;
+}
+
+static
+void extend(const raw_dfa &rdfa, const vector<CharReach> &rev_map,
+ const path &p, unordered_map<u32, vector<path>> &all,
+ vector<path> &out) {
+ const dstate &s = rdfa.states[p.dest];
+
+ if (!p.reach.empty() && p.reach.back().none()) {
+ out.push_back(p);
+ return;
+ }
+
+ if (!s.reports.empty()) {
+ if (generates_callbacks(rdfa.kind)) {
+ out.push_back(p);
+ return;
+ } else {
+ path pp = append(p, CharReach(), p.dest);
+ all[p.dest].push_back(pp);
+ out.push_back(move(pp));
+ }
+ }
+
+ if (!s.reports_eod.empty()) {
+ path pp = append(p, CharReach(), p.dest);
+ all[p.dest].push_back(pp);
+ out.push_back(move(pp));
+ }
+
+ flat_map<u32, CharReach> dest;
+ for (u32 i = 0; i < rev_map.size(); i++) {
+ u32 succ = s.next[i];
+ dest[succ] |= rev_map[i];
+ }
+
+ for (const auto &e : dest) {
+ path pp = append(p, e.second, e.first);
+ if (!is_useful_path(all[e.first], pp)) {
+ DEBUG_PRINTF("not useful: [%s] -> %u\n",
+ describeClasses(pp.reach).c_str(), pp.dest);
+ continue;
+ }
+
+ DEBUG_PRINTF("----good: [%s] -> %u\n",
+ describeClasses(pp.reach).c_str(), pp.dest);
+ all[e.first].push_back(pp);
+ out.push_back(move(pp));
+ }
+}
+
+static
+vector<vector<CharReach>> generate_paths(const raw_dfa &rdfa,
+ dstate_id_t base, u32 len) {
+ const vector<CharReach> rev_map = reverse_alpha_remapping(rdfa);
+ vector<path> paths{path(base)};
+ unordered_map<u32, vector<path>> all;
+ all[base].push_back(path(base));
+ for (u32 i = 0; i < len && paths.size() < PATHS_LIMIT; i++) {
+ vector<path> next_gen;
+ for (const auto &p : paths) {
+ extend(rdfa, rev_map, p, all, next_gen);
+ }
+
+ paths = move(next_gen);
+ }
+
+ dump_paths(paths);
+
+ vector<vector<CharReach>> rv;
+ rv.reserve(paths.size());
+ for (auto &p : paths) {
+ rv.push_back(vector<CharReach>(std::make_move_iterator(p.reach.begin()),
+ std::make_move_iterator(p.reach.end())));
+ }
+ return rv;
+}
+
+static
+AccelScheme look_for_offset_accel(const raw_dfa &rdfa, dstate_id_t base,
+ u32 max_allowed_accel_offset) {
+ DEBUG_PRINTF("looking for accel for %hu\n", base);
+ vector<vector<CharReach>> paths =
+ generate_paths(rdfa, base, max_allowed_accel_offset + 1);
+ AccelScheme as = findBestAccelScheme(paths, CharReach(), true);
+ DEBUG_PRINTF("found %s + %u\n", describeClass(as.cr).c_str(), as.offset);
+ return as;
+}
+
+static UNUSED
+bool better(const AccelScheme &a, const AccelScheme &b) {
+ if (!a.double_byte.empty() && b.double_byte.empty()) {
+ return true;
+ }
+
+ if (!b.double_byte.empty()) {
+ return false;
+ }
+
+ return a.cr.count() < b.cr.count();
+}
+
+static
+bool double_byte_ok(const AccelScheme &info) {
+ return !info.double_byte.empty() &&
+ info.double_cr.count() < info.double_byte.size() &&
info.double_cr.count() <= 2;
-}
-
-static
-bool has_self_loop(dstate_id_t s, const raw_dfa &raw) {
- u16 top_remap = raw.alpha_remap[TOP];
- for (u32 i = 0; i < raw.states[s].next.size(); i++) {
- if (i != top_remap && raw.states[s].next[i] == s) {
- return true;
- }
- }
- return false;
-}
-
-static
-flat_set<u16> find_nonexit_symbols(const raw_dfa &rdfa,
- const CharReach &escape) {
- flat_set<u16> rv;
- CharReach nonexit = ~escape;
- for (auto i = nonexit.find_first(); i != nonexit.npos;
- i = nonexit.find_next(i)) {
- rv.insert(rdfa.alpha_remap[i]);
- }
-
- return rv;
-}
-
-static
-dstate_id_t get_sds_or_proxy(const raw_dfa &raw) {
- if (raw.start_floating != DEAD_STATE) {
- DEBUG_PRINTF("has floating start\n");
- return raw.start_floating;
- }
-
- DEBUG_PRINTF("looking for SDS proxy\n");
-
- dstate_id_t s = raw.start_anchored;
-
- if (has_self_loop(s, raw)) {
- return s;
- }
-
- u16 top_remap = raw.alpha_remap[TOP];
-
- std::unordered_set<dstate_id_t> seen;
- while (true) {
- seen.insert(s);
- DEBUG_PRINTF("basis %hu\n", s);
-
- /* check if we are connected to a state with a self loop */
- for (u32 i = 0; i < raw.states[s].next.size(); i++) {
- dstate_id_t t = raw.states[s].next[i];
- if (i != top_remap && t != DEAD_STATE && has_self_loop(t, raw)) {
- return t;
- }
- }
-
- /* find a neighbour to use as a basis for looking for the sds proxy */
- dstate_id_t t = DEAD_STATE;
- for (u32 i = 0; i < raw.states[s].next.size(); i++) {
- dstate_id_t tt = raw.states[s].next[i];
- if (i != top_remap && tt != DEAD_STATE && !contains(seen, tt)) {
- t = tt;
- break;
- }
- }
-
- if (t == DEAD_STATE) {
- /* we were unable to find a state to use as a SDS proxy */
- return DEAD_STATE;
- }
-
- s = t;
- }
-}
-
-static
-set<dstate_id_t> find_region(const raw_dfa &rdfa, dstate_id_t base,
- const AccelScheme &ei) {
- DEBUG_PRINTF("looking for region around %hu\n", base);
-
- set<dstate_id_t> region = {base};
-
- if (!ei.double_byte.empty()) {
- return region;
- }
-
- DEBUG_PRINTF("accel %s+%u\n", describeClass(ei.cr).c_str(), ei.offset);
-
- const CharReach &escape = ei.cr;
- auto nonexit_symbols = find_nonexit_symbols(rdfa, escape);
-
- vector<dstate_id_t> pending = {base};
- while (!pending.empty()) {
- dstate_id_t curr = pending.back();
- pending.pop_back();
- for (auto s : nonexit_symbols) {
- dstate_id_t t = rdfa.states[curr].next[s];
- if (contains(region, t)) {
- continue;
- }
-
- DEBUG_PRINTF(" %hu is in region\n", t);
- region.insert(t);
- pending.push_back(t);
- }
- }
-
- return region;
-}
-
-AccelScheme
-accel_dfa_build_strat::find_escape_strings(dstate_id_t this_idx) const {
- AccelScheme rv;
- const raw_dfa &rdfa = get_raw();
- rv.cr.clear();
- rv.offset = 0;
- const dstate &raw = rdfa.states[this_idx];
- const vector<CharReach> rev_map = reverse_alpha_remapping(rdfa);
- bool outs2_broken = false;
- flat_map<dstate_id_t, CharReach> succs;
-
- for (u32 i = 0; i < rev_map.size(); i++) {
- if (raw.next[i] == this_idx) {
- continue;
- }
-
- const CharReach &cr_i = rev_map.at(i);
-
- rv.cr |= cr_i;
- dstate_id_t next_id = raw.next[i];
-
- DEBUG_PRINTF("next is %hu\n", next_id);
- const dstate &raw_next = rdfa.states[next_id];
-
- if (outs2_broken) {
- continue;
- }
-
- if (!raw_next.reports.empty() && generates_callbacks(rdfa.kind)) {
- DEBUG_PRINTF("leads to report\n");
- outs2_broken = true; /* cannot accelerate over reports */
- continue;
- }
- succs[next_id] |= cr_i;
- }
-
- if (!outs2_broken) {
- for (const auto &e : succs) {
- const CharReach &cr_i = e.second;
- const dstate &raw_next = rdfa.states[e.first];
-
- CharReach cr_all_j;
- for (u32 j = 0; j < rev_map.size(); j++) {
- if (raw_next.next[j] == raw.next[j]) {
- continue;
- }
-
- DEBUG_PRINTF("state %hu: adding sym %u -> %hu to 2 \n", e.first,
- j, raw_next.next[j]);
- cr_all_j |= rev_map.at(j);
- }
-
- if (cr_i.count() * cr_all_j.count() > 8) {
- DEBUG_PRINTF("adding %zu to double_cr\n", cr_i.count());
- rv.double_cr |= cr_i;
- } else {
- for (auto ii = cr_i.find_first(); ii != CharReach::npos;
- ii = cr_i.find_next(ii)) {
- for (auto jj = cr_all_j.find_first(); jj != CharReach::npos;
- jj = cr_all_j.find_next(jj)) {
- rv.double_byte.emplace((u8)ii, (u8)jj);
- if (rv.double_byte.size() > 8) {
- DEBUG_PRINTF("outs2 too big\n");
- outs2_broken = true;
- goto done;
- }
- }
- }
- }
- }
-
- done:
- assert(outs2_broken || rv.double_byte.size() <= 8);
- if (outs2_broken) {
- rv.double_byte.clear();
- }
- }
-
- DEBUG_PRINTF("this %u, sds proxy %hu\n", this_idx, get_sds_or_proxy(rdfa));
- DEBUG_PRINTF("broken %d\n", outs2_broken);
- if (!double_byte_ok(rv) && !is_triggered(rdfa.kind) &&
- this_idx == rdfa.start_floating && this_idx != DEAD_STATE) {
- DEBUG_PRINTF("looking for offset accel at %u\n", this_idx);
- auto offset =
- look_for_offset_accel(rdfa, this_idx, max_allowed_offset_accel());
- DEBUG_PRINTF("width %zu vs %zu\n", offset.cr.count(), rv.cr.count());
- if (double_byte_ok(offset) || offset.cr.count() < rv.cr.count()) {
- DEBUG_PRINTF("using offset accel\n");
- rv = offset;
- }
- }
-
- return rv;
-}
-
-void
-accel_dfa_build_strat::buildAccel(UNUSED dstate_id_t this_idx,
- const AccelScheme &info,
- void *accel_out) {
- AccelAux *accel = (AccelAux *)accel_out;
-
- DEBUG_PRINTF("accelerations scheme has offset s%u/d%u\n", info.offset,
- info.double_offset);
- accel->generic.offset = verify_u8(info.offset);
-
- if (double_byte_ok(info) && info.double_cr.none() &&
- info.double_byte.size() == 1) {
- accel->accel_type = ACCEL_DVERM;
- accel->dverm.c1 = info.double_byte.begin()->first;
- accel->dverm.c2 = info.double_byte.begin()->second;
- accel->dverm.offset = verify_u8(info.double_offset);
- DEBUG_PRINTF("state %hu is double vermicelli\n", this_idx);
- return;
- }
-
- if (double_byte_ok(info) && info.double_cr.none() &&
- (info.double_byte.size() == 2 || info.double_byte.size() == 4)) {
- bool ok = true;
-
- assert(!info.double_byte.empty());
- u8 firstC = info.double_byte.begin()->first & CASE_CLEAR;
- u8 secondC = info.double_byte.begin()->second & CASE_CLEAR;
-
- for (const pair<u8, u8> &p : info.double_byte) {
- if ((p.first & CASE_CLEAR) != firstC ||
- (p.second & CASE_CLEAR) != secondC) {
- ok = false;
- break;
- }
- }
-
- if (ok) {
- accel->accel_type = ACCEL_DVERM_NOCASE;
- accel->dverm.c1 = firstC;
- accel->dverm.c2 = secondC;
- accel->dverm.offset = verify_u8(info.double_offset);
- DEBUG_PRINTF("state %hu is nc double vermicelli\n", this_idx);
- return;
- }
-
- u8 m1;
- u8 m2;
- if (buildDvermMask(info.double_byte, &m1, &m2)) {
- accel->accel_type = ACCEL_DVERM_MASKED;
- accel->dverm.offset = verify_u8(info.double_offset);
- accel->dverm.c1 = info.double_byte.begin()->first & m1;
- accel->dverm.c2 = info.double_byte.begin()->second & m2;
- accel->dverm.m1 = m1;
- accel->dverm.m2 = m2;
- DEBUG_PRINTF(
- "building maskeddouble-vermicelli for 0x%02hhx%02hhx\n",
- accel->dverm.c1, accel->dverm.c2);
- return;
- }
- }
-
- if (double_byte_ok(info) &&
- shuftiBuildDoubleMasks(
- info.double_cr, info.double_byte, (u8 *)&accel->dshufti.lo1,
- (u8 *)&accel->dshufti.hi1, (u8 *)&accel->dshufti.lo2,
- (u8 *)&accel->dshufti.hi2)) {
- accel->accel_type = ACCEL_DSHUFTI;
- accel->dshufti.offset = verify_u8(info.double_offset);
- DEBUG_PRINTF("state %hu is double shufti\n", this_idx);
- return;
- }
-
- if (info.cr.none()) {
- accel->accel_type = ACCEL_RED_TAPE;
- DEBUG_PRINTF("state %hu is a dead end full of bureaucratic red tape"
- " from which there is no escape\n",
- this_idx);
- return;
- }
-
- if (info.cr.count() == 1) {
- accel->accel_type = ACCEL_VERM;
- accel->verm.c = info.cr.find_first();
- DEBUG_PRINTF("state %hu is vermicelli\n", this_idx);
- return;
- }
-
- if (info.cr.count() == 2 && info.cr.isCaselessChar()) {
- accel->accel_type = ACCEL_VERM_NOCASE;
- accel->verm.c = info.cr.find_first() & CASE_CLEAR;
- DEBUG_PRINTF("state %hu is caseless vermicelli\n", this_idx);
- return;
- }
-
- if (info.cr.count() > max_floating_stop_char()) {
- accel->accel_type = ACCEL_NONE;
- DEBUG_PRINTF("state %hu is too broad\n", this_idx);
- return;
- }
-
- accel->accel_type = ACCEL_SHUFTI;
- if (-1 != shuftiBuildMasks(info.cr, (u8 *)&accel->shufti.lo,
- (u8 *)&accel->shufti.hi)) {
- DEBUG_PRINTF("state %hu is shufti\n", this_idx);
- return;
- }
-
- assert(!info.cr.none());
- accel->accel_type = ACCEL_TRUFFLE;
- truffleBuildMasks(info.cr, (u8 *)&accel->truffle.mask1,
- (u8 *)&accel->truffle.mask2);
- DEBUG_PRINTF("state %hu is truffle\n", this_idx);
-}
-
-map<dstate_id_t, AccelScheme>
-accel_dfa_build_strat::getAccelInfo(const Grey &grey) {
- map<dstate_id_t, AccelScheme> rv;
- raw_dfa &rdfa = get_raw();
- if (!grey.accelerateDFA) {
- return rv;
- }
-
- dstate_id_t sds_proxy = get_sds_or_proxy(rdfa);
- DEBUG_PRINTF("sds %hu\n", sds_proxy);
-
- /* Find accel info for a single state. */
- auto do_state = [&](size_t i) {
- if (i == DEAD_STATE) {
- return;
- }
-
- /* Note on report acceleration states: While we can't accelerate while
- * we are spamming out callbacks, the QR code paths don't raise reports
- * during scanning so they can accelerate report states. */
- if (generates_callbacks(rdfa.kind) && !rdfa.states[i].reports.empty()) {
- return;
- }
-
- size_t single_limit =
- i == sds_proxy ? max_floating_stop_char() : max_stop_char();
- DEBUG_PRINTF("inspecting %zu/%hu: %zu\n", i, sds_proxy, single_limit);
-
- AccelScheme ei = find_escape_strings(i);
- if (ei.cr.count() > single_limit) {
- DEBUG_PRINTF("state %zu is not accelerable has %zu\n", i,
- ei.cr.count());
- return;
- }
-
- DEBUG_PRINTF("state %zu should be accelerable %zu\n", i, ei.cr.count());
-
- rv[i] = ei;
- };
-
- if (only_accel_init) {
- DEBUG_PRINTF("only computing accel for init states\n");
- do_state(rdfa.start_anchored);
- if (rdfa.start_floating != rdfa.start_anchored) {
- do_state(rdfa.start_floating);
- }
- } else {
- DEBUG_PRINTF("computing accel for all states\n");
- for (size_t i = 0; i < rdfa.states.size(); i++) {
- do_state(i);
- }
- }
-
- /* provide acceleration states to states in the region of sds */
- if (contains(rv, sds_proxy)) {
- AccelScheme sds_ei = rv[sds_proxy];
- sds_ei.double_byte.clear(); /* region based on single byte scheme
- * may differ from double byte */
- DEBUG_PRINTF("looking to expand offset accel to nearby states, %zu\n",
- sds_ei.cr.count());
- auto sds_region = find_region(rdfa, sds_proxy, sds_ei);
- for (auto s : sds_region) {
- if (!contains(rv, s) || better(sds_ei, rv[s])) {
- rv[s] = sds_ei;
- }
- }
- }
-
- return rv;
-}
-};
+}
+
+static
+bool has_self_loop(dstate_id_t s, const raw_dfa &raw) {
+ u16 top_remap = raw.alpha_remap[TOP];
+ for (u32 i = 0; i < raw.states[s].next.size(); i++) {
+ if (i != top_remap && raw.states[s].next[i] == s) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static
+flat_set<u16> find_nonexit_symbols(const raw_dfa &rdfa,
+ const CharReach &escape) {
+ flat_set<u16> rv;
+ CharReach nonexit = ~escape;
+ for (auto i = nonexit.find_first(); i != nonexit.npos;
+ i = nonexit.find_next(i)) {
+ rv.insert(rdfa.alpha_remap[i]);
+ }
+
+ return rv;
+}
+
+static
+dstate_id_t get_sds_or_proxy(const raw_dfa &raw) {
+ if (raw.start_floating != DEAD_STATE) {
+ DEBUG_PRINTF("has floating start\n");
+ return raw.start_floating;
+ }
+
+ DEBUG_PRINTF("looking for SDS proxy\n");
+
+ dstate_id_t s = raw.start_anchored;
+
+ if (has_self_loop(s, raw)) {
+ return s;
+ }
+
+ u16 top_remap = raw.alpha_remap[TOP];
+
+ std::unordered_set<dstate_id_t> seen;
+ while (true) {
+ seen.insert(s);
+ DEBUG_PRINTF("basis %hu\n", s);
+
+ /* check if we are connected to a state with a self loop */
+ for (u32 i = 0; i < raw.states[s].next.size(); i++) {
+ dstate_id_t t = raw.states[s].next[i];
+ if (i != top_remap && t != DEAD_STATE && has_self_loop(t, raw)) {
+ return t;
+ }
+ }
+
+ /* find a neighbour to use as a basis for looking for the sds proxy */
+ dstate_id_t t = DEAD_STATE;
+ for (u32 i = 0; i < raw.states[s].next.size(); i++) {
+ dstate_id_t tt = raw.states[s].next[i];
+ if (i != top_remap && tt != DEAD_STATE && !contains(seen, tt)) {
+ t = tt;
+ break;
+ }
+ }
+
+ if (t == DEAD_STATE) {
+ /* we were unable to find a state to use as a SDS proxy */
+ return DEAD_STATE;
+ }
+
+ s = t;
+ }
+}
+
+static
+set<dstate_id_t> find_region(const raw_dfa &rdfa, dstate_id_t base,
+ const AccelScheme &ei) {
+ DEBUG_PRINTF("looking for region around %hu\n", base);
+
+ set<dstate_id_t> region = {base};
+
+ if (!ei.double_byte.empty()) {
+ return region;
+ }
+
+ DEBUG_PRINTF("accel %s+%u\n", describeClass(ei.cr).c_str(), ei.offset);
+
+ const CharReach &escape = ei.cr;
+ auto nonexit_symbols = find_nonexit_symbols(rdfa, escape);
+
+ vector<dstate_id_t> pending = {base};
+ while (!pending.empty()) {
+ dstate_id_t curr = pending.back();
+ pending.pop_back();
+ for (auto s : nonexit_symbols) {
+ dstate_id_t t = rdfa.states[curr].next[s];
+ if (contains(region, t)) {
+ continue;
+ }
+
+ DEBUG_PRINTF(" %hu is in region\n", t);
+ region.insert(t);
+ pending.push_back(t);
+ }
+ }
+
+ return region;
+}
+
+AccelScheme
+accel_dfa_build_strat::find_escape_strings(dstate_id_t this_idx) const {
+ AccelScheme rv;
+ const raw_dfa &rdfa = get_raw();
+ rv.cr.clear();
+ rv.offset = 0;
+ const dstate &raw = rdfa.states[this_idx];
+ const vector<CharReach> rev_map = reverse_alpha_remapping(rdfa);
+ bool outs2_broken = false;
+ flat_map<dstate_id_t, CharReach> succs;
+
+ for (u32 i = 0; i < rev_map.size(); i++) {
+ if (raw.next[i] == this_idx) {
+ continue;
+ }
+
+ const CharReach &cr_i = rev_map.at(i);
+
+ rv.cr |= cr_i;
+ dstate_id_t next_id = raw.next[i];
+
+ DEBUG_PRINTF("next is %hu\n", next_id);
+ const dstate &raw_next = rdfa.states[next_id];
+
+ if (outs2_broken) {
+ continue;
+ }
+
+ if (!raw_next.reports.empty() && generates_callbacks(rdfa.kind)) {
+ DEBUG_PRINTF("leads to report\n");
+ outs2_broken = true; /* cannot accelerate over reports */
+ continue;
+ }
+ succs[next_id] |= cr_i;
+ }
+
+ if (!outs2_broken) {
+ for (const auto &e : succs) {
+ const CharReach &cr_i = e.second;
+ const dstate &raw_next = rdfa.states[e.first];
+
+ CharReach cr_all_j;
+ for (u32 j = 0; j < rev_map.size(); j++) {
+ if (raw_next.next[j] == raw.next[j]) {
+ continue;
+ }
+
+ DEBUG_PRINTF("state %hu: adding sym %u -> %hu to 2 \n", e.first,
+ j, raw_next.next[j]);
+ cr_all_j |= rev_map.at(j);
+ }
+
+ if (cr_i.count() * cr_all_j.count() > 8) {
+ DEBUG_PRINTF("adding %zu to double_cr\n", cr_i.count());
+ rv.double_cr |= cr_i;
+ } else {
+ for (auto ii = cr_i.find_first(); ii != CharReach::npos;
+ ii = cr_i.find_next(ii)) {
+ for (auto jj = cr_all_j.find_first(); jj != CharReach::npos;
+ jj = cr_all_j.find_next(jj)) {
+ rv.double_byte.emplace((u8)ii, (u8)jj);
+ if (rv.double_byte.size() > 8) {
+ DEBUG_PRINTF("outs2 too big\n");
+ outs2_broken = true;
+ goto done;
+ }
+ }
+ }
+ }
+ }
+
+ done:
+ assert(outs2_broken || rv.double_byte.size() <= 8);
+ if (outs2_broken) {
+ rv.double_byte.clear();
+ }
+ }
+
+ DEBUG_PRINTF("this %u, sds proxy %hu\n", this_idx, get_sds_or_proxy(rdfa));
+ DEBUG_PRINTF("broken %d\n", outs2_broken);
+ if (!double_byte_ok(rv) && !is_triggered(rdfa.kind) &&
+ this_idx == rdfa.start_floating && this_idx != DEAD_STATE) {
+ DEBUG_PRINTF("looking for offset accel at %u\n", this_idx);
+ auto offset =
+ look_for_offset_accel(rdfa, this_idx, max_allowed_offset_accel());
+ DEBUG_PRINTF("width %zu vs %zu\n", offset.cr.count(), rv.cr.count());
+ if (double_byte_ok(offset) || offset.cr.count() < rv.cr.count()) {
+ DEBUG_PRINTF("using offset accel\n");
+ rv = offset;
+ }
+ }
+
+ return rv;
+}
+
+void
+accel_dfa_build_strat::buildAccel(UNUSED dstate_id_t this_idx,
+ const AccelScheme &info,
+ void *accel_out) {
+ AccelAux *accel = (AccelAux *)accel_out;
+
+ DEBUG_PRINTF("accelerations scheme has offset s%u/d%u\n", info.offset,
+ info.double_offset);
+ accel->generic.offset = verify_u8(info.offset);
+
+ if (double_byte_ok(info) && info.double_cr.none() &&
+ info.double_byte.size() == 1) {
+ accel->accel_type = ACCEL_DVERM;
+ accel->dverm.c1 = info.double_byte.begin()->first;
+ accel->dverm.c2 = info.double_byte.begin()->second;
+ accel->dverm.offset = verify_u8(info.double_offset);
+ DEBUG_PRINTF("state %hu is double vermicelli\n", this_idx);
+ return;
+ }
+
+ if (double_byte_ok(info) && info.double_cr.none() &&
+ (info.double_byte.size() == 2 || info.double_byte.size() == 4)) {
+ bool ok = true;
+
+ assert(!info.double_byte.empty());
+ u8 firstC = info.double_byte.begin()->first & CASE_CLEAR;
+ u8 secondC = info.double_byte.begin()->second & CASE_CLEAR;
+
+ for (const pair<u8, u8> &p : info.double_byte) {
+ if ((p.first & CASE_CLEAR) != firstC ||
+ (p.second & CASE_CLEAR) != secondC) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ accel->accel_type = ACCEL_DVERM_NOCASE;
+ accel->dverm.c1 = firstC;
+ accel->dverm.c2 = secondC;
+ accel->dverm.offset = verify_u8(info.double_offset);
+ DEBUG_PRINTF("state %hu is nc double vermicelli\n", this_idx);
+ return;
+ }
+
+ u8 m1;
+ u8 m2;
+ if (buildDvermMask(info.double_byte, &m1, &m2)) {
+ accel->accel_type = ACCEL_DVERM_MASKED;
+ accel->dverm.offset = verify_u8(info.double_offset);
+ accel->dverm.c1 = info.double_byte.begin()->first & m1;
+ accel->dverm.c2 = info.double_byte.begin()->second & m2;
+ accel->dverm.m1 = m1;
+ accel->dverm.m2 = m2;
+ DEBUG_PRINTF(
+ "building maskeddouble-vermicelli for 0x%02hhx%02hhx\n",
+ accel->dverm.c1, accel->dverm.c2);
+ return;
+ }
+ }
+
+ if (double_byte_ok(info) &&
+ shuftiBuildDoubleMasks(
+ info.double_cr, info.double_byte, (u8 *)&accel->dshufti.lo1,
+ (u8 *)&accel->dshufti.hi1, (u8 *)&accel->dshufti.lo2,
+ (u8 *)&accel->dshufti.hi2)) {
+ accel->accel_type = ACCEL_DSHUFTI;
+ accel->dshufti.offset = verify_u8(info.double_offset);
+ DEBUG_PRINTF("state %hu is double shufti\n", this_idx);
+ return;
+ }
+
+ if (info.cr.none()) {
+ accel->accel_type = ACCEL_RED_TAPE;
+ DEBUG_PRINTF("state %hu is a dead end full of bureaucratic red tape"
+ " from which there is no escape\n",
+ this_idx);
+ return;
+ }
+
+ if (info.cr.count() == 1) {
+ accel->accel_type = ACCEL_VERM;
+ accel->verm.c = info.cr.find_first();
+ DEBUG_PRINTF("state %hu is vermicelli\n", this_idx);
+ return;
+ }
+
+ if (info.cr.count() == 2 && info.cr.isCaselessChar()) {
+ accel->accel_type = ACCEL_VERM_NOCASE;
+ accel->verm.c = info.cr.find_first() & CASE_CLEAR;
+ DEBUG_PRINTF("state %hu is caseless vermicelli\n", this_idx);
+ return;
+ }
+
+ if (info.cr.count() > max_floating_stop_char()) {
+ accel->accel_type = ACCEL_NONE;
+ DEBUG_PRINTF("state %hu is too broad\n", this_idx);
+ return;
+ }
+
+ accel->accel_type = ACCEL_SHUFTI;
+ if (-1 != shuftiBuildMasks(info.cr, (u8 *)&accel->shufti.lo,
+ (u8 *)&accel->shufti.hi)) {
+ DEBUG_PRINTF("state %hu is shufti\n", this_idx);
+ return;
+ }
+
+ assert(!info.cr.none());
+ accel->accel_type = ACCEL_TRUFFLE;
+ truffleBuildMasks(info.cr, (u8 *)&accel->truffle.mask1,
+ (u8 *)&accel->truffle.mask2);
+ DEBUG_PRINTF("state %hu is truffle\n", this_idx);
+}
+
+map<dstate_id_t, AccelScheme>
+accel_dfa_build_strat::getAccelInfo(const Grey &grey) {
+ map<dstate_id_t, AccelScheme> rv;
+ raw_dfa &rdfa = get_raw();
+ if (!grey.accelerateDFA) {
+ return rv;
+ }
+
+ dstate_id_t sds_proxy = get_sds_or_proxy(rdfa);
+ DEBUG_PRINTF("sds %hu\n", sds_proxy);
+
+ /* Find accel info for a single state. */
+ auto do_state = [&](size_t i) {
+ if (i == DEAD_STATE) {
+ return;
+ }
+
+ /* Note on report acceleration states: While we can't accelerate while
+ * we are spamming out callbacks, the QR code paths don't raise reports
+ * during scanning so they can accelerate report states. */
+ if (generates_callbacks(rdfa.kind) && !rdfa.states[i].reports.empty()) {
+ return;
+ }
+
+ size_t single_limit =
+ i == sds_proxy ? max_floating_stop_char() : max_stop_char();
+ DEBUG_PRINTF("inspecting %zu/%hu: %zu\n", i, sds_proxy, single_limit);
+
+ AccelScheme ei = find_escape_strings(i);
+ if (ei.cr.count() > single_limit) {
+ DEBUG_PRINTF("state %zu is not accelerable has %zu\n", i,
+ ei.cr.count());
+ return;
+ }
+
+ DEBUG_PRINTF("state %zu should be accelerable %zu\n", i, ei.cr.count());
+
+ rv[i] = ei;
+ };
+
+ if (only_accel_init) {
+ DEBUG_PRINTF("only computing accel for init states\n");
+ do_state(rdfa.start_anchored);
+ if (rdfa.start_floating != rdfa.start_anchored) {
+ do_state(rdfa.start_floating);
+ }
+ } else {
+ DEBUG_PRINTF("computing accel for all states\n");
+ for (size_t i = 0; i < rdfa.states.size(); i++) {
+ do_state(i);
+ }
+ }
+
+ /* provide acceleration states to states in the region of sds */
+ if (contains(rv, sds_proxy)) {
+ AccelScheme sds_ei = rv[sds_proxy];
+ sds_ei.double_byte.clear(); /* region based on single byte scheme
+ * may differ from double byte */
+ DEBUG_PRINTF("looking to expand offset accel to nearby states, %zu\n",
+ sds_ei.cr.count());
+ auto sds_region = find_region(rdfa, sds_proxy, sds_ei);
+ for (auto s : sds_region) {
+ if (!contains(rv, s) || better(sds_ei, rv[s])) {
+ rv[s] = sds_ei;
+ }
+ }
+ }
+
+ return rv;
+}
+};
diff --git a/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.h b/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.h
index 934f422d73d..53a6f35b3d4 100644
--- a/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.h
+++ b/contrib/libs/hyperscan/src/nfa/accel_dfa_build_strat.h
@@ -1,69 +1,69 @@
-/*
+/*
* Copyright (c) 2015-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ACCEL_DFA_BUILD_STRAT_H
-#define ACCEL_DFA_BUILD_STRAT_H
-
-#include "rdfa.h"
-#include "dfa_build_strat.h"
-#include "ue2common.h"
-#include "util/accel_scheme.h"
-
-#include <map>
-
-namespace ue2 {
-
-class ReportManager;
-struct Grey;
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ACCEL_DFA_BUILD_STRAT_H
+#define ACCEL_DFA_BUILD_STRAT_H
+
+#include "rdfa.h"
+#include "dfa_build_strat.h"
+#include "ue2common.h"
+#include "util/accel_scheme.h"
+
+#include <map>
+
+namespace ue2 {
+
+class ReportManager;
+struct Grey;
enum DfaType {
McClellan,
Sheng,
Gough
};
-
-class accel_dfa_build_strat : public dfa_build_strat {
-public:
- accel_dfa_build_strat(const ReportManager &rm_in, bool only_accel_init_in)
- : dfa_build_strat(rm_in), only_accel_init(only_accel_init_in) {}
- virtual AccelScheme find_escape_strings(dstate_id_t this_idx) const;
- virtual size_t accelSize(void) const = 0;
- virtual u32 max_allowed_offset_accel() const = 0;
- virtual u32 max_stop_char() const = 0;
- virtual u32 max_floating_stop_char() const = 0;
- virtual void buildAccel(dstate_id_t this_idx, const AccelScheme &info,
- void *accel_out);
- virtual std::map<dstate_id_t, AccelScheme> getAccelInfo(const Grey &grey);
+
+class accel_dfa_build_strat : public dfa_build_strat {
+public:
+ accel_dfa_build_strat(const ReportManager &rm_in, bool only_accel_init_in)
+ : dfa_build_strat(rm_in), only_accel_init(only_accel_init_in) {}
+ virtual AccelScheme find_escape_strings(dstate_id_t this_idx) const;
+ virtual size_t accelSize(void) const = 0;
+ virtual u32 max_allowed_offset_accel() const = 0;
+ virtual u32 max_stop_char() const = 0;
+ virtual u32 max_floating_stop_char() const = 0;
+ virtual void buildAccel(dstate_id_t this_idx, const AccelScheme &info,
+ void *accel_out);
+ virtual std::map<dstate_id_t, AccelScheme> getAccelInfo(const Grey &grey);
virtual DfaType getType() const = 0;
-private:
- bool only_accel_init;
-};
-
-} // namespace ue2
-
-#endif // ACCEL_DFA_BUILD_STRAT_H
+private:
+ bool only_accel_init;
+};
+
+} // namespace ue2
+
+#endif // ACCEL_DFA_BUILD_STRAT_H
diff --git a/contrib/libs/hyperscan/src/nfa/accelcompile.cpp b/contrib/libs/hyperscan/src/nfa/accelcompile.cpp
index 092388e6a72..a224410dc92 100644
--- a/contrib/libs/hyperscan/src/nfa/accelcompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/accelcompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -72,8 +72,8 @@ void buildAccelSingle(const AccelInfo &info, AccelAux *aux) {
}
DEBUG_PRINTF("attempting shufti for %zu chars\n", outs);
- if (-1 != shuftiBuildMasks(info.single_stops, (u8 *)&aux->shufti.lo,
- (u8 *)&aux->shufti.hi)) {
+ if (-1 != shuftiBuildMasks(info.single_stops, (u8 *)&aux->shufti.lo,
+ (u8 *)&aux->shufti.hi)) {
aux->accel_type = ACCEL_SHUFTI;
aux->shufti.offset = offset;
DEBUG_PRINTF("shufti built OK\n");
@@ -86,55 +86,55 @@ void buildAccelSingle(const AccelInfo &info, AccelAux *aux) {
DEBUG_PRINTF("building Truffle for %zu chars\n", outs);
aux->accel_type = ACCEL_TRUFFLE;
aux->truffle.offset = offset;
- truffleBuildMasks(info.single_stops, (u8 *)&aux->truffle.mask1,
- (u8 *)&aux->truffle.mask2);
+ truffleBuildMasks(info.single_stops, (u8 *)&aux->truffle.mask1,
+ (u8 *)&aux->truffle.mask2);
return;
}
DEBUG_PRINTF("unable to accelerate case with %zu outs\n", outs);
}
-bool buildDvermMask(const flat_set<pair<u8, u8>> &escape_set, u8 *m1_out,
- u8 *m2_out) {
- u8 a1 = 0xff;
- u8 a2 = 0xff;
- u8 b1 = 0xff;
- u8 b2 = 0xff;
-
- for (const auto &e : escape_set) {
- DEBUG_PRINTF("%0hhx %0hhx\n", e.first, e.second);
- a1 &= e.first;
- b1 &= ~e.first;
- a2 &= e.second;
- b2 &= ~e.second;
- }
-
- u8 m1 = a1 | b1;
- u8 m2 = a2 | b2;
-
- u32 holes1 = 8 - popcount32(m1);
- u32 holes2 = 8 - popcount32(m2);
-
- DEBUG_PRINTF("aaaa %0hhx %0hhx\n", a1, a2);
- DEBUG_PRINTF("bbbb %0hhx %0hhx\n", b1, b2);
- DEBUG_PRINTF("mask %0hhx %0hhx\n", m1, m2);
-
- assert(holes1 <= 8 && holes2 <= 8);
- assert(escape_set.size() <= 1U << (holes1 + holes2));
- if (escape_set.size() != 1U << (holes1 + holes2)) {
- return false;
- }
-
- if (m1_out) {
- *m1_out = m1;
- }
- if (m2_out) {
- *m2_out = m2;
- }
-
- return true;
-}
-
+bool buildDvermMask(const flat_set<pair<u8, u8>> &escape_set, u8 *m1_out,
+ u8 *m2_out) {
+ u8 a1 = 0xff;
+ u8 a2 = 0xff;
+ u8 b1 = 0xff;
+ u8 b2 = 0xff;
+
+ for (const auto &e : escape_set) {
+ DEBUG_PRINTF("%0hhx %0hhx\n", e.first, e.second);
+ a1 &= e.first;
+ b1 &= ~e.first;
+ a2 &= e.second;
+ b2 &= ~e.second;
+ }
+
+ u8 m1 = a1 | b1;
+ u8 m2 = a2 | b2;
+
+ u32 holes1 = 8 - popcount32(m1);
+ u32 holes2 = 8 - popcount32(m2);
+
+ DEBUG_PRINTF("aaaa %0hhx %0hhx\n", a1, a2);
+ DEBUG_PRINTF("bbbb %0hhx %0hhx\n", b1, b2);
+ DEBUG_PRINTF("mask %0hhx %0hhx\n", m1, m2);
+
+ assert(holes1 <= 8 && holes2 <= 8);
+ assert(escape_set.size() <= 1U << (holes1 + holes2));
+ if (escape_set.size() != 1U << (holes1 + holes2)) {
+ return false;
+ }
+
+ if (m1_out) {
+ *m1_out = m1;
+ }
+ if (m2_out) {
+ *m2_out = m2;
+ }
+
+ return true;
+}
+
static
bool isCaselessDouble(const flat_set<pair<u8, u8>> &stop) {
// test for vector containing <A,Z> <A,z> <a,Z> <a,z>
@@ -190,36 +190,36 @@ void buildAccelDouble(const AccelInfo &info, AccelAux *aux) {
return;
}
- if (outs1 == 0) {
- u8 m1;
- u8 m2;
-
- if (buildDvermMask(info.double_stop2, &m1, &m2)) {
- aux->accel_type = ACCEL_DVERM_MASKED;
- aux->dverm.offset = offset;
- aux->dverm.c1 = info.double_stop2.begin()->first & m1;
- aux->dverm.c2 = info.double_stop2.begin()->second & m2;
- aux->dverm.m1 = m1;
- aux->dverm.m2 = m2;
- DEBUG_PRINTF("building maskeddouble-vermicelli for 0x%02hhx%02hhx\n",
- aux->dverm.c1, aux->dverm.c2);
+ if (outs1 == 0) {
+ u8 m1;
+ u8 m2;
+
+ if (buildDvermMask(info.double_stop2, &m1, &m2)) {
+ aux->accel_type = ACCEL_DVERM_MASKED;
+ aux->dverm.offset = offset;
+ aux->dverm.c1 = info.double_stop2.begin()->first & m1;
+ aux->dverm.c2 = info.double_stop2.begin()->second & m2;
+ aux->dverm.m1 = m1;
+ aux->dverm.m2 = m2;
+ DEBUG_PRINTF("building maskeddouble-vermicelli for 0x%02hhx%02hhx\n",
+ aux->dverm.c1, aux->dverm.c2);
+ return;
+ }
+ }
+
+ if (outs1 < outs2 && outs1 <= 2) { // Heuristic from UE-438.
+ DEBUG_PRINTF("building double-shufti for %zu one-byte and %zu"
+ " two-byte literals\n", outs1, outs2);
+ aux->accel_type = ACCEL_DSHUFTI;
+ aux->dshufti.offset = offset;
+ if (shuftiBuildDoubleMasks(
+ info.double_stop1, info.double_stop2, (u8 *)&aux->dshufti.lo1,
+ (u8 *)&aux->dshufti.hi1, (u8 *)&aux->dshufti.lo2,
+ (u8 *)&aux->dshufti.hi2)) {
return;
}
}
- if (outs1 < outs2 && outs1 <= 2) { // Heuristic from UE-438.
- DEBUG_PRINTF("building double-shufti for %zu one-byte and %zu"
- " two-byte literals\n", outs1, outs2);
- aux->accel_type = ACCEL_DSHUFTI;
- aux->dshufti.offset = offset;
- if (shuftiBuildDoubleMasks(
- info.double_stop1, info.double_stop2, (u8 *)&aux->dshufti.lo1,
- (u8 *)&aux->dshufti.hi1, (u8 *)&aux->dshufti.lo2,
- (u8 *)&aux->dshufti.hi2)) {
- return;
- }
- }
-
// drop back to attempt single-byte accel
DEBUG_PRINTF("dropping back to single-byte acceleration\n");
aux->accel_type = ACCEL_NONE;
@@ -231,8 +231,8 @@ bool buildAccelAux(const AccelInfo &info, AccelAux *aux) {
DEBUG_PRINTF("picked red tape\n");
aux->accel_type = ACCEL_RED_TAPE;
aux->generic.offset = info.single_offset;
- }
- if (aux->accel_type == ACCEL_NONE) {
+ }
+ if (aux->accel_type == ACCEL_NONE) {
buildAccelDouble(info, aux);
}
if (aux->accel_type == ACCEL_NONE) {
diff --git a/contrib/libs/hyperscan/src/nfa/accelcompile.h b/contrib/libs/hyperscan/src/nfa/accelcompile.h
index c1930d22475..d0b3cdc74f7 100644
--- a/contrib/libs/hyperscan/src/nfa/accelcompile.h
+++ b/contrib/libs/hyperscan/src/nfa/accelcompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,7 @@
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
union AccelAux;
@@ -51,10 +51,10 @@ struct AccelInfo {
bool buildAccelAux(const AccelInfo &info, AccelAux *aux);
-/* returns true is the escape set can be handled with a masked double_verm */
-bool buildDvermMask(const flat_set<std::pair<u8, u8>> &escape_set,
- u8 *m1_out = nullptr, u8 *m2_out = nullptr);
-
+/* returns true is the escape set can be handled with a masked double_verm */
+bool buildDvermMask(const flat_set<std::pair<u8, u8>> &escape_set,
+ u8 *m1_out = nullptr, u8 *m2_out = nullptr);
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfa/callback.h b/contrib/libs/hyperscan/src/nfa/callback.h
index 8550e33c840..9bdaa8d141d 100644
--- a/contrib/libs/hyperscan/src/nfa/callback.h
+++ b/contrib/libs/hyperscan/src/nfa/callback.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,26 +37,26 @@
/** \brief The type for an NFA callback.
*
- * This is a function that takes as arguments the current start and end offsets
- * where the match occurs, the id of the match and the context pointer that was
- * passed into the NFA API function that executed the NFA.
+ * This is a function that takes as arguments the current start and end offsets
+ * where the match occurs, the id of the match and the context pointer that was
+ * passed into the NFA API function that executed the NFA.
*
- * The start offset is the "start of match" (SOM) offset for the match. It is
- * only provided by engines that natively support SOM tracking (e.g. Gough).
+ * The start offset is the "start of match" (SOM) offset for the match. It is
+ * only provided by engines that natively support SOM tracking (e.g. Gough).
+ *
+ * The end offset will be the offset after the character that caused the match.
+ * Thus, if we have a buffer containing 'abc', then a pattern that matches an
+ * empty string will have an offset of 0, a pattern that matches 'a' will have
+ * an offset of 1, and a pattern that matches 'abc' will have an offset of 3,
+ * which will be a value that is 'beyond' the size of the buffer. That is, if
+ * we have n characters in the buffer, there are n+1 different potential
+ * offsets for matches.
*
- * The end offset will be the offset after the character that caused the match.
- * Thus, if we have a buffer containing 'abc', then a pattern that matches an
- * empty string will have an offset of 0, a pattern that matches 'a' will have
- * an offset of 1, and a pattern that matches 'abc' will have an offset of 3,
- * which will be a value that is 'beyond' the size of the buffer. That is, if
- * we have n characters in the buffer, there are n+1 different potential
- * offsets for matches.
- *
* This function should return an int - currently the possible return values
* are 0, which means 'stop running the engine' or non-zero, which means
* 'continue matching'.
*/
-typedef int (*NfaCallback)(u64a start, u64a end, ReportID id, void *context);
+typedef int (*NfaCallback)(u64a start, u64a end, ReportID id, void *context);
/**
* standard \ref NfaCallback return value indicating that engine execution
diff --git a/contrib/libs/hyperscan/src/nfa/castle.c b/contrib/libs/hyperscan/src/nfa/castle.c
index 175a709ee1a..7c158b31c01 100644
--- a/contrib/libs/hyperscan/src/nfa/castle.c
+++ b/contrib/libs/hyperscan/src/nfa/castle.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -96,9 +96,9 @@ char subCastleReportCurrent(const struct Castle *c, struct mq *q,
repeatHasMatch(info, rctrl, rstate, offset);
DEBUG_PRINTF("repeatHasMatch returned %d\n", match);
if (match == REPEAT_MATCH) {
- DEBUG_PRINTF("firing match at %llu for sub %u, report %u\n", offset,
- subIdx, sub->report);
- if (q->cb(0, offset, sub->report, q->context) == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("firing match at %llu for sub %u, report %u\n", offset,
+ subIdx, sub->report);
+ if (q->cb(0, offset, sub->report, q->context) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
}
}
@@ -112,22 +112,22 @@ int castleReportCurrent(const struct Castle *c, struct mq *q) {
DEBUG_PRINTF("offset=%llu\n", offset);
if (c->exclusive) {
- u8 *active = (u8 *)q->streamState;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
- DEBUG_PRINTF("subcastle %u\n", activeIdx);
- if (subCastleReportCurrent(c, q,
- offset, activeIdx) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
+ u8 *active = (u8 *)q->streamState;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ DEBUG_PRINTF("subcastle %u\n", activeIdx);
+ if (subCastleReportCurrent(c, q,
+ offset, activeIdx) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- const u8 *active = (const u8 *)q->streamState + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ const u8 *active = (const u8 *)q->streamState + c->activeOffset;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
DEBUG_PRINTF("subcastle %u\n", i);
@@ -168,18 +168,18 @@ static really_inline
char castleInAccept(const struct Castle *c, struct mq *q,
const ReportID report, const u64a offset) {
DEBUG_PRINTF("offset=%llu\n", offset);
- /* ignore when just catching up due to full queue */
- if (report == MO_INVALID_IDX) {
- return 0;
- }
+ /* ignore when just catching up due to full queue */
+ if (report == MO_INVALID_IDX) {
+ return 0;
+ }
if (c->exclusive) {
- u8 *active = (u8 *)q->streamState;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ u8 *active = (u8 *)q->streamState;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
DEBUG_PRINTF("subcastle %u\n", activeIdx);
if (subCastleInAccept(c, q, report, offset, activeIdx)) {
return 1;
@@ -187,10 +187,10 @@ char castleInAccept(const struct Castle *c, struct mq *q,
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- const u8 *active = (const u8 *)q->streamState + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ const u8 *active = (const u8 *)q->streamState + c->activeOffset;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
+ i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
DEBUG_PRINTF("subcastle %u\n", i);
if (subCastleInAccept(c, q, report, offset, i)) {
return 1;
@@ -214,13 +214,13 @@ void subCastleDeactivateStaleSubs(const struct Castle *c, const u64a offset,
if (repeatHasMatch(info, rctrl, rstate, offset) == REPEAT_STALE) {
DEBUG_PRINTF("sub %u is stale at offset %llu\n", subIdx, offset);
- if (sub->exclusiveId < c->numRepeats) {
- u8 *active = (u8 *)stream_state;
- u8 *groups = active + c->groupIterOffset;
- mmbit_unset(groups, c->numGroups, sub->exclusiveId);
+ if (sub->exclusiveId < c->numRepeats) {
+ u8 *active = (u8 *)stream_state;
+ u8 *groups = active + c->groupIterOffset;
+ mmbit_unset(groups, c->numGroups, sub->exclusiveId);
} else {
- u8 *active = (u8 *)stream_state + c->activeOffset;
- mmbit_unset(active, c->numRepeats, subIdx);
+ u8 *active = (u8 *)stream_state + c->activeOffset;
+ mmbit_unset(active, c->numRepeats, subIdx);
}
}
}
@@ -230,47 +230,47 @@ void castleDeactivateStaleSubs(const struct Castle *c, const u64a offset,
void *full_state, void *stream_state) {
DEBUG_PRINTF("offset=%llu\n", offset);
- if (!c->staleIterOffset) {
- DEBUG_PRINTF("{no repeats can go stale}\n");
- return; /* no subcastle can ever go stale */
- }
-
+ if (!c->staleIterOffset) {
+ DEBUG_PRINTF("{no repeats can go stale}\n");
+ return; /* no subcastle can ever go stale */
+ }
+
if (c->exclusive) {
- u8 *active = (u8 *)stream_state;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ u8 *active = (u8 *)stream_state;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
DEBUG_PRINTF("subcastle %u\n", activeIdx);
subCastleDeactivateStaleSubs(c, offset, full_state,
stream_state, activeIdx);
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- const u8 *active = (const u8 *)stream_state + c->activeOffset;
- const struct mmbit_sparse_iter *it
- = (const void *)((const char *)c + c->staleIterOffset);
-
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
- u32 numRepeats = c->numRepeats;
- u32 idx = 0;
-
- u32 i = mmbit_sparse_iter_begin(active, numRepeats, &idx, it, si_state);
- while(i != MMB_INVALID) {
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ const u8 *active = (const u8 *)stream_state + c->activeOffset;
+ const struct mmbit_sparse_iter *it
+ = (const void *)((const char *)c + c->staleIterOffset);
+
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+ u32 numRepeats = c->numRepeats;
+ u32 idx = 0;
+
+ u32 i = mmbit_sparse_iter_begin(active, numRepeats, &idx, it, si_state);
+ while(i != MMB_INVALID) {
DEBUG_PRINTF("subcastle %u\n", i);
- subCastleDeactivateStaleSubs(c, offset, full_state, stream_state, i);
- i = mmbit_sparse_iter_next(active, numRepeats, i, &idx, it,
- si_state);
+ subCastleDeactivateStaleSubs(c, offset, full_state, stream_state, i);
+ i = mmbit_sparse_iter_next(active, numRepeats, i, &idx, it,
+ si_state);
}
}
}
static really_inline
void castleProcessTop(const struct Castle *c, const u32 top, const u64a offset,
- void *full_state, void *stream_state,
- UNUSED char stale_checked) {
+ void *full_state, void *stream_state,
+ UNUSED char stale_checked) {
assert(top < c->numRepeats);
const struct SubCastle *sub = getSubCastle(c, top);
@@ -280,20 +280,20 @@ void castleProcessTop(const struct Castle *c, const u32 top, const u64a offset,
info->packedCtrlSize;
char is_alive = 0;
- u8 *active = (u8 *)stream_state;
- if (sub->exclusiveId < c->numRepeats) {
- u8 *groups = active + c->groupIterOffset;
- active += sub->exclusiveId * c->activeIdxSize;
- if (mmbit_set(groups, c->numGroups, sub->exclusiveId)) {
- const u32 activeIdx = partial_load_u32(active, c->activeIdxSize);
- is_alive = (activeIdx == top);
- }
-
- if (!is_alive) {
- partial_store_u32(active, top, c->activeIdxSize);
- }
+ u8 *active = (u8 *)stream_state;
+ if (sub->exclusiveId < c->numRepeats) {
+ u8 *groups = active + c->groupIterOffset;
+ active += sub->exclusiveId * c->activeIdxSize;
+ if (mmbit_set(groups, c->numGroups, sub->exclusiveId)) {
+ const u32 activeIdx = partial_load_u32(active, c->activeIdxSize);
+ is_alive = (activeIdx == top);
+ }
+
+ if (!is_alive) {
+ partial_store_u32(active, top, c->activeIdxSize);
+ }
} else {
- active += c->activeOffset;
+ active += c->activeOffset;
is_alive = mmbit_set(active, c->numRepeats, top);
}
@@ -302,8 +302,8 @@ void castleProcessTop(const struct Castle *c, const u32 top, const u64a offset,
} else {
DEBUG_PRINTF("repeat %u is already alive\n", top);
// Caller should ensure we're not stale.
- assert(!stale_checked
- || repeatHasMatch(info, rctrl, rstate, offset) != REPEAT_STALE);
+ assert(!stale_checked
+ || repeatHasMatch(info, rctrl, rstate, offset) != REPEAT_STALE);
// Ignore duplicate top events.
u64a last = repeatLastTop(info, rctrl, rstate);
@@ -331,11 +331,11 @@ void subCastleFindMatch(const struct Castle *c, const u64a begin,
u64a match = repeatNextMatch(info, rctrl, rstate, begin);
if (match == 0) {
DEBUG_PRINTF("no more matches for sub %u\n", subIdx);
- if (sub->exclusiveId < c->numRepeats) {
- u8 *groups = (u8 *)stream_state + c->groupIterOffset;
- mmbit_unset(groups, c->numGroups, sub->exclusiveId);
+ if (sub->exclusiveId < c->numRepeats) {
+ u8 *groups = (u8 *)stream_state + c->groupIterOffset;
+ mmbit_unset(groups, c->numGroups, sub->exclusiveId);
} else {
- u8 *active = (u8 *)stream_state + c->activeOffset;
+ u8 *active = (u8 *)stream_state + c->activeOffset;
mmbit_unset(active, c->numRepeats, subIdx);
}
return;
@@ -368,20 +368,20 @@ char castleFindMatch(const struct Castle *c, const u64a begin, const u64a end,
*mloc = 0;
if (c->exclusive) {
- u8 *active = (u8 *)stream_state;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ u8 *active = (u8 *)stream_state;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
DEBUG_PRINTF("subcastle %u\n", activeIdx);
subCastleFindMatch(c, begin, end, full_state, stream_state, mloc,
&found, activeIdx);
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- u8 *active = (u8 *)stream_state + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ u8 *active = (u8 *)stream_state + c->activeOffset;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
i != MMB_INVALID;
i = mmbit_iterate(active, c->numRepeats, i)) {
@@ -411,37 +411,37 @@ u64a subCastleNextMatch(const struct Castle *c, void *full_state,
}
static really_inline
-void set_matching(const struct Castle *c, const u64a match, u8 *active,
- u8 *matching, const u32 active_size, const u32 active_id,
- const u32 matching_id, u64a *offset, const u64a end) {
- if (match == 0) {
- DEBUG_PRINTF("no more matches\n");
- mmbit_unset(active, active_size, active_id);
- } else if (match > end) {
- // If we had a local copy of the active mmbit, we could skip
- // looking at this repeat again. But we don't, so we just move
- // on.
- } else if (match == *offset) {
- mmbit_set(matching, c->numRepeats, matching_id);
- } else if (match < *offset) {
- // New minimum offset.
- *offset = match;
- mmbit_clear(matching, c->numRepeats);
- mmbit_set(matching, c->numRepeats, matching_id);
- }
-}
-
-static really_inline
+void set_matching(const struct Castle *c, const u64a match, u8 *active,
+ u8 *matching, const u32 active_size, const u32 active_id,
+ const u32 matching_id, u64a *offset, const u64a end) {
+ if (match == 0) {
+ DEBUG_PRINTF("no more matches\n");
+ mmbit_unset(active, active_size, active_id);
+ } else if (match > end) {
+ // If we had a local copy of the active mmbit, we could skip
+ // looking at this repeat again. But we don't, so we just move
+ // on.
+ } else if (match == *offset) {
+ mmbit_set(matching, c->numRepeats, matching_id);
+ } else if (match < *offset) {
+ // New minimum offset.
+ *offset = match;
+ mmbit_clear(matching, c->numRepeats);
+ mmbit_set(matching, c->numRepeats, matching_id);
+ }
+}
+
+static really_inline
void subCastleMatchLoop(const struct Castle *c, void *full_state,
void *stream_state, const u64a end,
const u64a loc, u64a *offset) {
- u8 *active = (u8 *)stream_state + c->activeOffset;
+ u8 *active = (u8 *)stream_state + c->activeOffset;
u8 *matching = full_state;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
u64a match = subCastleNextMatch(c, full_state, stream_state, loc, i);
- set_matching(c, match, active, matching, c->numRepeats, i,
- i, offset, end);
+ set_matching(c, match, active, matching, c->numRepeats, i,
+ i, offset, end);
}
}
@@ -457,7 +457,7 @@ char subCastleFireMatch(const struct Castle *c, const void *full_state,
i = mmbit_iterate(matching, c->numRepeats, i)) {
const struct SubCastle *sub = getSubCastle(c, i);
DEBUG_PRINTF("firing match at %llu for sub %u\n", offset, i);
- if (cb(0, offset, sub->report, ctx) == MO_HALT_MATCHING) {
+ if (cb(0, offset, sub->report, ctx) == MO_HALT_MATCHING) {
DEBUG_PRINTF("caller told us to halt\n");
return MO_HALT_MATCHING;
}
@@ -485,36 +485,36 @@ char castleMatchLoop(const struct Castle *c, const u64a begin, const u64a end,
u64a offset = end; // min offset of next match
u32 activeIdx = 0;
- mmbit_clear(matching, c->numRepeats);
+ mmbit_clear(matching, c->numRepeats);
if (c->exclusive) {
- u8 *active = (u8 *)stream_state;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ u8 *active = (u8 *)stream_state;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ activeIdx = partial_load_u32(cur, c->activeIdxSize);
u64a match = subCastleNextMatch(c, full_state, stream_state,
- loc, activeIdx);
- set_matching(c, match, groups, matching, c->numGroups, i,
- activeIdx, &offset, end);
+ loc, activeIdx);
+ set_matching(c, match, groups, matching, c->numGroups, i,
+ activeIdx, &offset, end);
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
+ if (c->exclusive != PURE_EXCLUSIVE) {
subCastleMatchLoop(c, full_state, stream_state,
- end, loc, &offset);
+ end, loc, &offset);
}
- DEBUG_PRINTF("offset=%llu\n", offset);
- if (!mmbit_any(matching, c->numRepeats)) {
- DEBUG_PRINTF("no more matches\n");
+ DEBUG_PRINTF("offset=%llu\n", offset);
+ if (!mmbit_any(matching, c->numRepeats)) {
+ DEBUG_PRINTF("no more matches\n");
break;
}
-
- if (subCastleFireMatch(c, full_state, stream_state,
- cb, ctx, offset) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- loc = offset;
+
+ if (subCastleFireMatch(c, full_state, stream_state,
+ cb, ctx, offset) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ loc = offset;
}
return MO_CONTINUE_MATCHING;
@@ -573,8 +573,8 @@ char castleScanShufti(const struct Castle *c, const u8 *buf, const size_t begin,
static really_inline
char castleScanTruffle(const struct Castle *c, const u8 *buf, const size_t begin,
const size_t end, size_t *loc) {
- const u8 *ptr = truffleExec(c->u.truffle.mask1, c->u.truffle.mask2,
- buf + begin, buf + end);
+ const u8 *ptr = truffleExec(c->u.truffle.mask1, c->u.truffle.mask2,
+ buf + begin, buf + end);
if (ptr == buf + end) {
DEBUG_PRINTF("no escape found\n");
return 0;
@@ -616,103 +616,103 @@ char castleScan(const struct Castle *c, const u8 *buf, const size_t begin,
}
static really_inline
-char castleRevScanVerm(const struct Castle *c, const u8 *buf,
- const size_t begin, const size_t end, size_t *loc) {
- const u8 *ptr = rvermicelliExec(c->u.verm.c, 0, buf + begin, buf + end);
- if (ptr == buf + begin - 1) {
- DEBUG_PRINTF("no escape found\n");
- return 0;
- }
-
- assert(loc);
- assert(ptr >= buf && ptr < buf + end);
- *loc = (size_t)(ptr - buf);
- DEBUG_PRINTF("escape found at offset %zu\n", *loc);
- return 1;
-}
-
-static really_inline
-char castleRevScanNVerm(const struct Castle *c, const u8 *buf,
- const size_t begin, const size_t end, size_t *loc) {
- const u8 *ptr = rnvermicelliExec(c->u.verm.c, 0, buf + begin, buf + end);
- if (ptr == buf + begin - 1) {
- DEBUG_PRINTF("no escape found\n");
- return 0;
- }
-
- assert(loc);
- assert(ptr >= buf && ptr < buf + end);
- *loc = (size_t)(ptr - buf);
- DEBUG_PRINTF("escape found at offset %zu\n", *loc);
- return 1;
-}
-
-static really_inline
-char castleRevScanShufti(const struct Castle *c, const u8 *buf,
- const size_t begin, const size_t end, size_t *loc) {
- const m128 mask_lo = c->u.shuf.mask_lo;
- const m128 mask_hi = c->u.shuf.mask_hi;
- const u8 *ptr = rshuftiExec(mask_lo, mask_hi, buf + begin, buf + end);
- if (ptr == buf + begin - 1) {
- DEBUG_PRINTF("no escape found\n");
- return 0;
- }
-
- assert(loc);
- assert(ptr >= buf && ptr < buf + end);
- *loc = (size_t)(ptr - buf);
- DEBUG_PRINTF("escape found at offset %zu\n", *loc);
- return 1;
-}
-
-static really_inline
-char castleRevScanTruffle(const struct Castle *c, const u8 *buf,
- const size_t begin, const size_t end, size_t *loc) {
- const u8 *ptr = rtruffleExec(c->u.truffle.mask1, c->u.truffle.mask2,
- buf + begin, buf + end);
- if (ptr == buf + begin - 1) {
- DEBUG_PRINTF("no escape found\n");
- return 0;
- }
-
- assert(loc);
- assert(ptr >= buf && ptr < buf + end);
- *loc = (size_t)(ptr - buf);
- DEBUG_PRINTF("escape found at offset %zu\n", *loc);
- return 1;
-}
-
-static really_inline
-char castleRevScan(const struct Castle *c, const u8 *buf, const size_t begin,
- const size_t end, size_t *loc) {
- assert(begin <= end);
- DEBUG_PRINTF("scanning backwards over (%zu,%zu]\n", begin, end);
- if (begin == end) {
- return 0;
- }
-
- switch (c->type) {
- case CASTLE_DOT:
- // Nothing can stop a dot scan!
- return 0;
- case CASTLE_VERM:
- return castleRevScanVerm(c, buf, begin, end, loc);
- case CASTLE_NVERM:
- return castleRevScanNVerm(c, buf, begin, end, loc);
- case CASTLE_SHUFTI:
- return castleRevScanShufti(c, buf, begin, end, loc);
- case CASTLE_TRUFFLE:
- return castleRevScanTruffle(c, buf, begin, end, loc);
- default:
- DEBUG_PRINTF("unknown scan type!\n");
- assert(0);
- return 0;
- }
-}
-
-static really_inline
-void castleHandleEvent(const struct Castle *c, struct mq *q, const u64a sp,
- char stale_checked) {
+char castleRevScanVerm(const struct Castle *c, const u8 *buf,
+ const size_t begin, const size_t end, size_t *loc) {
+ const u8 *ptr = rvermicelliExec(c->u.verm.c, 0, buf + begin, buf + end);
+ if (ptr == buf + begin - 1) {
+ DEBUG_PRINTF("no escape found\n");
+ return 0;
+ }
+
+ assert(loc);
+ assert(ptr >= buf && ptr < buf + end);
+ *loc = (size_t)(ptr - buf);
+ DEBUG_PRINTF("escape found at offset %zu\n", *loc);
+ return 1;
+}
+
+static really_inline
+char castleRevScanNVerm(const struct Castle *c, const u8 *buf,
+ const size_t begin, const size_t end, size_t *loc) {
+ const u8 *ptr = rnvermicelliExec(c->u.verm.c, 0, buf + begin, buf + end);
+ if (ptr == buf + begin - 1) {
+ DEBUG_PRINTF("no escape found\n");
+ return 0;
+ }
+
+ assert(loc);
+ assert(ptr >= buf && ptr < buf + end);
+ *loc = (size_t)(ptr - buf);
+ DEBUG_PRINTF("escape found at offset %zu\n", *loc);
+ return 1;
+}
+
+static really_inline
+char castleRevScanShufti(const struct Castle *c, const u8 *buf,
+ const size_t begin, const size_t end, size_t *loc) {
+ const m128 mask_lo = c->u.shuf.mask_lo;
+ const m128 mask_hi = c->u.shuf.mask_hi;
+ const u8 *ptr = rshuftiExec(mask_lo, mask_hi, buf + begin, buf + end);
+ if (ptr == buf + begin - 1) {
+ DEBUG_PRINTF("no escape found\n");
+ return 0;
+ }
+
+ assert(loc);
+ assert(ptr >= buf && ptr < buf + end);
+ *loc = (size_t)(ptr - buf);
+ DEBUG_PRINTF("escape found at offset %zu\n", *loc);
+ return 1;
+}
+
+static really_inline
+char castleRevScanTruffle(const struct Castle *c, const u8 *buf,
+ const size_t begin, const size_t end, size_t *loc) {
+ const u8 *ptr = rtruffleExec(c->u.truffle.mask1, c->u.truffle.mask2,
+ buf + begin, buf + end);
+ if (ptr == buf + begin - 1) {
+ DEBUG_PRINTF("no escape found\n");
+ return 0;
+ }
+
+ assert(loc);
+ assert(ptr >= buf && ptr < buf + end);
+ *loc = (size_t)(ptr - buf);
+ DEBUG_PRINTF("escape found at offset %zu\n", *loc);
+ return 1;
+}
+
+static really_inline
+char castleRevScan(const struct Castle *c, const u8 *buf, const size_t begin,
+ const size_t end, size_t *loc) {
+ assert(begin <= end);
+ DEBUG_PRINTF("scanning backwards over (%zu,%zu]\n", begin, end);
+ if (begin == end) {
+ return 0;
+ }
+
+ switch (c->type) {
+ case CASTLE_DOT:
+ // Nothing can stop a dot scan!
+ return 0;
+ case CASTLE_VERM:
+ return castleRevScanVerm(c, buf, begin, end, loc);
+ case CASTLE_NVERM:
+ return castleRevScanNVerm(c, buf, begin, end, loc);
+ case CASTLE_SHUFTI:
+ return castleRevScanShufti(c, buf, begin, end, loc);
+ case CASTLE_TRUFFLE:
+ return castleRevScanTruffle(c, buf, begin, end, loc);
+ default:
+ DEBUG_PRINTF("unknown scan type!\n");
+ assert(0);
+ return 0;
+ }
+}
+
+static really_inline
+void castleHandleEvent(const struct Castle *c, struct mq *q, const u64a sp,
+ char stale_checked) {
const u32 event = q->items[q->cur].type;
switch (event) {
case MQE_TOP:
@@ -726,29 +726,29 @@ void castleHandleEvent(const struct Castle *c, struct mq *q, const u64a sp,
assert(event < MQE_INVALID);
u32 top = event - MQE_TOP_FIRST;
DEBUG_PRINTF("top %u at offset %llu\n", top, sp);
- castleProcessTop(c, top, sp, q->state, q->streamState, stale_checked);
+ castleProcessTop(c, top, sp, q->state, q->streamState, stale_checked);
break;
}
}
static really_inline
-void clear_repeats(const struct Castle *c, const struct mq *q, u8 *active) {
- DEBUG_PRINTF("clearing active repeats due to escape\n");
- if (c->exclusive) {
- u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
- mmbit_clear(groups, c->numGroups);
- }
-
- if (c->exclusive != PURE_EXCLUSIVE) {
- mmbit_clear(active, c->numRepeats);
- }
-}
-
-static really_inline
-char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
- enum MatchMode mode) {
+void clear_repeats(const struct Castle *c, const struct mq *q, u8 *active) {
+ DEBUG_PRINTF("clearing active repeats due to escape\n");
+ if (c->exclusive) {
+ u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
+ mmbit_clear(groups, c->numGroups);
+ }
+
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ mmbit_clear(active, c->numRepeats);
+ }
+}
+
+static really_inline
+char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
+ enum MatchMode mode) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("state=%p, streamState=%p\n", q->state, q->streamState);
@@ -766,7 +766,7 @@ char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
return 1;
}
- u8 *active = (u8 *)q->streamState + c->activeOffset;// active multibit
+ u8 *active = (u8 *)q->streamState + c->activeOffset;// active multibit
assert(q->cur + 1 < q->end); // require at least two items
assert(q_cur_type(q) == MQE_START);
@@ -780,8 +780,8 @@ char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
char found = 0;
if (c->exclusive) {
- u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
- found = mmbit_any(groups, c->numGroups);
+ u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
+ found = mmbit_any(groups, c->numGroups);
}
if (!found && !mmbit_any(active, c->numRepeats)) {
@@ -828,7 +828,7 @@ char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
}
if (escape_found) {
- clear_repeats(c, q, active);
+ clear_repeats(c, q, active);
}
}
@@ -842,63 +842,63 @@ char nfaExecCastle_Q_i(const struct NFA *n, struct mq *q, s64a end,
}
sp = q_cur_offset(q);
- castleHandleEvent(c, q, sp, 1);
+ castleHandleEvent(c, q, sp, 1);
q->cur++;
}
if (c->exclusive) {
- u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
- if (mmbit_any_precise(groups, c->numGroups)) {
- return 1;
+ u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
+ if (mmbit_any_precise(groups, c->numGroups)) {
+ return 1;
}
}
return mmbit_any_precise(active, c->numRepeats);
}
-char nfaExecCastle_Q(const struct NFA *n, struct mq *q, s64a end) {
+char nfaExecCastle_Q(const struct NFA *n, struct mq *q, s64a end) {
DEBUG_PRINTF("entry\n");
- return nfaExecCastle_Q_i(n, q, end, CALLBACK_OUTPUT);
+ return nfaExecCastle_Q_i(n, q, end, CALLBACK_OUTPUT);
}
-char nfaExecCastle_Q2(const struct NFA *n, struct mq *q, s64a end) {
+char nfaExecCastle_Q2(const struct NFA *n, struct mq *q, s64a end) {
DEBUG_PRINTF("entry\n");
- return nfaExecCastle_Q_i(n, q, end, STOP_AT_MATCH);
+ return nfaExecCastle_Q_i(n, q, end, STOP_AT_MATCH);
}
-static
-s64a castleLastKillLoc(const struct Castle *c, struct mq *q) {
- assert(q_cur_type(q) == MQE_START);
- assert(q_last_type(q) == MQE_END);
- s64a sp = q_cur_loc(q);
- s64a ep = q_last_loc(q);
+static
+s64a castleLastKillLoc(const struct Castle *c, struct mq *q) {
+ assert(q_cur_type(q) == MQE_START);
+ assert(q_last_type(q) == MQE_END);
+ s64a sp = q_cur_loc(q);
+ s64a ep = q_last_loc(q);
+
+ DEBUG_PRINTF("finding final squash in (%lld, %lld]\n", sp, ep);
- DEBUG_PRINTF("finding final squash in (%lld, %lld]\n", sp, ep);
+ size_t loc;
- size_t loc;
-
- if (ep > 0) {
- if (castleRevScan(c, q->buffer, sp > 0 ? sp : 0, ep, &loc)) {
- return (s64a)loc;
+ if (ep > 0) {
+ if (castleRevScan(c, q->buffer, sp > 0 ? sp : 0, ep, &loc)) {
+ return (s64a)loc;
}
- ep = 0;
- }
-
- if (sp < 0) {
- s64a hlen = q->hlength;
-
- if (castleRevScan(c, q->history, sp + hlen, ep + hlen, &loc)) {
- return (s64a)loc - hlen;
+ ep = 0;
+ }
+
+ if (sp < 0) {
+ s64a hlen = q->hlength;
+
+ if (castleRevScan(c, q->history, sp + hlen, ep + hlen, &loc)) {
+ return (s64a)loc - hlen;
}
- ep = 0;
+ ep = 0;
}
-
- return sp - 1; /* the repeats are never killed */
+
+ return sp - 1; /* the repeats are never killed */
}
-char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report) {
+char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry\n");
if (q->cur == q->end) {
@@ -909,42 +909,42 @@ char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report) {
assert(q_cur_type(q) == MQE_START);
const struct Castle *c = getImplNfa(n);
- u8 *active = (u8 *)q->streamState + c->activeOffset;
-
- u64a end_offset = q_last_loc(q) + q->offset;
- s64a last_kill_loc = castleLastKillLoc(c, q);
- DEBUG_PRINTF("all repeats killed at %lld (exec range %lld, %lld)\n",
- last_kill_loc, q_cur_loc(q), q_last_loc(q));
- assert(last_kill_loc < q_last_loc(q));
-
- if (last_kill_loc != q_cur_loc(q) - 1) {
- clear_repeats(c, q, active);
- }
-
- q->cur++; /* skip start event */
-
- /* skip events prior to the repeats being squashed */
- while (q_cur_loc(q) <= last_kill_loc) {
- DEBUG_PRINTF("skipping moot event at %lld\n", q_cur_loc(q));
- q->cur++;
- assert(q->cur < q->end);
- }
-
- while (q->cur < q->end) {
- DEBUG_PRINTF("q item type=%d offset=%llu\n", q_cur_type(q),
- q_cur_offset(q));
- u64a sp = q_cur_offset(q);
- castleHandleEvent(c, q, sp, 0);
+ u8 *active = (u8 *)q->streamState + c->activeOffset;
+
+ u64a end_offset = q_last_loc(q) + q->offset;
+ s64a last_kill_loc = castleLastKillLoc(c, q);
+ DEBUG_PRINTF("all repeats killed at %lld (exec range %lld, %lld)\n",
+ last_kill_loc, q_cur_loc(q), q_last_loc(q));
+ assert(last_kill_loc < q_last_loc(q));
+
+ if (last_kill_loc != q_cur_loc(q) - 1) {
+ clear_repeats(c, q, active);
+ }
+
+ q->cur++; /* skip start event */
+
+ /* skip events prior to the repeats being squashed */
+ while (q_cur_loc(q) <= last_kill_loc) {
+ DEBUG_PRINTF("skipping moot event at %lld\n", q_cur_loc(q));
+ q->cur++;
+ assert(q->cur < q->end);
+ }
+
+ while (q->cur < q->end) {
+ DEBUG_PRINTF("q item type=%d offset=%llu\n", q_cur_type(q),
+ q_cur_offset(q));
+ u64a sp = q_cur_offset(q);
+ castleHandleEvent(c, q, sp, 0);
q->cur++;
}
- castleDeactivateStaleSubs(c, end_offset, q->state, q->streamState);
-
- char found = 0;
+ castleDeactivateStaleSubs(c, end_offset, q->state, q->streamState);
+
+ char found = 0;
if (c->exclusive) {
- u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
- found = mmbit_any_precise(groups, c->numGroups);
-
+ u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
+ found = mmbit_any_precise(groups, c->numGroups);
+
}
if (!found && !mmbit_any_precise(active, c->numRepeats)) {
@@ -952,16 +952,16 @@ char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report) {
return 0;
}
- if (castleInAccept(c, q, report, end_offset)) {
+ if (castleInAccept(c, q, report, end_offset)) {
return MO_MATCHES_PENDING;
}
return 1;
}
-char nfaExecCastle_reportCurrent(const struct NFA *n, struct mq *q) {
+char nfaExecCastle_reportCurrent(const struct NFA *n, struct mq *q) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry\n");
const struct Castle *c = getImplNfa(n);
@@ -969,89 +969,89 @@ char nfaExecCastle_reportCurrent(const struct NFA *n, struct mq *q) {
return 0;
}
-char nfaExecCastle_inAccept(const struct NFA *n, ReportID report,
- struct mq *q) {
+char nfaExecCastle_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry\n");
const struct Castle *c = getImplNfa(n);
return castleInAccept(c, q, report, q_cur_offset(q));
}
-char nfaExecCastle_inAnyAccept(const struct NFA *n, struct mq *q) {
+char nfaExecCastle_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+ assert(n->type == CASTLE_NFA);
+ DEBUG_PRINTF("entry\n");
+
+ const struct Castle *c = getImplNfa(n);
+ const u64a offset = q_cur_offset(q);
+ DEBUG_PRINTF("offset=%llu\n", offset);
+
+ if (c->exclusive) {
+ u8 *active = (u8 *)q->streamState;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ DEBUG_PRINTF("subcastle %u\n", activeIdx);
+ const struct SubCastle *sub = getSubCastle(c, activeIdx);
+ if (subCastleInAccept(c, q, sub->report, offset, activeIdx)) {
+ return 1;
+ }
+ }
+ }
+
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ const u8 *active = (const u8 *)q->streamState + c->activeOffset;
+ for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
+ DEBUG_PRINTF("subcastle %u\n", i);
+ const struct SubCastle *sub = getSubCastle(c, i);
+ if (subCastleInAccept(c, q, sub->report, offset, i)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+char nfaExecCastle_queueInitState(UNUSED const struct NFA *n, struct mq *q) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry\n");
const struct Castle *c = getImplNfa(n);
- const u64a offset = q_cur_offset(q);
- DEBUG_PRINTF("offset=%llu\n", offset);
-
- if (c->exclusive) {
- u8 *active = (u8 *)q->streamState;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
- DEBUG_PRINTF("subcastle %u\n", activeIdx);
- const struct SubCastle *sub = getSubCastle(c, activeIdx);
- if (subCastleInAccept(c, q, sub->report, offset, activeIdx)) {
- return 1;
- }
- }
- }
-
- if (c->exclusive != PURE_EXCLUSIVE) {
- const u8 *active = (const u8 *)q->streamState + c->activeOffset;
- for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
- DEBUG_PRINTF("subcastle %u\n", i);
- const struct SubCastle *sub = getSubCastle(c, i);
- if (subCastleInAccept(c, q, sub->report, offset, i)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-
-char nfaExecCastle_queueInitState(UNUSED const struct NFA *n, struct mq *q) {
- assert(n && q);
- assert(n->type == CASTLE_NFA);
- DEBUG_PRINTF("entry\n");
-
- const struct Castle *c = getImplNfa(n);
assert(q->streamState);
if (c->exclusive) {
- u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
- mmbit_clear(groups, c->numGroups);
+ u8 *groups = (u8 *)q->streamState + c->groupIterOffset;
+ mmbit_clear(groups, c->numGroups);
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- u8 *active = (u8 *)q->streamState + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ u8 *active = (u8 *)q->streamState + c->activeOffset;
mmbit_clear(active, c->numRepeats);
}
return 0;
}
-char nfaExecCastle_initCompressedState(const struct NFA *n, UNUSED u64a offset,
- void *state, UNUSED u8 key) {
+char nfaExecCastle_initCompressedState(const struct NFA *n, UNUSED u64a offset,
+ void *state, UNUSED u8 key) {
assert(n && state);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry\n");
const struct Castle *c = getImplNfa(n);
if (c->exclusive) {
- u8 *groups = (u8 *)state + c->groupIterOffset;
- mmbit_clear(groups, c->numGroups);
+ u8 *groups = (u8 *)state + c->groupIterOffset;
+ mmbit_clear(groups, c->numGroups);
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- u8 *active = (u8 *)state + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ u8 *active = (u8 *)state + c->activeOffset;
mmbit_clear(active, c->numRepeats);
}
return 0;
@@ -1070,10 +1070,10 @@ void subCastleQueueCompressState(const struct Castle *c, const u32 subIdx,
repeatPack(packed, info, rctrl, offset);
}
-char nfaExecCastle_queueCompressState(const struct NFA *n, const struct mq *q,
- s64a loc) {
+char nfaExecCastle_queueCompressState(const struct NFA *n, const struct mq *q,
+ s64a loc) {
assert(n && q);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry, loc=%lld\n", loc);
const struct Castle *c = getImplNfa(n);
@@ -1082,19 +1082,19 @@ char nfaExecCastle_queueCompressState(const struct NFA *n, const struct mq *q,
const u64a offset = q->offset + loc;
DEBUG_PRINTF("offset=%llu\n", offset);
if (c->exclusive) {
- u8 *active = (u8 *)q->streamState;
- u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ u8 *active = (u8 *)q->streamState;
+ u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
DEBUG_PRINTF("packing state for sub %u\n", activeIdx);
subCastleQueueCompressState(c, activeIdx, q, offset);
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
- const u8 *active = (const u8 *)q->streamState + c->activeOffset;
+ if (c->exclusive != PURE_EXCLUSIVE) {
+ const u8 *active = (const u8 *)q->streamState + c->activeOffset;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
DEBUG_PRINTF("packing state for sub %u\n", i);
@@ -1118,28 +1118,28 @@ void subCastleExpandState(const struct Castle *c, const u32 subIdx,
packed + info->packedCtrlSize, offset));
}
-char nfaExecCastle_expandState(const struct NFA *n, void *dest, const void *src,
- u64a offset, UNUSED u8 key) {
+char nfaExecCastle_expandState(const struct NFA *n, void *dest, const void *src,
+ u64a offset, UNUSED u8 key) {
assert(n && dest && src);
- assert(n->type == CASTLE_NFA);
+ assert(n->type == CASTLE_NFA);
DEBUG_PRINTF("entry, src=%p, dest=%p, offset=%llu\n", src, dest, offset);
const struct Castle *c = getImplNfa(n);
if (c->exclusive) {
- const u8 *active = (const u8 *)src;
- const u8 *groups = active + c->groupIterOffset;
- for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
- i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
- const u8 *cur = active + i * c->activeIdxSize;
- const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
+ const u8 *active = (const u8 *)src;
+ const u8 *groups = active + c->groupIterOffset;
+ for (u32 i = mmbit_iterate(groups, c->numGroups, MMB_INVALID);
+ i != MMB_INVALID; i = mmbit_iterate(groups, c->numGroups, i)) {
+ const u8 *cur = active + i * c->activeIdxSize;
+ const u32 activeIdx = partial_load_u32(cur, c->activeIdxSize);
subCastleExpandState(c, activeIdx, dest, src, offset);
}
}
- if (c->exclusive != PURE_EXCLUSIVE) {
+ if (c->exclusive != PURE_EXCLUSIVE) {
// Unpack state for all active repeats.
- const u8 *active = (const u8 *)src + c->activeOffset;
+ const u8 *active = (const u8 *)src + c->activeOffset;
for (u32 i = mmbit_iterate(active, c->numRepeats, MMB_INVALID);
i != MMB_INVALID; i = mmbit_iterate(active, c->numRepeats, i)) {
subCastleExpandState(c, i, dest, src, offset);
diff --git a/contrib/libs/hyperscan/src/nfa/castle.h b/contrib/libs/hyperscan/src/nfa/castle.h
index 83f0b6fb79f..cc7496ca712 100644
--- a/contrib/libs/hyperscan/src/nfa/castle.h
+++ b/contrib/libs/hyperscan/src/nfa/castle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,24 +38,24 @@ extern "C" {
struct mq;
struct NFA;
-char nfaExecCastle_Q(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecCastle_Q2(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report);
-char nfaExecCastle_reportCurrent(const struct NFA *n, struct mq *q);
-char nfaExecCastle_inAccept(const struct NFA *n, ReportID report,
- struct mq *q);
-char nfaExecCastle_inAnyAccept(const struct NFA *n, struct mq *q);
-char nfaExecCastle_queueInitState(const struct NFA *n, struct mq *q);
-char nfaExecCastle_initCompressedState(const struct NFA *n, u64a offset,
- void *state, u8 key);
-char nfaExecCastle_queueCompressState(const struct NFA *nfa, const struct mq *q,
- s64a loc);
-char nfaExecCastle_expandState(const struct NFA *nfa, void *dest,
- const void *src, u64a offset, u8 key);
+char nfaExecCastle_Q(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecCastle_Q2(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecCastle_QR(const struct NFA *n, struct mq *q, ReportID report);
+char nfaExecCastle_reportCurrent(const struct NFA *n, struct mq *q);
+char nfaExecCastle_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q);
+char nfaExecCastle_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecCastle_queueInitState(const struct NFA *n, struct mq *q);
+char nfaExecCastle_initCompressedState(const struct NFA *n, u64a offset,
+ void *state, u8 key);
+char nfaExecCastle_queueCompressState(const struct NFA *nfa, const struct mq *q,
+ s64a loc);
+char nfaExecCastle_expandState(const struct NFA *nfa, void *dest,
+ const void *src, u64a offset, u8 key);
-#define nfaExecCastle_testEOD NFA_API_NO_IMPL
-#define nfaExecCastle_B_Reverse NFA_API_NO_IMPL
-#define nfaExecCastle_zombie_status NFA_API_ZOMBIE_NO_IMPL
+#define nfaExecCastle_testEOD NFA_API_NO_IMPL
+#define nfaExecCastle_B_Reverse NFA_API_NO_IMPL
+#define nfaExecCastle_zombie_status NFA_API_ZOMBIE_NO_IMPL
#ifdef __cplusplus
}
diff --git a/contrib/libs/hyperscan/src/nfa/castle_internal.h b/contrib/libs/hyperscan/src/nfa/castle_internal.h
index 19c353b4ddc..429c232ff8b 100644
--- a/contrib/libs/hyperscan/src/nfa/castle_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/castle_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,9 +42,9 @@ struct SubCastle {
u32 streamStateOffset; //!< offset within stream state
u32 repeatInfoOffset; //!< offset of RepeatInfo structure
// relative to the start of SubCastle
- u32 exclusiveId; //!< exclusive group id of this SubCastle,
- // set to the number of SubCastles in Castle
- // if it is not exclusive
+ u32 exclusiveId; //!< exclusive group id of this SubCastle,
+ // set to the number of SubCastles in Castle
+ // if it is not exclusive
};
#define CASTLE_DOT 0
@@ -53,12 +53,12 @@ struct SubCastle {
#define CASTLE_SHUFTI 3
#define CASTLE_TRUFFLE 4
-enum ExclusiveType {
- NOT_EXCLUSIVE, //!< no subcastles are exclusive
- EXCLUSIVE, //!< a subset of subcastles are exclusive
- PURE_EXCLUSIVE //!< all subcastles are exclusive
-};
-
+enum ExclusiveType {
+ NOT_EXCLUSIVE, //!< no subcastles are exclusive
+ EXCLUSIVE, //!< a subset of subcastles are exclusive
+ PURE_EXCLUSIVE //!< all subcastles are exclusive
+};
+
/**
* \brief Castle engine structure.
*
@@ -71,60 +71,60 @@ enum ExclusiveType {
* - struct Castle
* - struct SubCastle[numRepeats]
* - tables for sparse model repeats
- * - sparse iterator for subcastles that may be stale
+ * - sparse iterator for subcastles that may be stale
*
* Castle stores an "active repeats" multibit in stream state, followed by the
- * packed repeat state for each SubCastle. If there are both exclusive and
- * non-exclusive SubCastle groups, we use an active id for each exclusive group
- * and a multibit for the non-exclusive group. We also store an "active
- * exclusive groups" multibit for exclusive groups. If all SubCastles are mutual
- * exclusive, we remove "active repeats" multibit from stream state.
- * * Castle stream state:
- * *
- * * |---|
- * * | | active subengine id for exclusive group 1
- * * |---|
- * * | | active subengine id for exclusive group 2(if necessary)
- * * |---|
- * * ...
- * * |---|
- * * | | "active repeats" multibit for non-exclusive subcastles
- * * | | (if not all subcastles are exclusive)
- * * |---|
- * * | | active multibit for exclusive groups
- * * | |
- * * |---|
- * * ||-|| common pool of stream state for exclusive group 1
- * * ||-||
- * * |---|
- * * ||-|| common pool of stream state for exclusive group 2(if necessary)
- * * ||-||
- * * |---|
- * * ...
- * * |---|
- * * | | stream state for each non-exclusive subcastles
- * * ...
- * * | |
- * * |---|
+ * packed repeat state for each SubCastle. If there are both exclusive and
+ * non-exclusive SubCastle groups, we use an active id for each exclusive group
+ * and a multibit for the non-exclusive group. We also store an "active
+ * exclusive groups" multibit for exclusive groups. If all SubCastles are mutual
+ * exclusive, we remove "active repeats" multibit from stream state.
+ * * Castle stream state:
+ * *
+ * * |---|
+ * * | | active subengine id for exclusive group 1
+ * * |---|
+ * * | | active subengine id for exclusive group 2(if necessary)
+ * * |---|
+ * * ...
+ * * |---|
+ * * | | "active repeats" multibit for non-exclusive subcastles
+ * * | | (if not all subcastles are exclusive)
+ * * |---|
+ * * | | active multibit for exclusive groups
+ * * | |
+ * * |---|
+ * * ||-|| common pool of stream state for exclusive group 1
+ * * ||-||
+ * * |---|
+ * * ||-|| common pool of stream state for exclusive group 2(if necessary)
+ * * ||-||
+ * * |---|
+ * * ...
+ * * |---|
+ * * | | stream state for each non-exclusive subcastles
+ * * ...
+ * * | |
+ * * |---|
*
* In full state (stored in scratch space) it stores a temporary multibit over
* the repeats (used by \ref castleMatchLoop), followed by the repeat control
- * blocks for each SubCastle.
+ * blocks for each SubCastle.
*/
struct ALIGN_AVX_DIRECTIVE Castle {
- u32 numRepeats; //!< number of repeats in Castle
- u32 numGroups; //!< number of exclusive groups
- u8 type; //!< tells us which scanning mechanism (below) to use
- u8 exclusive; //!< tells us if there are mutual exclusive SubCastles
- u8 activeIdxSize; //!< number of bytes in stream state to store
- // active SubCastle id for exclusive mode
- u32 activeOffset; //!< offset to active multibit for non-exclusive
- // SubCastles
- u32 staleIterOffset; //!< offset to a sparse iterator to check for stale
- // sub castles
- u32 groupIterOffset; //!< offset to a iterator to check the aliveness of
- // exclusive groups
-
+ u32 numRepeats; //!< number of repeats in Castle
+ u32 numGroups; //!< number of exclusive groups
+ u8 type; //!< tells us which scanning mechanism (below) to use
+ u8 exclusive; //!< tells us if there are mutual exclusive SubCastles
+ u8 activeIdxSize; //!< number of bytes in stream state to store
+ // active SubCastle id for exclusive mode
+ u32 activeOffset; //!< offset to active multibit for non-exclusive
+ // SubCastles
+ u32 staleIterOffset; //!< offset to a sparse iterator to check for stale
+ // sub castles
+ u32 groupIterOffset; //!< offset to a iterator to check the aliveness of
+ // exclusive groups
+
union {
struct {
char c;
diff --git a/contrib/libs/hyperscan/src/nfa/castlecompile.cpp b/contrib/libs/hyperscan/src/nfa/castlecompile.cpp
index ac3d514a77f..d4c361337af 100644
--- a/contrib/libs/hyperscan/src/nfa/castlecompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/castlecompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,15 +26,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Castle: multi-tenant repeat engine, compiler code.
*/
-
+
#include "castlecompile.h"
#include "castle_internal.h"
-#include "limex_limits.h"
+#include "limex_limits.h"
#include "nfa_internal.h"
#include "repeatcompile.h"
#include "shufticompile.h"
@@ -48,18 +48,18 @@
#include "util/compile_context.h"
#include "util/container.h"
#include "util/dump_charclass.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/make_unique.h"
-#include "util/multibit_build.h"
-#include "util/report_manager.h"
+#include "util/multibit_build.h"
+#include "util/report_manager.h"
#include "util/verify_types.h"
#include "grey.h"
#include <stack>
#include <cassert>
-#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptor/map.hpp>
using namespace std;
@@ -102,15 +102,15 @@ void writeCastleScanEngine(const CharReach &cr, Castle *c) {
return;
}
- if (shuftiBuildMasks(negated, (u8 *)&c->u.shuf.mask_lo,
- (u8 *)&c->u.shuf.mask_hi) != -1) {
+ if (shuftiBuildMasks(negated, (u8 *)&c->u.shuf.mask_lo,
+ (u8 *)&c->u.shuf.mask_hi) != -1) {
c->type = CASTLE_SHUFTI;
return;
}
c->type = CASTLE_TRUFFLE;
- truffleBuildMasks(negated, (u8 *)(u8 *)&c->u.truffle.mask1,
- (u8 *)&c->u.truffle.mask2);
+ truffleBuildMasks(negated, (u8 *)(u8 *)&c->u.truffle.mask1,
+ (u8 *)&c->u.truffle.mask2);
}
static
@@ -156,7 +156,7 @@ void getNeighborInfo(const CliqueGraph &g, vector<u32> &neighbor,
// find neighbors for cv
for (const auto &v : adjacent_vertices_range(cv, g)) {
- if (g[v].stateId != id && contains(group, g[v].stateId)) {
+ if (g[v].stateId != id && contains(group, g[v].stateId)) {
neighbor.push_back(g[v].stateId);
DEBUG_PRINTF("Neighbor:%u\n", g[v].stateId);
}
@@ -208,7 +208,7 @@ bool graph_empty(const Graph &g) {
static
vector<u32> removeClique(CliqueGraph &cg) {
vector<vector<u32>> cliquesVec(1);
- DEBUG_PRINTF("graph size:%zu\n", num_vertices(cg));
+ DEBUG_PRINTF("graph size:%zu\n", num_vertices(cg));
findCliqueGroup(cg, cliquesVec[0]);
while (!graph_empty(cg)) {
const vector<u32> &c = cliquesVec.back();
@@ -240,7 +240,7 @@ vector<u32> removeClique(CliqueGraph &cg) {
}
}
- DEBUG_PRINTF("clique size:%zu\n", cliquesVec[id].size());
+ DEBUG_PRINTF("clique size:%zu\n", cliquesVec[id].size());
return cliquesVec[id];
}
@@ -248,18 +248,18 @@ vector<u32> removeClique(CliqueGraph &cg) {
// the end locations where it overlaps with other literals,
// then the literals are mutual exclusive
static
-bool findExclusivePair(const size_t id1, const size_t id2,
- const size_t lower,
+bool findExclusivePair(const size_t id1, const size_t id2,
+ const size_t lower,
const vector<vector<size_t>> &min_reset_dist,
const vector<vector<vector<CharReach>>> &triggers) {
const auto &triggers1 = triggers[id1];
const auto &triggers2 = triggers[id2];
- for (size_t i = 0; i < triggers1.size(); ++i) {
- for (size_t j = 0; j < triggers2.size(); ++j) {
+ for (size_t i = 0; i < triggers1.size(); ++i) {
+ for (size_t j = 0; j < triggers2.size(); ++j) {
if (!literalOverlap(triggers1[i], triggers2[j],
- min_reset_dist[id2 - lower][j]) ||
+ min_reset_dist[id2 - lower][j]) ||
!literalOverlap(triggers2[j], triggers1[i],
- min_reset_dist[id1 - lower][i])) {
+ min_reset_dist[id1 - lower][i])) {
return false;
}
}
@@ -268,92 +268,92 @@ bool findExclusivePair(const size_t id1, const size_t id2,
}
static
-vector<vector<u32>> checkExclusion(u32 &streamStateSize,
- const CharReach &cr,
- const vector<vector<vector<CharReach>>> &triggers,
- enum ExclusiveType &exclusive,
- const size_t numRepeats) {
- vector<vector<u32>> groups;
- size_t trigSize = triggers.size();
- DEBUG_PRINTF("trigSize %zu\n", trigSize);
-
- size_t lower = 0;
- size_t total = 0;
- while (lower < trigSize) {
- vector<CliqueVertex> vertices;
- unique_ptr<CliqueGraph> cg = std::make_unique<CliqueGraph>();
-
- vector<vector<size_t>> min_reset_dist;
- size_t upper = min(lower + CLIQUE_GRAPH_MAX_SIZE, trigSize);
- // get min reset distance for each repeat
- for (size_t i = lower; i < upper; i++) {
- CliqueVertex v = add_vertex(CliqueVertexProps(i), *cg);
- vertices.push_back(v);
-
- const vector<size_t> &tmp_dist =
- minResetDistToEnd(triggers[i], cr);
- min_reset_dist.push_back(tmp_dist);
- }
-
- // find exclusive pair for each repeat
- for (size_t i = lower; i < upper; i++) {
- CliqueVertex s = vertices[i - lower];
- for (size_t j = i + 1; j < upper; j++) {
- if (findExclusivePair(i, j, lower, min_reset_dist,
- triggers)) {
- CliqueVertex d = vertices[j - lower];
- add_edge(s, d, *cg);
- }
+vector<vector<u32>> checkExclusion(u32 &streamStateSize,
+ const CharReach &cr,
+ const vector<vector<vector<CharReach>>> &triggers,
+ enum ExclusiveType &exclusive,
+ const size_t numRepeats) {
+ vector<vector<u32>> groups;
+ size_t trigSize = triggers.size();
+ DEBUG_PRINTF("trigSize %zu\n", trigSize);
+
+ size_t lower = 0;
+ size_t total = 0;
+ while (lower < trigSize) {
+ vector<CliqueVertex> vertices;
+ unique_ptr<CliqueGraph> cg = std::make_unique<CliqueGraph>();
+
+ vector<vector<size_t>> min_reset_dist;
+ size_t upper = min(lower + CLIQUE_GRAPH_MAX_SIZE, trigSize);
+ // get min reset distance for each repeat
+ for (size_t i = lower; i < upper; i++) {
+ CliqueVertex v = add_vertex(CliqueVertexProps(i), *cg);
+ vertices.push_back(v);
+
+ const vector<size_t> &tmp_dist =
+ minResetDistToEnd(triggers[i], cr);
+ min_reset_dist.push_back(tmp_dist);
+ }
+
+ // find exclusive pair for each repeat
+ for (size_t i = lower; i < upper; i++) {
+ CliqueVertex s = vertices[i - lower];
+ for (size_t j = i + 1; j < upper; j++) {
+ if (findExclusivePair(i, j, lower, min_reset_dist,
+ triggers)) {
+ CliqueVertex d = vertices[j - lower];
+ add_edge(s, d, *cg);
+ }
}
}
-
- // find the largest exclusive group
- auto clique = removeClique(*cg);
- size_t cliqueSize = clique.size();
- if (cliqueSize > 1) {
- groups.push_back(clique);
- exclusive = EXCLUSIVE;
- total += cliqueSize;
- }
-
- lower += CLIQUE_GRAPH_MAX_SIZE;
- }
- DEBUG_PRINTF("clique size %zu, num of repeats %zu\n",
- total, numRepeats);
- if (total == numRepeats) {
- exclusive = PURE_EXCLUSIVE;
- streamStateSize = 0;
- };
-
- return groups;
+
+ // find the largest exclusive group
+ auto clique = removeClique(*cg);
+ size_t cliqueSize = clique.size();
+ if (cliqueSize > 1) {
+ groups.push_back(clique);
+ exclusive = EXCLUSIVE;
+ total += cliqueSize;
+ }
+
+ lower += CLIQUE_GRAPH_MAX_SIZE;
+ }
+ DEBUG_PRINTF("clique size %zu, num of repeats %zu\n",
+ total, numRepeats);
+ if (total == numRepeats) {
+ exclusive = PURE_EXCLUSIVE;
+ streamStateSize = 0;
+ };
+
+ return groups;
+}
+
+namespace {
+struct ExclusiveInfo {
+
+ /** Mapping between top and exclusive group id */
+ map<u32, u32> groupId;
+
+ /** Number of exclusive groups */
+ u32 numGroups = 0;
+};
}
-namespace {
-struct ExclusiveInfo {
-
- /** Mapping between top and exclusive group id */
- map<u32, u32> groupId;
-
- /** Number of exclusive groups */
- u32 numGroups = 0;
-};
-}
-
static
void buildSubcastles(const CastleProto &proto, vector<SubCastle> &subs,
vector<RepeatInfo> &infos, vector<u64a> &patchSize,
const vector<pair<depth, bool>> &repeatInfoPair,
u32 &scratchStateSize, u32 &streamStateSize,
u32 &tableSize, vector<u64a> &tables, u32 &sparseRepeats,
- const ExclusiveInfo &exclusiveInfo,
- vector<u32> &may_stale, const ReportManager &rm) {
- const bool remap_reports = has_managed_reports(proto.kind);
-
+ const ExclusiveInfo &exclusiveInfo,
+ vector<u32> &may_stale, const ReportManager &rm) {
+ const bool remap_reports = has_managed_reports(proto.kind);
+
u32 i = 0;
- const auto &groupId = exclusiveInfo.groupId;
- const auto &numGroups = exclusiveInfo.numGroups;
- vector<u32> maxStreamSize(numGroups, 0);
-
+ const auto &groupId = exclusiveInfo.groupId;
+ const auto &numGroups = exclusiveInfo.numGroups;
+ vector<u32> maxStreamSize(numGroups, 0);
+
for (auto it = proto.repeats.begin(), ite = proto.repeats.end();
it != ite; ++it, ++i) {
const PureRepeat &pr = it->second;
@@ -361,7 +361,7 @@ void buildSubcastles(const CastleProto &proto, vector<SubCastle> &subs,
bool is_reset = repeatInfoPair[i].second;
enum RepeatType rtype = chooseRepeatType(pr.bounds.min, pr.bounds.max,
- min_period, is_reset, true);
+ min_period, is_reset, true);
RepeatStateInfo rsi(rtype, pr.bounds.min, pr.bounds.max, min_period);
DEBUG_PRINTF("sub %u: selected %s model for %s repeat\n", i,
@@ -370,26 +370,26 @@ void buildSubcastles(const CastleProto &proto, vector<SubCastle> &subs,
SubCastle &sub = subs[i];
RepeatInfo &info = infos[i];
- info.packedCtrlSize = rsi.packedCtrlSize;
- u32 subStreamStateSize = verify_u32(rsi.packedCtrlSize + rsi.stateSize);
-
- // Handle stream/scratch space alloc for exclusive case differently.
- if (contains(groupId, i)) {
- u32 id = groupId.at(i);
- maxStreamSize[id] = max(maxStreamSize[id], subStreamStateSize);
- // SubCastle full/stream state offsets are written in for the group
- // below.
+ info.packedCtrlSize = rsi.packedCtrlSize;
+ u32 subStreamStateSize = verify_u32(rsi.packedCtrlSize + rsi.stateSize);
+
+ // Handle stream/scratch space alloc for exclusive case differently.
+ if (contains(groupId, i)) {
+ u32 id = groupId.at(i);
+ maxStreamSize[id] = max(maxStreamSize[id], subStreamStateSize);
+ // SubCastle full/stream state offsets are written in for the group
+ // below.
} else {
sub.fullStateOffset = scratchStateSize;
sub.streamStateOffset = streamStateSize;
- scratchStateSize += verify_u32(sizeof(RepeatControl));
+ scratchStateSize += verify_u32(sizeof(RepeatControl));
streamStateSize += subStreamStateSize;
}
- if (pr.bounds.max.is_finite()) {
- may_stale.push_back(i);
- }
-
+ if (pr.bounds.max.is_finite()) {
+ may_stale.push_back(i);
+ }
+
info.type = verify_u8(rtype);
info.repeatMin = depth_to_u32(pr.bounds.min);
info.repeatMax = depth_to_u32(pr.bounds.max);
@@ -405,44 +405,44 @@ void buildSubcastles(const CastleProto &proto, vector<SubCastle> &subs,
info.encodingSize = rsi.encodingSize;
info.patchesOffset = rsi.patchesOffset;
- assert(pr.reports.size() == 1);
- ReportID id = *pr.reports.begin();
- sub.report = remap_reports ? rm.getProgramOffset(id) : id;
+ assert(pr.reports.size() == 1);
+ ReportID id = *pr.reports.begin();
+ sub.report = remap_reports ? rm.getProgramOffset(id) : id;
if (rtype == REPEAT_SPARSE_OPTIMAL_P) {
- for (u32 j = 0; j < rsi.patchSize; j++) {
- tables.push_back(rsi.table[j]);
- }
- sparseRepeats++;
- patchSize[i] = rsi.patchSize;
- tableSize += rsi.patchSize;
- }
- }
-
- vector<u32> scratchOffset(numGroups, 0);
- vector<u32> streamOffset(numGroups, 0);
- for (const auto &j : groupId) {
- u32 top = j.first;
- u32 id = j.second;
- SubCastle &sub = subs[top];
- if (!scratchOffset[id]) {
+ for (u32 j = 0; j < rsi.patchSize; j++) {
+ tables.push_back(rsi.table[j]);
+ }
+ sparseRepeats++;
+ patchSize[i] = rsi.patchSize;
+ tableSize += rsi.patchSize;
+ }
+ }
+
+ vector<u32> scratchOffset(numGroups, 0);
+ vector<u32> streamOffset(numGroups, 0);
+ for (const auto &j : groupId) {
+ u32 top = j.first;
+ u32 id = j.second;
+ SubCastle &sub = subs[top];
+ if (!scratchOffset[id]) {
sub.fullStateOffset = scratchStateSize;
sub.streamStateOffset = streamStateSize;
- scratchOffset[id] = scratchStateSize;
- streamOffset[id] = streamStateSize;
- scratchStateSize += verify_u32(sizeof(RepeatControl));
- streamStateSize += maxStreamSize[id];
- } else {
- sub.fullStateOffset = scratchOffset[id];
- sub.streamStateOffset = streamOffset[id];
+ scratchOffset[id] = scratchStateSize;
+ streamOffset[id] = streamStateSize;
+ scratchStateSize += verify_u32(sizeof(RepeatControl));
+ streamStateSize += maxStreamSize[id];
+ } else {
+ sub.fullStateOffset = scratchOffset[id];
+ sub.streamStateOffset = streamOffset[id];
}
}
}
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
buildCastle(const CastleProto &proto,
const map<u32, vector<vector<CharReach>>> &triggers,
- const CompileContext &cc, const ReportManager &rm) {
+ const CompileContext &cc, const ReportManager &rm) {
assert(cc.grey.allowCastle);
const size_t numRepeats = proto.repeats.size();
@@ -474,8 +474,8 @@ buildCastle(const CastleProto &proto,
depth maxWidth(0);
u32 i = 0;
- ExclusiveInfo exclusiveInfo;
- vector<vector<vector<CharReach>>> candidateTriggers;
+ ExclusiveInfo exclusiveInfo;
+ vector<vector<vector<CharReach>>> candidateTriggers;
vector<u32> candidateRepeats;
vector<pair<depth, bool>> repeatInfoPair;
for (auto it = proto.repeats.begin(), ite = proto.repeats.end();
@@ -501,7 +501,7 @@ buildCastle(const CastleProto &proto,
// possibly means that we've got a repeat that we can't trigger. We do
// need to cope with it though.
if (contains(triggers, top)) {
- min_period = depth(minPeriod(triggers.at(top), cr, &is_reset));
+ min_period = depth(minPeriod(triggers.at(top), cr, &is_reset));
}
if (min_period > pr.bounds.max) {
@@ -511,60 +511,60 @@ buildCastle(const CastleProto &proto,
repeatInfoPair.push_back(make_pair(min_period, is_reset));
- candidateTriggers.push_back(triggers.at(top));
- candidateRepeats.push_back(i);
+ candidateTriggers.push_back(triggers.at(top));
+ candidateRepeats.push_back(i);
}
// Case 1: exclusive repeats
- enum ExclusiveType exclusive = NOT_EXCLUSIVE;
+ enum ExclusiveType exclusive = NOT_EXCLUSIVE;
u32 activeIdxSize = 0;
- u32 groupIterOffset = 0;
+ u32 groupIterOffset = 0;
if (cc.grey.castleExclusive) {
- auto cliqueGroups =
- checkExclusion(streamStateSize, cr, candidateTriggers,
- exclusive, numRepeats);
- for (const auto &group : cliqueGroups) {
- // mutual exclusive repeats group found,
- // update state sizes
+ auto cliqueGroups =
+ checkExclusion(streamStateSize, cr, candidateTriggers,
+ exclusive, numRepeats);
+ for (const auto &group : cliqueGroups) {
+ // mutual exclusive repeats group found,
+ // update state sizes
activeIdxSize = calcPackedBytes(numRepeats + 1);
streamStateSize += activeIdxSize;
// replace with top values
- for (const auto &val : group) {
- const u32 top = candidateRepeats[val];
- exclusiveInfo.groupId[top] = exclusiveInfo.numGroups;
+ for (const auto &val : group) {
+ const u32 top = candidateRepeats[val];
+ exclusiveInfo.groupId[top] = exclusiveInfo.numGroups;
}
- exclusiveInfo.numGroups++;
+ exclusiveInfo.numGroups++;
}
-
- if (exclusive) {
- groupIterOffset = streamStateSize;
- streamStateSize += mmbit_size(exclusiveInfo.numGroups);
- }
-
- DEBUG_PRINTF("num of groups:%u\n", exclusiveInfo.numGroups);
+
+ if (exclusive) {
+ groupIterOffset = streamStateSize;
+ streamStateSize += mmbit_size(exclusiveInfo.numGroups);
+ }
+
+ DEBUG_PRINTF("num of groups:%u\n", exclusiveInfo.numGroups);
}
- candidateRepeats.clear();
+ candidateRepeats.clear();
DEBUG_PRINTF("reach %s exclusive %u\n", describeClass(cr).c_str(),
exclusive);
u32 tableSize = 0;
u32 sparseRepeats = 0;
- vector<u32> may_stale; /* sub castles that may go stale */
-
+ vector<u32> may_stale; /* sub castles that may go stale */
+
buildSubcastles(proto, subs, infos, patchSize, repeatInfoPair,
scratchStateSize, streamStateSize, tableSize,
- tables, sparseRepeats, exclusiveInfo, may_stale, rm);
-
- DEBUG_PRINTF("%zu subcastles may go stale\n", may_stale.size());
- vector<mmbit_sparse_iter> stale_iter;
- if (!may_stale.empty()) {
- stale_iter = mmbBuildSparseIterator(may_stale, numRepeats);
- }
-
-
- size_t total_size =
+ tables, sparseRepeats, exclusiveInfo, may_stale, rm);
+
+ DEBUG_PRINTF("%zu subcastles may go stale\n", may_stale.size());
+ vector<mmbit_sparse_iter> stale_iter;
+ if (!may_stale.empty()) {
+ stale_iter = mmbBuildSparseIterator(may_stale, numRepeats);
+ }
+
+
+ size_t total_size =
sizeof(NFA) + // initial NFA structure
sizeof(Castle) + // Castle structure
sizeof(SubCastle) * subs.size() + // SubCastles themselves
@@ -574,11 +574,11 @@ buildCastle(const CastleProto &proto,
sizeof(u64a) * sparseRepeats; // paddings for
// REPEAT_SPARSE_OPTIMAL_P tables
- total_size = ROUNDUP_N(total_size, alignof(mmbit_sparse_iter));
- total_size += byte_length(stale_iter); // stale sparse iter
-
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
- nfa->type = verify_u8(CASTLE_NFA);
+ total_size = ROUNDUP_N(total_size, alignof(mmbit_sparse_iter));
+ total_size += byte_length(stale_iter); // stale sparse iter
+
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ nfa->type = verify_u8(CASTLE_NFA);
nfa->length = verify_u32(total_size);
nfa->nPositions = verify_u32(subs.size());
nfa->streamStateSize = streamStateSize;
@@ -586,15 +586,15 @@ buildCastle(const CastleProto &proto,
nfa->minWidth = verify_u32(minWidth);
nfa->maxWidth = maxWidth.is_finite() ? verify_u32(maxWidth) : 0;
- char * const base_ptr = (char *)nfa.get() + sizeof(NFA);
- char *ptr = base_ptr;
+ char * const base_ptr = (char *)nfa.get() + sizeof(NFA);
+ char *ptr = base_ptr;
Castle *c = (Castle *)ptr;
c->numRepeats = verify_u32(subs.size());
- c->numGroups = exclusiveInfo.numGroups;
- c->exclusive = verify_s8(exclusive);
+ c->numGroups = exclusiveInfo.numGroups;
+ c->exclusive = verify_s8(exclusive);
c->activeIdxSize = verify_u8(activeIdxSize);
- c->activeOffset = verify_u32(c->numGroups * activeIdxSize);
- c->groupIterOffset = groupIterOffset;
+ c->activeOffset = verify_u32(c->numGroups * activeIdxSize);
+ c->groupIterOffset = groupIterOffset;
writeCastleScanEngine(cr, c);
@@ -628,22 +628,22 @@ buildCastle(const CastleProto &proto,
}
// set exclusive group info
- if (contains(exclusiveInfo.groupId, i)) {
- sub->exclusiveId = exclusiveInfo.groupId[i];
+ if (contains(exclusiveInfo.groupId, i)) {
+ sub->exclusiveId = exclusiveInfo.groupId[i];
} else {
- sub->exclusiveId = numRepeats;
- }
- }
-
- ptr = base_ptr + total_size - sizeof(NFA) - byte_length(stale_iter);
-
- assert(ptr + byte_length(stale_iter) == base_ptr + total_size - sizeof(NFA));
- if (!stale_iter.empty()) {
- c->staleIterOffset = verify_u32(ptr - base_ptr);
- copy_bytes(ptr, stale_iter);
- ptr += byte_length(stale_iter);
- }
-
+ sub->exclusiveId = numRepeats;
+ }
+ }
+
+ ptr = base_ptr + total_size - sizeof(NFA) - byte_length(stale_iter);
+
+ assert(ptr + byte_length(stale_iter) == base_ptr + total_size - sizeof(NFA));
+ if (!stale_iter.empty()) {
+ c->staleIterOffset = verify_u32(ptr - base_ptr);
+ copy_bytes(ptr, stale_iter);
+ ptr += byte_length(stale_iter);
+ }
+
return nfa;
}
@@ -687,7 +687,7 @@ depth findMaxWidth(const CastleProto &proto, u32 top) {
return proto.repeats.at(top).bounds.max;
}
-CastleProto::CastleProto(nfa_kind k, const PureRepeat &pr) : kind(k) {
+CastleProto::CastleProto(nfa_kind k, const PureRepeat &pr) : kind(k) {
assert(pr.reach.any());
assert(pr.reports.size() == 1);
u32 top = 0;
@@ -749,7 +749,7 @@ u32 CastleProto::merge(const PureRepeat &pr) {
bool mergeCastle(CastleProto &c1, const CastleProto &c2,
map<u32, u32> &top_map) {
assert(&c1 != &c2);
- assert(c1.kind == c2.kind);
+ assert(c1.kind == c2.kind);
DEBUG_PRINTF("c1 has %zu repeats, c2 has %zu repeats\n", c1.repeats.size(),
c2.repeats.size());
@@ -770,7 +770,7 @@ bool mergeCastle(CastleProto &c1, const CastleProto &c2,
const u32 top = m.first;
const PureRepeat &pr = m.second;
DEBUG_PRINTF("top %u\n", top);
- u32 new_top = c1.merge(pr);
+ u32 new_top = c1.merge(pr);
top_map[top] = new_top;
DEBUG_PRINTF("adding repeat: map %u->%u\n", top, new_top);
}
@@ -823,7 +823,7 @@ bool is_equal(const CastleProto &c1, ReportID report1, const CastleProto &c2,
ReportID report2) {
assert(!c1.repeats.empty());
assert(!c2.repeats.empty());
- assert(c1.kind == c2.kind);
+ assert(c1.kind == c2.kind);
if (c1.reach() != c2.reach()) {
DEBUG_PRINTF("different reach\n");
@@ -870,7 +870,7 @@ bool is_equal(const CastleProto &c1, ReportID report1, const CastleProto &c2,
bool is_equal(const CastleProto &c1, const CastleProto &c2) {
assert(!c1.repeats.empty());
assert(!c2.repeats.empty());
- assert(c1.kind == c2.kind);
+ assert(c1.kind == c2.kind);
if (c1.reach() != c2.reach()) {
DEBUG_PRINTF("different reach\n");
@@ -881,7 +881,7 @@ bool is_equal(const CastleProto &c1, const CastleProto &c2) {
}
bool requiresDedupe(const CastleProto &proto,
- const flat_set<ReportID> &reports) {
+ const flat_set<ReportID> &reports) {
for (const auto &report : reports) {
auto it = proto.report_map.find(report);
if (it == end(proto.report_map)) {
@@ -905,8 +905,8 @@ void addToHolder(NGHolder &g, u32 top, const PureRepeat &pr) {
u32 min_bound = pr.bounds.min; // always finite
if (min_bound == 0) { // Vacuous case, we can only do this once.
assert(!edge(g.start, g.accept, g).second);
- NFAEdge e = add_edge(g.start, g.accept, g);
- g[e].tops.insert(top);
+ NFAEdge e = add_edge(g.start, g.accept, g);
+ g[e].tops.insert(top);
g[u].reports.insert(pr.reports.begin(), pr.reports.end());
min_bound = 1;
}
@@ -914,9 +914,9 @@ void addToHolder(NGHolder &g, u32 top, const PureRepeat &pr) {
for (u32 i = 0; i < min_bound; i++) {
NFAVertex v = add_vertex(g);
g[v].char_reach = pr.reach;
- NFAEdge e = add_edge(u, v, g);
+ NFAEdge e = add_edge(u, v, g);
if (u == g.start) {
- g[e].tops.insert(top);
+ g[e].tops.insert(top);
}
u = v;
}
@@ -933,9 +933,9 @@ void addToHolder(NGHolder &g, u32 top, const PureRepeat &pr) {
if (head != u) {
add_edge(head, v, g);
}
- NFAEdge e = add_edge(u, v, g);
+ NFAEdge e = add_edge(u, v, g);
if (u == g.start) {
- g[e].tops.insert(top);
+ g[e].tops.insert(top);
}
u = v;
}
@@ -964,7 +964,7 @@ bool hasZeroMinBound(const CastleProto &proto) {
return false;
}
-unique_ptr<NGHolder> makeHolder(const CastleProto &proto,
+unique_ptr<NGHolder> makeHolder(const CastleProto &proto,
const CompileContext &cc) {
assert(!proto.repeats.empty());
@@ -977,13 +977,13 @@ unique_ptr<NGHolder> makeHolder(const CastleProto &proto,
}
}
- auto g = ue2::make_unique<NGHolder>(proto.kind);
+ auto g = ue2::make_unique<NGHolder>(proto.kind);
for (const auto &m : proto.repeats) {
addToHolder(*g, m.first, m.second);
}
- //dumpGraph("castle_holder.dot", *g);
+ //dumpGraph("castle_holder.dot", *g);
// Sanity checks.
assert(allMatchStatesHaveReports(*g));
diff --git a/contrib/libs/hyperscan/src/nfa/castlecompile.h b/contrib/libs/hyperscan/src/nfa/castlecompile.h
index cd830eb3a04..ea5f06dabc7 100644
--- a/contrib/libs/hyperscan/src/nfa/castlecompile.h
+++ b/contrib/libs/hyperscan/src/nfa/castlecompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Castle: multi-tenant repeat engine, compiler code.
*/
@@ -37,14 +37,14 @@
#include "nfa_kind.h"
#include "ue2common.h"
#include "nfagraph/ng_repeat.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/depth.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <map>
#include <memory>
#include <set>
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
struct NFA;
@@ -53,7 +53,7 @@ namespace ue2 {
class CharReach;
class NGHolder;
-class ReportManager;
+class ReportManager;
struct CompileContext;
/**
@@ -68,7 +68,7 @@ struct CompileContext;
*/
struct CastleProto {
static constexpr size_t max_occupancy = 65536; // arbitrary limit
- CastleProto(nfa_kind k, const PureRepeat &pr);
+ CastleProto(nfa_kind k, const PureRepeat &pr);
const CharReach &reach() const;
/** \brief Add a new repeat. */
@@ -90,16 +90,16 @@ struct CastleProto {
std::map<u32, PureRepeat> repeats;
/** \brief Mapping from report to associated tops. */
- std::unordered_map<ReportID, flat_set<u32>> report_map;
+ std::unordered_map<ReportID, flat_set<u32>> report_map;
/**
* \brief Next top id to use. Repeats may be removed without top remapping,
* so we track this explicitly instead of using repeats.size().
*/
u32 next_top = 1;
-
- /** \brief Kind for this engine. */
- nfa_kind kind;
+
+ /** \brief Kind for this engine. */
+ nfa_kind kind;
};
std::set<ReportID> all_reports(const CastleProto &proto);
@@ -122,15 +122,15 @@ void remapCastleTops(CastleProto &proto, std::map<u32, u32> &top_map);
* NOTE: Tops must be contiguous, i.e. \ref remapCastleTops must have been run
* first.
*/
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
buildCastle(const CastleProto &proto,
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
- const CompileContext &cc, const ReportManager &rm);
+ const CompileContext &cc, const ReportManager &rm);
/**
- * \brief Merge two CastleProto prototypes together, if possible. If a
- * particular repeat from c2 is already in c1, then it will be reused rather
- * than adding a duplicate repeat.
+ * \brief Merge two CastleProto prototypes together, if possible. If a
+ * particular repeat from c2 is already in c1, then it will be reused rather
+ * than adding a duplicate repeat.
*
* Returns true if merge of all repeats in c2 into c1 succeeds, and fills
* mapping with the repeat indices.
@@ -158,12 +158,12 @@ bool is_equal(const CastleProto &c1, const CastleProto &c2);
* of the reports in the given set.
*/
bool requiresDedupe(const CastleProto &proto,
- const flat_set<ReportID> &reports);
+ const flat_set<ReportID> &reports);
/**
* \brief Build an NGHolder from a CastleProto.
*/
-std::unique_ptr<NGHolder> makeHolder(const CastleProto &castle,
+std::unique_ptr<NGHolder> makeHolder(const CastleProto &castle,
const CompileContext &cc);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/dfa_build_strat.cpp b/contrib/libs/hyperscan/src/nfa/dfa_build_strat.cpp
index 378ad692c27..b6b7a7fb9f4 100644
--- a/contrib/libs/hyperscan/src/nfa/dfa_build_strat.cpp
+++ b/contrib/libs/hyperscan/src/nfa/dfa_build_strat.cpp
@@ -1,38 +1,38 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "dfa_build_strat.h"
-
-namespace ue2 {
-
-// prevent weak vtables for raw_report_info, dfa_build_strat
-raw_report_info::~raw_report_info() {}
-
-dfa_build_strat::~dfa_build_strat() {}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "dfa_build_strat.h"
+
+namespace ue2 {
+
+// prevent weak vtables for raw_report_info, dfa_build_strat
+raw_report_info::~raw_report_info() {}
+
+dfa_build_strat::~dfa_build_strat() {}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/dfa_build_strat.h b/contrib/libs/hyperscan/src/nfa/dfa_build_strat.h
index 552e35573a3..cda001623c8 100644
--- a/contrib/libs/hyperscan/src/nfa/dfa_build_strat.h
+++ b/contrib/libs/hyperscan/src/nfa/dfa_build_strat.h
@@ -1,68 +1,68 @@
-/*
- * Copyright (c) 2015-2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef DFA_BUILD_STRAT_H
-#define DFA_BUILD_STRAT_H
-
-#include "rdfa.h"
-#include "ue2common.h"
-
-#include <memory>
-#include <vector>
-
-struct NFA;
-
-namespace ue2 {
-
-class ReportManager;
-
-struct raw_report_info {
- virtual ~raw_report_info();
- virtual u32 getReportListSize() const = 0; /* in bytes */
- virtual size_t size() const = 0; /* number of lists */
- virtual void fillReportLists(NFA *n, size_t base_offset,
- std::vector<u32> &ro /* out */) const = 0;
-};
-
-class dfa_build_strat {
-public:
- explicit dfa_build_strat(const ReportManager &rm_in) : rm(rm_in) {}
- virtual ~dfa_build_strat();
- virtual raw_dfa &get_raw() const = 0;
- virtual std::unique_ptr<raw_report_info> gatherReports(
- std::vector<u32> &reports /* out */,
- std::vector<u32> &reports_eod /* out */,
- u8 *isSingleReport /* out */,
- ReportID *arbReport /* out */) const = 0;
-protected:
- const ReportManager &rm;
-};
-
-} // namespace ue2
-
-#endif // DFA_BUILD_STRAT_H
+/*
+ * Copyright (c) 2015-2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef DFA_BUILD_STRAT_H
+#define DFA_BUILD_STRAT_H
+
+#include "rdfa.h"
+#include "ue2common.h"
+
+#include <memory>
+#include <vector>
+
+struct NFA;
+
+namespace ue2 {
+
+class ReportManager;
+
+struct raw_report_info {
+ virtual ~raw_report_info();
+ virtual u32 getReportListSize() const = 0; /* in bytes */
+ virtual size_t size() const = 0; /* number of lists */
+ virtual void fillReportLists(NFA *n, size_t base_offset,
+ std::vector<u32> &ro /* out */) const = 0;
+};
+
+class dfa_build_strat {
+public:
+ explicit dfa_build_strat(const ReportManager &rm_in) : rm(rm_in) {}
+ virtual ~dfa_build_strat();
+ virtual raw_dfa &get_raw() const = 0;
+ virtual std::unique_ptr<raw_report_info> gatherReports(
+ std::vector<u32> &reports /* out */,
+ std::vector<u32> &reports_eod /* out */,
+ u8 *isSingleReport /* out */,
+ ReportID *arbReport /* out */) const = 0;
+protected:
+ const ReportManager &rm;
+};
+
+} // namespace ue2
+
+#endif // DFA_BUILD_STRAT_H
diff --git a/contrib/libs/hyperscan/src/nfa/dfa_min.cpp b/contrib/libs/hyperscan/src/nfa/dfa_min.cpp
index 68b7680b78c..1a07e8a7d36 100644
--- a/contrib/libs/hyperscan/src/nfa/dfa_min.cpp
+++ b/contrib/libs/hyperscan/src/nfa/dfa_min.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,14 +26,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Build code for DFA minimization.
- */
+/**
+ * \file
+ * \brief Build code for DFA minimization.
+ */
/**
- * /Summary of the Hopcroft minimisation algorithm/
- *
+ * /Summary of the Hopcroft minimisation algorithm/
+ *
* partition := {F, Q \ F};
* work_queue := {F};
* while (work_queue is not empty) do
@@ -59,19 +59,19 @@
#include "dfa_min.h"
#include "grey.h"
-#include "mcclellancompile_util.h"
-#include "rdfa.h"
+#include "mcclellancompile_util.h"
+#include "rdfa.h"
#include "ue2common.h"
-#include "util/container.h"
-#include "util/flat_containers.h"
-#include "util/noncopyable.h"
+#include "util/container.h"
+#include "util/flat_containers.h"
+#include "util/noncopyable.h"
#include "util/partitioned_set.h"
#include <algorithm>
#include <functional>
-#include <iterator>
+#include <iterator>
#include <map>
-#include <queue>
+#include <queue>
#include <set>
#include <vector>
@@ -82,77 +82,77 @@ namespace ue2 {
namespace {
struct hopcroft_state_info {
- explicit hopcroft_state_info(size_t alpha_size) : prev(alpha_size) {}
-
- /** \brief Mapping from symbol to a list of predecessors that transition to
- * this state on that symbol. */
- vector<vector<dstate_id_t>> prev;
+ explicit hopcroft_state_info(size_t alpha_size) : prev(alpha_size) {}
+
+ /** \brief Mapping from symbol to a list of predecessors that transition to
+ * this state on that symbol. */
+ vector<vector<dstate_id_t>> prev;
};
-struct HopcroftInfo : noncopyable {
- size_t alpha_size; //!< Size of DFA alphabet.
- queue<size_t> work_queue; //!< Hopcroft work queue of partition indices.
- partitioned_set<dstate_id_t> partition; //!< Partition set of DFA states.
- vector<hopcroft_state_info> states; //!< Pre-calculated state info (preds)
+struct HopcroftInfo : noncopyable {
+ size_t alpha_size; //!< Size of DFA alphabet.
+ queue<size_t> work_queue; //!< Hopcroft work queue of partition indices.
+ partitioned_set<dstate_id_t> partition; //!< Partition set of DFA states.
+ vector<hopcroft_state_info> states; //!< Pre-calculated state info (preds)
- explicit HopcroftInfo(const raw_dfa &rdfa);
+ explicit HopcroftInfo(const raw_dfa &rdfa);
};
-} // namespace
+} // namespace
/**
- * \brief Create an initial partitioning and work_queue.
+ * \brief Create an initial partitioning and work_queue.
*
- * Initial partition contains {accepting states..., Non-accepting states}
- * Initial work_queue contains accepting state subsets
+ * Initial partition contains {accepting states..., Non-accepting states}
+ * Initial work_queue contains accepting state subsets
*
- * The initial partitioning needs to distinguish between the different
- * reporting behaviours (unlike standard Hopcroft) --> more than one subset
- * possible for the accepting states.
- *
- * Look for accepting states in both reports and reports_eod.
- * Creates a map with a key(reports, reports_eod) and an id.
- * Reports of each state are searched against the map and
- * added to the corresponding id -> partition[id] and work_queue[id].
- * Non Accept states are added to partition[id+1].
+ * The initial partitioning needs to distinguish between the different
+ * reporting behaviours (unlike standard Hopcroft) --> more than one subset
+ * possible for the accepting states.
+ *
+ * Look for accepting states in both reports and reports_eod.
+ * Creates a map with a key(reports, reports_eod) and an id.
+ * Reports of each state are searched against the map and
+ * added to the corresponding id -> partition[id] and work_queue[id].
+ * Non Accept states are added to partition[id+1].
*/
static
-vector<size_t> create_map(const raw_dfa &rdfa, queue<size_t> &work_queue) {
+vector<size_t> create_map(const raw_dfa &rdfa, queue<size_t> &work_queue) {
using ReportKey = pair<flat_set<ReportID>, flat_set<ReportID>>;
map<ReportKey, size_t> subset_map;
vector<size_t> state_to_subset(rdfa.states.size(), INVALID_SUBSET);
for (size_t i = 0; i < rdfa.states.size(); i++) {
- const auto &ds = rdfa.states[i];
- if (!ds.reports.empty() || !ds.reports_eod.empty()) {
- ReportKey key(ds.reports, ds.reports_eod);
+ const auto &ds = rdfa.states[i];
+ if (!ds.reports.empty() || !ds.reports_eod.empty()) {
+ ReportKey key(ds.reports, ds.reports_eod);
if (contains(subset_map, key)) {
state_to_subset[i] = subset_map[key];
} else {
size_t sub = subset_map.size();
- subset_map.emplace(std::move(key), sub);
+ subset_map.emplace(std::move(key), sub);
state_to_subset[i] = sub;
- work_queue.push(sub);
+ work_queue.push(sub);
}
}
}
- /* Give non-accept states their own subset. */
+ /* Give non-accept states their own subset. */
size_t non_accept_sub = subset_map.size();
- replace(state_to_subset.begin(), state_to_subset.end(), INVALID_SUBSET,
- non_accept_sub);
+ replace(state_to_subset.begin(), state_to_subset.end(), INVALID_SUBSET,
+ non_accept_sub);
return state_to_subset;
}
-HopcroftInfo::HopcroftInfo(const raw_dfa &rdfa)
- : alpha_size(rdfa.alpha_size), partition(create_map(rdfa, work_queue)),
- states(rdfa.states.size(), hopcroft_state_info(alpha_size)) {
- /* Construct predecessor lists for each state, indexed by symbol. */
- for (size_t i = 0; i < states.size(); i++) { // i is the previous state
- for (size_t sym = 0; sym < alpha_size; sym++) {
- dstate_id_t present_state = rdfa.states[i].next[sym];
- states[present_state].prev[sym].push_back(i);
+HopcroftInfo::HopcroftInfo(const raw_dfa &rdfa)
+ : alpha_size(rdfa.alpha_size), partition(create_map(rdfa, work_queue)),
+ states(rdfa.states.size(), hopcroft_state_info(alpha_size)) {
+ /* Construct predecessor lists for each state, indexed by symbol. */
+ for (size_t i = 0; i < states.size(); i++) { // i is the previous state
+ for (size_t sym = 0; sym < alpha_size; sym++) {
+ dstate_id_t present_state = rdfa.states[i].next[sym];
+ states[present_state].prev[sym].push_back(i);
}
}
}
@@ -170,14 +170,14 @@ HopcroftInfo::HopcroftInfo(const raw_dfa &rdfa)
* - replace S in work_queue by the smaller of the two sets.
*/
static
-void split_and_replace_set(const size_t part_index, HopcroftInfo &info,
- const flat_set<dstate_id_t> &splitter) {
+void split_and_replace_set(const size_t part_index, HopcroftInfo &info,
+ const flat_set<dstate_id_t> &splitter) {
/* singleton sets cannot be split */
- if (info.partition[part_index].size() == 1) {
+ if (info.partition[part_index].size() == 1) {
return;
}
- size_t small_index = info.partition.split(part_index, splitter);
+ size_t small_index = info.partition.split(part_index, splitter);
if (small_index == INVALID_SUBSET) {
/* the set could not be split */
@@ -187,56 +187,56 @@ void split_and_replace_set(const size_t part_index, HopcroftInfo &info,
/* larger subset remains at the input subset index, if the input subset was
* already in the work queue then the larger subset will remain there. */
- info.work_queue.push(small_index);
+ info.work_queue.push(small_index);
}
/**
- * \brief Core of the Hopcroft minimisation algorithm.
+ * \brief Core of the Hopcroft minimisation algorithm.
*/
static
-void dfa_min(HopcroftInfo &info) {
- flat_set<dstate_id_t> curr, sym_preds;
+void dfa_min(HopcroftInfo &info) {
+ flat_set<dstate_id_t> curr, sym_preds;
vector<size_t> cand_subsets;
- while (!info.work_queue.empty()) {
- /* Choose and remove a set of states (curr, or A in the description
- * above) from the work queue. Note that we copy the set because the
- * partition may be split by the loop below. */
- curr.clear();
- insert(&curr, info.partition[info.work_queue.front()]);
- info.work_queue.pop();
-
- for (size_t sym = 0; sym < info.alpha_size; sym++) {
- /* Find the set of states sym_preds for which a transition on the
- * given symbol leads to a state in curr. */
- sym_preds.clear();
- for (dstate_id_t s : curr) {
- insert(&sym_preds, info.states[s].prev[sym]);
- }
-
- if (sym_preds.empty()) {
+ while (!info.work_queue.empty()) {
+ /* Choose and remove a set of states (curr, or A in the description
+ * above) from the work queue. Note that we copy the set because the
+ * partition may be split by the loop below. */
+ curr.clear();
+ insert(&curr, info.partition[info.work_queue.front()]);
+ info.work_queue.pop();
+
+ for (size_t sym = 0; sym < info.alpha_size; sym++) {
+ /* Find the set of states sym_preds for which a transition on the
+ * given symbol leads to a state in curr. */
+ sym_preds.clear();
+ for (dstate_id_t s : curr) {
+ insert(&sym_preds, info.states[s].prev[sym]);
+ }
+
+ if (sym_preds.empty()) {
continue;
}
- /* we only need to consider subsets with at least one member in
- * sym_preds for splitting */
+ /* we only need to consider subsets with at least one member in
+ * sym_preds for splitting */
cand_subsets.clear();
- info.partition.find_overlapping(sym_preds, &cand_subsets);
+ info.partition.find_overlapping(sym_preds, &cand_subsets);
for (size_t sub : cand_subsets) {
- split_and_replace_set(sub, info, sym_preds);
+ split_and_replace_set(sub, info, sym_preds);
}
}
}
}
/**
- * \brief Build the new DFA state table.
+ * \brief Build the new DFA state table.
*/
static
-void mapping_new_states(const HopcroftInfo &info,
- vector<dstate_id_t> &old_to_new, raw_dfa &rdfa) {
- const size_t num_partitions = info.partition.size();
+void mapping_new_states(const HopcroftInfo &info,
+ vector<dstate_id_t> &old_to_new, raw_dfa &rdfa) {
+ const size_t num_partitions = info.partition.size();
// Mapping from equiv class's first state to equiv class index.
map<dstate_id_t, size_t> ordering;
@@ -245,7 +245,7 @@ void mapping_new_states(const HopcroftInfo &info,
vector<dstate_id_t> eq_state(num_partitions);
for (size_t i = 0; i < num_partitions; i++) {
- ordering[*info.partition[i].begin()] = i;
+ ordering[*info.partition[i].begin()] = i;
}
dstate_id_t new_id = 0;
@@ -253,28 +253,28 @@ void mapping_new_states(const HopcroftInfo &info,
eq_state[m.second] = new_id++;
}
- for (size_t t = 0; t < info.partition.size(); t++) {
- for (dstate_id_t id : info.partition[t]) {
+ for (size_t t = 0; t < info.partition.size(); t++) {
+ for (dstate_id_t id : info.partition[t]) {
old_to_new[id] = eq_state[t];
}
}
vector<dstate> new_states;
new_states.reserve(num_partitions);
-
- for (const auto &m : ordering) {
- new_states.push_back(rdfa.states[m.first]);
+
+ for (const auto &m : ordering) {
+ new_states.push_back(rdfa.states[m.first]);
}
- rdfa.states = std::move(new_states);
+ rdfa.states = std::move(new_states);
}
static
-void renumber_new_states(const HopcroftInfo &info,
- const vector<dstate_id_t> &old_to_new, raw_dfa &rdfa) {
- for (size_t i = 0; i < info.partition.size(); i++) {
- for (size_t sym = 0; sym < info.alpha_size; sym++) {
- dstate_id_t output = rdfa.states[i].next[sym];
- rdfa.states[i].next[sym] = old_to_new[output];
+void renumber_new_states(const HopcroftInfo &info,
+ const vector<dstate_id_t> &old_to_new, raw_dfa &rdfa) {
+ for (size_t i = 0; i < info.partition.size(); i++) {
+ for (size_t sym = 0; sym < info.alpha_size; sym++) {
+ dstate_id_t output = rdfa.states[i].next[sym];
+ rdfa.states[i].next[sym] = old_to_new[output];
}
dstate_id_t dad = rdfa.states[i].daddy;
rdfa.states[i].daddy = old_to_new[dad];
@@ -285,14 +285,14 @@ void renumber_new_states(const HopcroftInfo &info,
}
static
-void new_dfa(raw_dfa &rdfa, const HopcroftInfo &info) {
- if (info.partition.size() == info.states.size()) {
- return;
+void new_dfa(raw_dfa &rdfa, const HopcroftInfo &info) {
+ if (info.partition.size() == info.states.size()) {
+ return;
}
-
- vector<dstate_id_t> old_to_new(info.states.size());
- mapping_new_states(info, old_to_new, rdfa);
- renumber_new_states(info, old_to_new, rdfa);
+
+ vector<dstate_id_t> old_to_new(info.states.size());
+ mapping_new_states(info, old_to_new, rdfa);
+ renumber_new_states(info, old_to_new, rdfa);
}
void minimize_hopcroft(raw_dfa &rdfa, const Grey &grey) {
@@ -300,16 +300,16 @@ void minimize_hopcroft(raw_dfa &rdfa, const Grey &grey) {
return;
}
- if (is_dead(rdfa)) {
- DEBUG_PRINTF("dfa is empty\n");
- }
-
+ if (is_dead(rdfa)) {
+ DEBUG_PRINTF("dfa is empty\n");
+ }
+
UNUSED const size_t states_before = rdfa.states.size();
- HopcroftInfo info(rdfa);
+ HopcroftInfo info(rdfa);
- dfa_min(info);
- new_dfa(rdfa, info);
+ dfa_min(info);
+ new_dfa(rdfa, info);
DEBUG_PRINTF("reduced from %zu to %zu states\n", states_before,
rdfa.states.size());
diff --git a/contrib/libs/hyperscan/src/nfa/dfa_min.h b/contrib/libs/hyperscan/src/nfa/dfa_min.h
index efad545f1ec..61ca6c21a40 100644
--- a/contrib/libs/hyperscan/src/nfa/dfa_min.h
+++ b/contrib/libs/hyperscan/src/nfa/dfa_min.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,9 +26,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Build code for DFA minimization.
+/**
+ * \file
+ * \brief Build code for DFA minimization.
*/
#ifndef DFA_MIN_H
diff --git a/contrib/libs/hyperscan/src/nfa/gough.c b/contrib/libs/hyperscan/src/nfa/gough.c
index 1dde71e9bab..44acd4c2865 100644
--- a/contrib/libs/hyperscan/src/nfa/gough.c
+++ b/contrib/libs/hyperscan/src/nfa/gough.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -110,7 +110,7 @@ u64a expandSomValue(u32 comp_slot_width, u64a curr_offset,
}
static really_inline
-char doReports(NfaCallback cb, void *ctxt, const struct mcclellan *m,
+char doReports(NfaCallback cb, void *ctxt, const struct mcclellan *m,
const struct gough_som_info *som, u16 s, u64a loc,
char eod, u16 * const cached_accept_state,
u32 * const cached_accept_id, u32 * const cached_accept_som) {
@@ -307,7 +307,7 @@ u16 goughEnableStarts(const struct mcclellan *m, u16 s, u64a som_offset,
static really_inline
char goughExec16_i(const struct mcclellan *m, struct gough_som_info *som,
u16 *state, const u8 *buf, size_t len, u64a offAdj,
- NfaCallback cb, void *ctxt, const u8 **c_final,
+ NfaCallback cb, void *ctxt, const u8 **c_final,
enum MatchMode mode) {
assert(ISALIGNED_N(state, 2));
@@ -461,7 +461,7 @@ with_accel:
static really_inline
char goughExec8_i(const struct mcclellan *m, struct gough_som_info *som,
u8 *state, const u8 *buf, size_t len, u64a offAdj,
- NfaCallback cb, void *ctxt, const u8 **c_final,
+ NfaCallback cb, void *ctxt, const u8 **c_final,
enum MatchMode mode) {
u8 s = *state;
const u8 *c = buf, *c_end = buf + len;
@@ -595,7 +595,7 @@ with_accel:
static never_inline
char goughExec8_i_ni(const struct mcclellan *m, struct gough_som_info *som,
u8 *state, const u8 *buf, size_t len, u64a offAdj,
- NfaCallback cb, void *ctxt, const u8 **final_point,
+ NfaCallback cb, void *ctxt, const u8 **final_point,
enum MatchMode mode) {
return goughExec8_i(m, som, state, buf, len, offAdj, cb, ctxt, final_point,
mode);
@@ -604,7 +604,7 @@ char goughExec8_i_ni(const struct mcclellan *m, struct gough_som_info *som,
static never_inline
char goughExec16_i_ni(const struct mcclellan *m, struct gough_som_info *som,
u16 *state, const u8 *buf, size_t len, u64a offAdj,
- NfaCallback cb, void *ctxt, const u8 **final_point,
+ NfaCallback cb, void *ctxt, const u8 **final_point,
enum MatchMode mode) {
return goughExec16_i(m, som, state, buf, len, offAdj, cb, ctxt, final_point,
mode);
@@ -622,7 +622,7 @@ const struct gough_som_info *getSomInfoConst(const char *state_base) {
static really_inline
char nfaExecGough8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
- const u8 *hend, NfaCallback cb, void *context,
+ const u8 *hend, NfaCallback cb, void *context,
struct mq *q, s64a end, enum MatchMode mode) {
DEBUG_PRINTF("enter\n");
struct gough_som_info *som = getSomInfo(q->state);
@@ -685,7 +685,7 @@ char nfaExecGough8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
const u8 *final_look;
if (goughExec8_i_ni(m, som, &s, cur_buf + sp, local_ep - sp,
- offset + sp, cb, context, &final_look, mode)
+ offset + sp, cb, context, &final_look, mode)
== MO_HALT_MATCHING) {
*(u8 *)q->state = 0;
return 0;
@@ -747,7 +747,7 @@ char nfaExecGough8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
static really_inline
char nfaExecGough16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
- const u8 *hend, NfaCallback cb, void *context,
+ const u8 *hend, NfaCallback cb, void *context,
struct mq *q, s64a end, enum MatchMode mode) {
struct gough_som_info *som = getSomInfo(q->state);
assert(n->type == GOUGH_NFA_16);
@@ -808,7 +808,7 @@ char nfaExecGough16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
/* do main buffer region */
const u8 *final_look;
if (goughExec16_i_ni(m, som, &s, cur_buf + sp, local_ep - sp,
- offset + sp, cb, context, &final_look, mode)
+ offset + sp, cb, context, &final_look, mode)
== MO_HALT_MATCHING) {
*(u16 *)q->state = 0;
return 0;
@@ -870,7 +870,7 @@ char nfaExecGough16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
char nfaExecGough8_Q(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_8);
const u8 *hend = q->history + q->hlength;
@@ -882,7 +882,7 @@ char nfaExecGough8_Q(const struct NFA *n, struct mq *q, s64a end) {
char nfaExecGough16_Q(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_16);
const u8 *hend = q->history + q->hlength;
@@ -894,7 +894,7 @@ char nfaExecGough16_Q(const struct NFA *n, struct mq *q, s64a end) {
char nfaExecGough8_Q2(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_8);
const u8 *hend = q->history + q->hlength;
@@ -906,7 +906,7 @@ char nfaExecGough8_Q2(const struct NFA *n, struct mq *q, s64a end) {
char nfaExecGough16_Q2(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_16);
const u8 *hend = q->history + q->hlength;
@@ -918,7 +918,7 @@ char nfaExecGough16_Q2(const struct NFA *n, struct mq *q, s64a end) {
char nfaExecGough8_QR(const struct NFA *n, struct mq *q, ReportID report) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_8);
const u8 *hend = q->history + q->hlength;
@@ -935,7 +935,7 @@ char nfaExecGough8_QR(const struct NFA *n, struct mq *q, ReportID report) {
char nfaExecGough16_QR(const struct NFA *n, struct mq *q, ReportID report) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == GOUGH_NFA_16);
const u8 *hend = q->history + q->hlength;
@@ -977,7 +977,7 @@ char nfaExecGough16_initCompressedState(const struct NFA *nfa, u64a offset,
char nfaExecGough8_reportCurrent(const struct NFA *n, struct mq *q) {
const struct mcclellan *m = (const struct mcclellan *)getImplNfa(n);
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *ctxt = q->context;
u8 s = *(u8 *)q->state;
u64a offset = q_cur_offset(q);
@@ -999,7 +999,7 @@ char nfaExecGough8_reportCurrent(const struct NFA *n, struct mq *q) {
char nfaExecGough16_reportCurrent(const struct NFA *n, struct mq *q) {
const struct mcclellan *m = (const struct mcclellan *)getImplNfa(n);
- NfaCallback cb = q->cb;
+ NfaCallback cb = q->cb;
void *ctxt = q->context;
u16 s = *(u16 *)q->state;
const struct mstate_aux *aux = get_aux(m, s);
@@ -1031,42 +1031,42 @@ char nfaExecGough16_inAccept(const struct NFA *n, ReportID report,
return nfaExecMcClellan16_inAccept(n, report, q);
}
-char nfaExecGough8_inAnyAccept(const struct NFA *n, struct mq *q) {
- return nfaExecMcClellan8_inAnyAccept(n, q);
-}
-
-char nfaExecGough16_inAnyAccept(const struct NFA *n, struct mq *q) {
- return nfaExecMcClellan16_inAnyAccept(n, q);
-}
-
+char nfaExecGough8_inAnyAccept(const struct NFA *n, struct mq *q) {
+ return nfaExecMcClellan8_inAnyAccept(n, q);
+}
+
+char nfaExecGough16_inAnyAccept(const struct NFA *n, struct mq *q) {
+ return nfaExecMcClellan16_inAnyAccept(n, q);
+}
+
static
-char goughCheckEOD(const struct NFA *nfa, u16 s,
+char goughCheckEOD(const struct NFA *nfa, u16 s,
const struct gough_som_info *som,
- u64a offset, NfaCallback cb, void *ctxt) {
+ u64a offset, NfaCallback cb, void *ctxt) {
const struct mcclellan *m = (const struct mcclellan *)getImplNfa(nfa);
const struct mstate_aux *aux = get_aux(m, s);
- if (!aux->accept_eod) {
- return MO_CONTINUE_MATCHING;
+ if (!aux->accept_eod) {
+ return MO_CONTINUE_MATCHING;
}
- return doReports(cb, ctxt, m, som, s, offset, 1, NULL, NULL, NULL);
+ return doReports(cb, ctxt, m, som, s, offset, 1, NULL, NULL, NULL);
}
char nfaExecGough8_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
const struct gough_som_info *som = getSomInfoConst(state);
- return goughCheckEOD(nfa, *(const u8 *)state, som, offset, callback,
- context);
+ return goughCheckEOD(nfa, *(const u8 *)state, som, offset, callback,
+ context);
}
char nfaExecGough16_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
assert(ISALIGNED_N(state, 8));
const struct gough_som_info *som = getSomInfoConst(state);
- return goughCheckEOD(nfa, *(const u16 *)state, som, offset, callback,
- context);
+ return goughCheckEOD(nfa, *(const u16 *)state, som, offset, callback,
+ context);
}
char nfaExecGough8_queueInitState(UNUSED const struct NFA *nfa, struct mq *q) {
diff --git a/contrib/libs/hyperscan/src/nfa/gough.h b/contrib/libs/hyperscan/src/nfa/gough.h
index e3d9f64190f..a7f4889232e 100644
--- a/contrib/libs/hyperscan/src/nfa/gough.h
+++ b/contrib/libs/hyperscan/src/nfa/gough.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,13 +39,13 @@ struct mq;
char nfaExecGough8_testEOD(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
char nfaExecGough8_Q(const struct NFA *n, struct mq *q, s64a end);
char nfaExecGough8_Q2(const struct NFA *n, struct mq *q, s64a end);
char nfaExecGough8_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecGough8_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecGough8_inAccept(const struct NFA *n, ReportID report, struct mq *q);
-char nfaExecGough8_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecGough8_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecGough8_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecGough8_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -61,13 +61,13 @@ char nfaExecGough8_expandState(const struct NFA *nfa, void *dest,
char nfaExecGough16_testEOD(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
char nfaExecGough16_Q(const struct NFA *n, struct mq *q, s64a end);
char nfaExecGough16_Q2(const struct NFA *n, struct mq *q, s64a end);
char nfaExecGough16_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecGough16_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecGough16_inAccept(const struct NFA *n, ReportID report, struct mq *q);
-char nfaExecGough16_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecGough16_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecGough16_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecGough16_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
diff --git a/contrib/libs/hyperscan/src/nfa/goughcompile.cpp b/contrib/libs/hyperscan/src/nfa/goughcompile.cpp
index cd127cdba07..d41c6f42356 100644
--- a/contrib/libs/hyperscan/src/nfa/goughcompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/goughcompile.cpp
@@ -37,11 +37,11 @@
#include "nfa_internal.h"
#include "util/compile_context.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/make_unique.h"
#include "util/order_check.h"
-#include "util/report_manager.h"
+#include "util/report_manager.h"
#include "util/verify_types.h"
#include "ue2common.h"
@@ -77,20 +77,20 @@ namespace {
class gough_build_strat : public mcclellan_build_strat {
public:
- gough_build_strat(
- raw_som_dfa &r, const GoughGraph &g, const ReportManager &rm_in,
- const map<dstate_id_t, gough_accel_state_info> &accel_info)
- : mcclellan_build_strat(r, rm_in, false), rdfa(r), gg(g),
+ gough_build_strat(
+ raw_som_dfa &r, const GoughGraph &g, const ReportManager &rm_in,
+ const map<dstate_id_t, gough_accel_state_info> &accel_info)
+ : mcclellan_build_strat(r, rm_in, false), rdfa(r), gg(g),
accel_gough_info(accel_info) {}
unique_ptr<raw_report_info> gatherReports(vector<u32> &reports /* out */,
vector<u32> &reports_eod /* out */,
u8 *isSingleReport /* out */,
ReportID *arbReport /* out */) const override;
- AccelScheme find_escape_strings(dstate_id_t this_idx) const override;
+ AccelScheme find_escape_strings(dstate_id_t this_idx) const override;
size_t accelSize(void) const override { return sizeof(gough_accel); }
- void buildAccel(dstate_id_t this_idx, const AccelScheme &info,
- void *accel_out) override;
- u32 max_allowed_offset_accel() const override { return 0; }
+ void buildAccel(dstate_id_t this_idx, const AccelScheme &info,
+ void *accel_out) override;
+ u32 max_allowed_offset_accel() const override { return 0; }
DfaType getType() const override { return Gough; }
raw_som_dfa &rdfa;
@@ -1036,9 +1036,9 @@ void update_accel_prog_offset(const gough_build_strat &gbs,
}
}
-bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
- const CompileContext &cc,
- const ReportManager &rm) {
+bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
+ const CompileContext &cc,
+ const ReportManager &rm) {
assert(somPrecision == 2 || somPrecision == 4 || somPrecision == 8
|| !cc.streaming);
@@ -1070,8 +1070,8 @@ bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
map<dstate_id_t, gough_accel_state_info> accel_allowed;
find_allowed_accel_states(*cfg, blocks, &accel_allowed);
- gough_build_strat gbs(raw, *cfg, rm, accel_allowed);
- auto basic_dfa = mcclellanCompile_i(raw, gbs, cc);
+ gough_build_strat gbs(raw, *cfg, rm, accel_allowed);
+ auto basic_dfa = mcclellanCompile_i(raw, gbs, cc);
assert(basic_dfa);
if (!basic_dfa) {
return nullptr;
@@ -1117,7 +1117,7 @@ bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
gi.stream_som_loc_width = somPrecision;
u32 gough_size = ROUNDUP_N(curr_offset, 16);
- auto gough_dfa = make_zeroed_bytecode_ptr<NFA>(gough_size);
+ auto gough_dfa = make_zeroed_bytecode_ptr<NFA>(gough_size);
memcpy(gough_dfa.get(), basic_dfa.get(), basic_dfa->length);
memcpy((char *)gough_dfa.get() + haig_offset, &gi, sizeof(gi));
@@ -1149,44 +1149,44 @@ bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
return gough_dfa;
}
-AccelScheme gough_build_strat::find_escape_strings(dstate_id_t this_idx) const {
- AccelScheme rv;
+AccelScheme gough_build_strat::find_escape_strings(dstate_id_t this_idx) const {
+ AccelScheme rv;
if (!contains(accel_gough_info, this_idx)) {
- rv.cr = CharReach::dot();
- rv.double_byte.clear();
- return rv;
+ rv.cr = CharReach::dot();
+ rv.double_byte.clear();
+ return rv;
}
- rv = mcclellan_build_strat::find_escape_strings(this_idx);
+ rv = mcclellan_build_strat::find_escape_strings(this_idx);
+
+ assert(!rv.offset || rv.cr.all()); /* should have been limited by strat */
+ if (rv.offset) {
+ rv.cr = CharReach::dot();
+ rv.double_byte.clear();
+ return rv;
+ }
- assert(!rv.offset || rv.cr.all()); /* should have been limited by strat */
- if (rv.offset) {
- rv.cr = CharReach::dot();
- rv.double_byte.clear();
- return rv;
+ if (rv.double_offset
+ || !accel_gough_info.at(this_idx).two_byte) {
+ rv.double_byte.clear();
}
-
- if (rv.double_offset
- || !accel_gough_info.at(this_idx).two_byte) {
- rv.double_byte.clear();
- }
-
- return rv;
+
+ return rv;
}
-void gough_build_strat::buildAccel(dstate_id_t this_idx, const AccelScheme &info,
- void *accel_out) {
+void gough_build_strat::buildAccel(dstate_id_t this_idx, const AccelScheme &info,
+ void *accel_out) {
assert(mcclellan_build_strat::accelSize() == sizeof(AccelAux));
gough_accel *accel = (gough_accel *)accel_out;
/* build a plain accelaux so we can work out where we can get to */
- mcclellan_build_strat::buildAccel(this_idx, info, &accel->accel);
+ mcclellan_build_strat::buildAccel(this_idx, info, &accel->accel);
DEBUG_PRINTF("state %hu is accel with type %hhu\n", this_idx,
accel->accel.accel_type);
if (accel->accel.accel_type == ACCEL_NONE) {
return;
}
- assert(!accel->accel.generic.offset);
+ assert(!accel->accel.generic.offset);
assert(contains(accel_gough_info, this_idx));
accel->margin_dist = verify_u8(accel_gough_info.at(this_idx).margin);
built_accel[accel] = this_idx;
@@ -1198,11 +1198,11 @@ namespace {
struct raw_gough_report_list {
set<som_report> reports;
- raw_gough_report_list(
- const vector<pair<ReportID, GoughSSAVar *>> &raw_reports,
- const ReportManager &rm, bool do_remap) {
+ raw_gough_report_list(
+ const vector<pair<ReportID, GoughSSAVar *>> &raw_reports,
+ const ReportManager &rm, bool do_remap) {
for (const auto &m : raw_reports) {
- ReportID r = do_remap ? rm.getProgramOffset(m.first) : m.first;
+ ReportID r = do_remap ? rm.getProgramOffset(m.first) : m.first;
u32 impl_slot = INVALID_SLOT;
if (m.second) {
impl_slot = m.second->slot;
@@ -1233,11 +1233,11 @@ unique_ptr<raw_report_info> gough_build_strat::gatherReports(
ReportID *arbReport) const {
DEBUG_PRINTF("gathering reports\n");
- const bool remap_reports = has_managed_reports(rdfa.kind);
-
- auto ri = ue2::make_unique<raw_gough_report_info_impl>();
- map<raw_gough_report_list, u32> rev;
-
+ const bool remap_reports = has_managed_reports(rdfa.kind);
+
+ auto ri = ue2::make_unique<raw_gough_report_info_impl>();
+ map<raw_gough_report_list, u32> rev;
+
assert(!rdfa.states.empty());
vector<GoughVertex> verts(rdfa.states.size());
@@ -1256,7 +1256,7 @@ unique_ptr<raw_report_info> gough_build_strat::gatherReports(
continue;
}
- raw_gough_report_list rrl(gg[v].reports, rm, remap_reports);
+ raw_gough_report_list rrl(gg[v].reports, rm, remap_reports);
DEBUG_PRINTF("non empty r %zu\n", reports.size());
if (rev.find(rrl) != rev.end()) {
reports.push_back(rev[rrl]);
@@ -1275,7 +1275,7 @@ unique_ptr<raw_report_info> gough_build_strat::gatherReports(
}
DEBUG_PRINTF("non empty r eod\n");
- raw_gough_report_list rrl(gg[v].reports_eod, rm, remap_reports);
+ raw_gough_report_list rrl(gg[v].reports_eod, rm, remap_reports);
if (rev.find(rrl) != rev.end()) {
reports_eod.push_back(rev[rrl]);
continue;
diff --git a/contrib/libs/hyperscan/src/nfa/goughcompile.h b/contrib/libs/hyperscan/src/nfa/goughcompile.h
index de29ce23e26..00da1891ec0 100644
--- a/contrib/libs/hyperscan/src/nfa/goughcompile.h
+++ b/contrib/libs/hyperscan/src/nfa/goughcompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,8 +32,8 @@
#include "mcclellancompile.h"
#include "nfa_kind.h"
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
-#include "util/flat_containers.h"
+#include "util/bytecode_ptr.h"
+#include "util/flat_containers.h"
#include "util/order_check.h"
#include <map>
@@ -88,10 +88,10 @@ struct raw_som_dfa : public raw_dfa {
* som */
};
-bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
- const CompileContext &cc,
- const ReportManager &rm);
+bytecode_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
+ const CompileContext &cc,
+ const ReportManager &rm);
} // namespace ue2
-#endif // GOUGHCOMPILE_H
+#endif // GOUGHCOMPILE_H
diff --git a/contrib/libs/hyperscan/src/nfa/goughcompile_internal.h b/contrib/libs/hyperscan/src/nfa/goughcompile_internal.h
index 404b828dca9..e64540523b2 100644
--- a/contrib/libs/hyperscan/src/nfa/goughcompile_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/goughcompile_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,8 +33,8 @@
#include "mcclellancompile.h"
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/flat_containers.h"
-#include "util/noncopyable.h"
+#include "util/flat_containers.h"
+#include "util/noncopyable.h"
#include "util/order_check.h"
#include <map>
@@ -103,13 +103,13 @@ struct GoughSSAVarWithInputs;
struct GoughSSAVarMin;
struct GoughSSAVarJoin;
-struct GoughSSAVar : noncopyable {
+struct GoughSSAVar : noncopyable {
GoughSSAVar(void) : seen(false), slot(INVALID_SLOT) {}
virtual ~GoughSSAVar();
- const flat_set<GoughSSAVar *> &get_inputs() const {
+ const flat_set<GoughSSAVar *> &get_inputs() const {
return inputs;
}
- const flat_set<GoughSSAVarWithInputs *> &get_outputs() const {
+ const flat_set<GoughSSAVarWithInputs *> &get_outputs() const {
return outputs;
}
virtual void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) = 0;
@@ -127,8 +127,8 @@ struct GoughSSAVar : noncopyable {
clear_outputs();
}
protected:
- flat_set<GoughSSAVar *> inputs;
- flat_set<GoughSSAVarWithInputs *> outputs;
+ flat_set<GoughSSAVar *> inputs;
+ flat_set<GoughSSAVarWithInputs *> outputs;
friend struct GoughSSAVarWithInputs;
friend struct GoughSSAVarMin;
friend struct GoughSSAVarJoin;
@@ -184,14 +184,14 @@ struct GoughSSAVarJoin : public GoughSSAVarWithInputs {
void add_input(GoughSSAVar *v, GoughEdge prev);
- const flat_set<GoughEdge> &get_edges_for_input(GoughSSAVar *input) const;
- const std::map<GoughSSAVar *, flat_set<GoughEdge>> &get_input_map() const;
+ const flat_set<GoughEdge> &get_edges_for_input(GoughSSAVar *input) const;
+ const std::map<GoughSSAVar *, flat_set<GoughEdge>> &get_input_map() const;
protected:
void remove_input_raw(GoughSSAVar *v) override;
private:
- std::map<GoughSSAVar *, flat_set<GoughEdge>> input_map;
+ std::map<GoughSSAVar *, flat_set<GoughEdge>> input_map;
};
struct gough_accel_state_info {
diff --git a/contrib/libs/hyperscan/src/nfa/goughcompile_reg.cpp b/contrib/libs/hyperscan/src/nfa/goughcompile_reg.cpp
index df7c74aeb3f..48e515b9ad3 100644
--- a/contrib/libs/hyperscan/src/nfa/goughcompile_reg.cpp
+++ b/contrib/libs/hyperscan/src/nfa/goughcompile_reg.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,7 @@
#include "gough_internal.h"
#include "grey.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/graph_range.h"
#include "util/order_check.h"
@@ -235,7 +235,7 @@ void handle_pending_vertices(GoughSSAVar *def, const GoughGraph &g,
if (contains(aux.containing_v, def)) {
def_v = aux.containing_v.at(def);
}
- unordered_set<GoughVertex> done;
+ unordered_set<GoughVertex> done;
while (!pending_vertex.empty()) {
GoughVertex current = *pending_vertex.begin();
pending_vertex.erase(current);
diff --git a/contrib/libs/hyperscan/src/nfa/lbr.c b/contrib/libs/hyperscan/src/nfa/lbr.c
index 80f5186d017..d403733a65c 100644
--- a/contrib/libs/hyperscan/src/nfa/lbr.c
+++ b/contrib/libs/hyperscan/src/nfa/lbr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -77,7 +77,7 @@ void lbrExpandState(const struct lbr_common *l, u64a offset,
const struct RepeatInfo *info = getRepeatInfo(l);
repeatUnpack(stream_state, info, offset, &lstate->ctrl);
- lstate->lastEscape = 0;
+ lstate->lastEscape = 0;
}
static really_inline
@@ -131,9 +131,9 @@ char repeatIsDead(const struct RepeatInfo *info,
return lstate->ctrl.ring.offset == REPEAT_DEAD;
case REPEAT_TRAILER:
return lstate->ctrl.trailer.offset == REPEAT_DEAD;
- case REPEAT_ALWAYS:
- assert(!"REPEAT_ALWAYS should only be used by Castle");
- return 0;
+ case REPEAT_ALWAYS:
+ assert(!"REPEAT_ALWAYS should only be used by Castle");
+ return 0;
}
assert(0);
@@ -294,7 +294,7 @@ char lbrMatchLoop(const struct lbr_common *l, const u64a begin, const u64a end,
}
DEBUG_PRINTF("firing match at %llu\n", i);
- if (cb(0, i, l->report, ctx) == MO_HALT_MATCHING) {
+ if (cb(0, i, l->report, ctx) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
}
}
@@ -308,7 +308,7 @@ char lbrRevScanDot(UNUSED const struct NFA *nfa, UNUSED const u8 *buf,
UNUSED size_t begin, UNUSED size_t end,
UNUSED size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_DOT);
+ assert(nfa->type == LBR_NFA_DOT);
// Nothing can kill a dot!
return 0;
}
@@ -317,7 +317,7 @@ static really_inline
char lbrRevScanVerm(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end, size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_VERM);
+ assert(nfa->type == LBR_NFA_VERM);
const struct lbr_verm *l = getImplNfa(nfa);
if (begin == end) {
@@ -341,7 +341,7 @@ static really_inline
char lbrRevScanNVerm(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end, size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_NVERM);
+ assert(nfa->type == LBR_NFA_NVERM);
const struct lbr_verm *l = getImplNfa(nfa);
if (begin == end) {
@@ -366,7 +366,7 @@ char lbrRevScanShuf(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end,
size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_SHUF);
+ assert(nfa->type == LBR_NFA_SHUF);
const struct lbr_shuf *l = getImplNfa(nfa);
if (begin == end) {
@@ -390,7 +390,7 @@ char lbrRevScanTruf(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end,
size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_TRUF);
+ assert(nfa->type == LBR_NFA_TRUF);
const struct lbr_truf *l = getImplNfa(nfa);
if (begin == end) {
@@ -414,7 +414,7 @@ char lbrFwdScanDot(UNUSED const struct NFA *nfa, UNUSED const u8 *buf,
UNUSED size_t begin, UNUSED size_t end,
UNUSED size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_DOT);
+ assert(nfa->type == LBR_NFA_DOT);
// Nothing can kill a dot!
return 0;
}
@@ -423,7 +423,7 @@ static really_inline
char lbrFwdScanVerm(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end, size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_VERM);
+ assert(nfa->type == LBR_NFA_VERM);
const struct lbr_verm *l = getImplNfa(nfa);
if (begin == end) {
@@ -447,7 +447,7 @@ static really_inline
char lbrFwdScanNVerm(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end, size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_NVERM);
+ assert(nfa->type == LBR_NFA_NVERM);
const struct lbr_verm *l = getImplNfa(nfa);
if (begin == end) {
@@ -472,7 +472,7 @@ char lbrFwdScanShuf(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end,
size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_SHUF);
+ assert(nfa->type == LBR_NFA_SHUF);
const struct lbr_shuf *l = getImplNfa(nfa);
if (begin == end) {
@@ -496,7 +496,7 @@ char lbrFwdScanTruf(const struct NFA *nfa, const u8 *buf,
size_t begin, size_t end,
size_t *loc) {
assert(begin <= end);
- assert(nfa->type == LBR_NFA_TRUF);
+ assert(nfa->type == LBR_NFA_TRUF);
const struct lbr_truf *l = getImplNfa(nfa);
if (begin == end) {
diff --git a/contrib/libs/hyperscan/src/nfa/lbr.h b/contrib/libs/hyperscan/src/nfa/lbr.h
index 3f89d778508..a9e42046db3 100644
--- a/contrib/libs/hyperscan/src/nfa/lbr.h
+++ b/contrib/libs/hyperscan/src/nfa/lbr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -46,7 +46,7 @@ char nfaExecLbrDot_Q2(const struct NFA *n, struct mq *q, s64a end);
char nfaExecLbrDot_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecLbrDot_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecLbrDot_inAccept(const struct NFA *n, ReportID report, struct mq *q);
-char nfaExecLbrDot_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecLbrDot_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecLbrDot_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecLbrDot_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -67,7 +67,7 @@ char nfaExecLbrVerm_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecLbrVerm_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecLbrVerm_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecLbrVerm_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecLbrVerm_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecLbrVerm_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecLbrVerm_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -88,7 +88,7 @@ char nfaExecLbrNVerm_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecLbrNVerm_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecLbrNVerm_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecLbrNVerm_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecLbrNVerm_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecLbrNVerm_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecLbrNVerm_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -109,7 +109,7 @@ char nfaExecLbrShuf_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecLbrShuf_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecLbrShuf_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecLbrShuf_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecLbrShuf_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecLbrShuf_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecLbrShuf_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -130,7 +130,7 @@ char nfaExecLbrTruf_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecLbrTruf_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecLbrTruf_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecLbrTruf_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecLbrTruf_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecLbrTruf_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecLbrTruf_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
diff --git a/contrib/libs/hyperscan/src/nfa/lbr_common_impl.h b/contrib/libs/hyperscan/src/nfa/lbr_common_impl.h
index 7f309b6b104..5ae35431e43 100644
--- a/contrib/libs/hyperscan/src/nfa/lbr_common_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/lbr_common_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -72,7 +72,7 @@ char JOIN(ENGINE_EXEC_NAME, _reportCurrent)(const struct NFA *nfa,
const struct lbr_common *l = getImplNfa(nfa);
u64a offset = q_cur_offset(q);
DEBUG_PRINTF("firing match %u at %llu\n", l->report, offset);
- q->cb(0, offset, l->report, q->context);
+ q->cb(0, offset, l->report, q->context);
return 0;
}
@@ -94,15 +94,15 @@ char JOIN(ENGINE_EXEC_NAME, _inAccept)(const struct NFA *nfa,
return lbrInAccept(l, lstate, q->streamState, offset, report);
}
-char JOIN(ENGINE_EXEC_NAME, _inAnyAccept)(const struct NFA *nfa, struct mq *q) {
- assert(nfa && q);
- assert(isLbrType(nfa->type));
- DEBUG_PRINTF("entry\n");
-
- const struct lbr_common *l = getImplNfa(nfa);
- return JOIN(ENGINE_EXEC_NAME, _inAccept)(nfa, l->report, q);
-}
-
+char JOIN(ENGINE_EXEC_NAME, _inAnyAccept)(const struct NFA *nfa, struct mq *q) {
+ assert(nfa && q);
+ assert(isLbrType(nfa->type));
+ DEBUG_PRINTF("entry\n");
+
+ const struct lbr_common *l = getImplNfa(nfa);
+ return JOIN(ENGINE_EXEC_NAME, _inAccept)(nfa, l->report, q);
+}
+
char JOIN(ENGINE_EXEC_NAME, _queueInitState)(const struct NFA *nfa,
struct mq *q) {
assert(nfa && q);
@@ -215,7 +215,7 @@ char JOIN(ENGINE_EXEC_NAME, _Q_i)(const struct NFA *nfa, struct mq *q,
if (q->report_current) {
DEBUG_PRINTF("report_current: fire match at %llu\n", q_cur_offset(q));
- int rv = q->cb(0, q_cur_offset(q), l->report, q->context);
+ int rv = q->cb(0, q_cur_offset(q), l->report, q->context);
q->report_current = 0;
if (rv == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
diff --git a/contrib/libs/hyperscan/src/nfa/limex.h b/contrib/libs/hyperscan/src/nfa/limex.h
index 0beb3a807a6..0223604dae7 100644
--- a/contrib/libs/hyperscan/src/nfa/limex.h
+++ b/contrib/libs/hyperscan/src/nfa/limex.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,7 +30,7 @@
#define LIMEX_H
#ifdef __cplusplus
-#include <string>
+#include <string>
extern "C"
{
#endif
@@ -41,7 +41,7 @@ extern "C"
#define GENERATE_NFA_DUMP_DECL(gf_name) \
} /* extern "C" */ \
namespace ue2 { \
- void gf_name##_dump(const struct NFA *nfa, const std::string &base); \
+ void gf_name##_dump(const struct NFA *nfa, const std::string &base); \
} /* namespace ue2 */ \
extern "C" {
@@ -52,34 +52,34 @@ extern "C"
#define GENERATE_NFA_DECL(gf_name) \
char gf_name##_testEOD(const struct NFA *nfa, const char *state, \
const char *streamState, u64a offset, \
- NfaCallback callback, void *context); \
+ NfaCallback callback, void *context); \
char gf_name##_Q(const struct NFA *n, struct mq *q, s64a end); \
char gf_name##_Q2(const struct NFA *n, struct mq *q, s64a end); \
char gf_name##_QR(const struct NFA *n, struct mq *q, ReportID report); \
char gf_name##_reportCurrent(const struct NFA *n, struct mq *q); \
char gf_name##_inAccept(const struct NFA *n, ReportID report, \
struct mq *q); \
- char gf_name##_inAnyAccept(const struct NFA *n, struct mq *q); \
+ char gf_name##_inAnyAccept(const struct NFA *n, struct mq *q); \
char gf_name##_queueInitState(const struct NFA *n, struct mq *q); \
char gf_name##_initCompressedState(const struct NFA *n, u64a offset, \
void *state, u8 key); \
char gf_name##_B_Reverse(const struct NFA *n, u64a offset, const u8 *buf, \
size_t buflen, const u8 *hbuf, size_t hlen, \
- NfaCallback cb, void *context); \
+ NfaCallback cb, void *context); \
char gf_name##_queueCompressState(const struct NFA *nfa, \
const struct mq *q, s64a loc); \
char gf_name##_expandState(const struct NFA *nfa, void *dest, \
const void *src, u64a offset, u8 key); \
- enum nfa_zombie_status gf_name##_zombie_status(const struct NFA *nfa, \
- struct mq *q, s64a loc); \
+ enum nfa_zombie_status gf_name##_zombie_status(const struct NFA *nfa, \
+ struct mq *q, s64a loc); \
GENERATE_NFA_DUMP_DECL(gf_name)
-GENERATE_NFA_DECL(nfaExecLimEx32)
-GENERATE_NFA_DECL(nfaExecLimEx64)
-GENERATE_NFA_DECL(nfaExecLimEx128)
-GENERATE_NFA_DECL(nfaExecLimEx256)
-GENERATE_NFA_DECL(nfaExecLimEx384)
-GENERATE_NFA_DECL(nfaExecLimEx512)
+GENERATE_NFA_DECL(nfaExecLimEx32)
+GENERATE_NFA_DECL(nfaExecLimEx64)
+GENERATE_NFA_DECL(nfaExecLimEx128)
+GENERATE_NFA_DECL(nfaExecLimEx256)
+GENERATE_NFA_DECL(nfaExecLimEx384)
+GENERATE_NFA_DECL(nfaExecLimEx512)
#undef GENERATE_NFA_DECL
#undef GENERATE_NFA_DUMP_DECL
diff --git a/contrib/libs/hyperscan/src/nfa/limex_64.c b/contrib/libs/hyperscan/src/nfa/limex_64.c
index 877891078ba..e8f0880b27a 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_64.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_64.c
@@ -1,73 +1,73 @@
-/*
- * Copyright (c) 2015-2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief LimEx NFA: 128-bit SIMD runtime implementations.
- */
-
-/* Limex64 is unusual on as on 32 bit platforms, at runtime it uses an m128 for
- * state calculations.
- */
-
-//#define DEBUG_INPUT
-//#define DEBUG_EXCEPTIONS
-
-#include "limex.h"
-
-#include "accel.h"
-#include "limex_internal.h"
-#include "nfa_internal.h"
-#include "ue2common.h"
-#include "util/bitutils.h"
-#include "util/simd_utils.h"
-
-// Common code
-#define STATE_ON_STACK
-#define ESTATE_ON_STACK
-
-#include "limex_runtime.h"
-
-#define SIZE 64
-#define ENG_STATE_T u64a
-
-#ifdef ARCH_64_BIT
-#define STATE_T u64a
-#define LOAD_FROM_ENG load_u64a
-#else
-#define STATE_T m128
-#define LOAD_FROM_ENG load_m128_from_u64a
-#endif
-
-#include "limex_exceptional.h"
-
-#include "limex_state_impl.h"
-
-#define INLINE_ATTR really_inline
-#include "limex_common_impl.h"
-
-#include "limex_runtime_impl.h"
+/*
+ * Copyright (c) 2015-2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief LimEx NFA: 128-bit SIMD runtime implementations.
+ */
+
+/* Limex64 is unusual on as on 32 bit platforms, at runtime it uses an m128 for
+ * state calculations.
+ */
+
+//#define DEBUG_INPUT
+//#define DEBUG_EXCEPTIONS
+
+#include "limex.h"
+
+#include "accel.h"
+#include "limex_internal.h"
+#include "nfa_internal.h"
+#include "ue2common.h"
+#include "util/bitutils.h"
+#include "util/simd_utils.h"
+
+// Common code
+#define STATE_ON_STACK
+#define ESTATE_ON_STACK
+
+#include "limex_runtime.h"
+
+#define SIZE 64
+#define ENG_STATE_T u64a
+
+#ifdef ARCH_64_BIT
+#define STATE_T u64a
+#define LOAD_FROM_ENG load_u64a
+#else
+#define STATE_T m128
+#define LOAD_FROM_ENG load_m128_from_u64a
+#endif
+
+#include "limex_exceptional.h"
+
+#include "limex_state_impl.h"
+
+#define INLINE_ATTR really_inline
+#include "limex_common_impl.h"
+
+#include "limex_runtime_impl.h"
diff --git a/contrib/libs/hyperscan/src/nfa/limex_accel.c b/contrib/libs/hyperscan/src/nfa/limex_accel.c
index 407c06208c8..4834b6a5470 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_accel.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_accel.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,13 +35,13 @@
#include "accel.h"
#include "limex_internal.h"
#include "limex_limits.h"
-#include "limex_shuffle.h"
+#include "limex_shuffle.h"
#include "nfa_internal.h"
#include "shufti.h"
#include "truffle.h"
#include "ue2common.h"
#include "vermicelli.h"
-#include "util/arch.h"
+#include "util/arch.h"
#include "util/bitutils.h"
#include "util/simd_utils.h"
@@ -65,7 +65,7 @@ size_t accelScanWrapper(const u8 *accelTable, const union AccelAux *aux,
}
aux = aux + aux_idx;
- const u8 *ptr = run_accel(aux, &input[i], &input[end]);
+ const u8 *ptr = run_accel(aux, &input[i], &input[end]);
assert(ptr >= &input[i]);
size_t j = (size_t)(ptr - input);
DEBUG_PRINTF("accel skipped %zu of %zu chars\n", (j - i), (end - i));
@@ -76,26 +76,26 @@ size_t accelScanWrapper(const u8 *accelTable, const union AccelAux *aux,
size_t doAccel32(u32 s, u32 accel, const u8 *accelTable,
const union AccelAux *aux, const u8 *input, size_t i,
size_t end) {
- u32 idx = pext32(s, accel);
+ u32 idx = pext32(s, accel);
return accelScanWrapper(accelTable, aux, input, idx, i, end);
}
-#ifdef ARCH_64_BIT
-size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
- const union AccelAux *aux, const u8 *input, size_t i,
- size_t end) {
- u32 idx = pext64(s, accel);
- return accelScanWrapper(accelTable, aux, input, idx, i, end);
-}
-#else
-size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
- const union AccelAux *aux, const u8 *input, size_t i,
- size_t end) {
- u32 idx = pext64(movq(s), movq(accel));
- return accelScanWrapper(accelTable, aux, input, idx, i, end);
-}
-#endif
-
+#ifdef ARCH_64_BIT
+size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end) {
+ u32 idx = pext64(s, accel);
+ return accelScanWrapper(accelTable, aux, input, idx, i, end);
+}
+#else
+size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end) {
+ u32 idx = pext64(movq(s), movq(accel));
+ return accelScanWrapper(accelTable, aux, input, idx, i, end);
+}
+#endif
+
size_t doAccel128(const m128 *state, const struct LimExNFA128 *limex,
const u8 *accelTable, const union AccelAux *aux,
const u8 *input, size_t i, size_t end) {
@@ -104,7 +104,7 @@ size_t doAccel128(const m128 *state, const struct LimExNFA128 *limex,
DEBUG_PRINTF("using PSHUFB for 128-bit shuffle\n");
m128 accelPerm = limex->accelPermute;
m128 accelComp = limex->accelCompare;
- idx = packedExtract128(s, accelPerm, accelComp);
+ idx = packedExtract128(s, accelPerm, accelComp);
return accelScanWrapper(accelTable, aux, input, idx, i, end);
}
@@ -116,13 +116,13 @@ size_t doAccel256(const m256 *state, const struct LimExNFA256 *limex,
DEBUG_PRINTF("using PSHUFB for 256-bit shuffle\n");
m256 accelPerm = limex->accelPermute;
m256 accelComp = limex->accelCompare;
-#if !defined(HAVE_AVX2)
- u32 idx1 = packedExtract128(s.lo, accelPerm.lo, accelComp.lo);
- u32 idx2 = packedExtract128(s.hi, accelPerm.hi, accelComp.hi);
- assert((idx1 & idx2) == 0); // should be no shared bits
- idx = idx1 | idx2;
+#if !defined(HAVE_AVX2)
+ u32 idx1 = packedExtract128(s.lo, accelPerm.lo, accelComp.lo);
+ u32 idx2 = packedExtract128(s.hi, accelPerm.hi, accelComp.hi);
+ assert((idx1 & idx2) == 0); // should be no shared bits
+ idx = idx1 | idx2;
#else
- idx = packedExtract256(s, accelPerm, accelComp);
+ idx = packedExtract256(s, accelPerm, accelComp);
#endif
return accelScanWrapper(accelTable, aux, input, idx, i, end);
}
@@ -135,9 +135,9 @@ size_t doAccel384(const m384 *state, const struct LimExNFA384 *limex,
DEBUG_PRINTF("using PSHUFB for 384-bit shuffle\n");
m384 accelPerm = limex->accelPermute;
m384 accelComp = limex->accelCompare;
- u32 idx1 = packedExtract128(s.lo, accelPerm.lo, accelComp.lo);
- u32 idx2 = packedExtract128(s.mid, accelPerm.mid, accelComp.mid);
- u32 idx3 = packedExtract128(s.hi, accelPerm.hi, accelComp.hi);
+ u32 idx1 = packedExtract128(s.lo, accelPerm.lo, accelComp.lo);
+ u32 idx2 = packedExtract128(s.mid, accelPerm.mid, accelComp.mid);
+ u32 idx3 = packedExtract128(s.hi, accelPerm.hi, accelComp.hi);
assert((idx1 & idx2 & idx3) == 0); // should be no shared bits
idx = idx1 | idx2 | idx3;
return accelScanWrapper(accelTable, aux, input, idx, i, end);
@@ -151,20 +151,20 @@ size_t doAccel512(const m512 *state, const struct LimExNFA512 *limex,
DEBUG_PRINTF("using PSHUFB for 512-bit shuffle\n");
m512 accelPerm = limex->accelPermute;
m512 accelComp = limex->accelCompare;
-#if defined(HAVE_AVX512)
- idx = packedExtract512(s, accelPerm, accelComp);
-#elif defined(HAVE_AVX2)
- u32 idx1 = packedExtract256(s.lo, accelPerm.lo, accelComp.lo);
- u32 idx2 = packedExtract256(s.hi, accelPerm.hi, accelComp.hi);
- assert((idx1 & idx2) == 0); // should be no shared bits
- idx = idx1 | idx2;
+#if defined(HAVE_AVX512)
+ idx = packedExtract512(s, accelPerm, accelComp);
+#elif defined(HAVE_AVX2)
+ u32 idx1 = packedExtract256(s.lo, accelPerm.lo, accelComp.lo);
+ u32 idx2 = packedExtract256(s.hi, accelPerm.hi, accelComp.hi);
+ assert((idx1 & idx2) == 0); // should be no shared bits
+ idx = idx1 | idx2;
#else
- u32 idx1 = packedExtract128(s.lo.lo, accelPerm.lo.lo, accelComp.lo.lo);
- u32 idx2 = packedExtract128(s.lo.hi, accelPerm.lo.hi, accelComp.lo.hi);
- u32 idx3 = packedExtract128(s.hi.lo, accelPerm.hi.lo, accelComp.hi.lo);
- u32 idx4 = packedExtract128(s.hi.hi, accelPerm.hi.hi, accelComp.hi.hi);
+ u32 idx1 = packedExtract128(s.lo.lo, accelPerm.lo.lo, accelComp.lo.lo);
+ u32 idx2 = packedExtract128(s.lo.hi, accelPerm.lo.hi, accelComp.lo.hi);
+ u32 idx3 = packedExtract128(s.hi.lo, accelPerm.hi.lo, accelComp.hi.lo);
+ u32 idx4 = packedExtract128(s.hi.hi, accelPerm.hi.hi, accelComp.hi.hi);
assert((idx1 & idx2 & idx3 & idx4) == 0); // should be no shared bits
idx = idx1 | idx2 | idx3 | idx4;
-#endif
+#endif
return accelScanWrapper(accelTable, aux, input, idx, i, end);
}
diff --git a/contrib/libs/hyperscan/src/nfa/limex_accel.h b/contrib/libs/hyperscan/src/nfa/limex_accel.h
index 0150081609c..e5c94e82ad1 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_accel.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_accel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,7 +40,7 @@
#include "util/simd_utils.h" // for m128 etc
union AccelAux;
-struct LimExNFA64;
+struct LimExNFA64;
struct LimExNFA128;
struct LimExNFA256;
struct LimExNFA384;
@@ -50,16 +50,16 @@ size_t doAccel32(u32 s, u32 accel, const u8 *accelTable,
const union AccelAux *aux, const u8 *input, size_t i,
size_t end);
-#ifdef ARCH_64_BIT
-size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
- const union AccelAux *aux, const u8 *input, size_t i,
- size_t end);
-#else
-size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
- const union AccelAux *aux, const u8 *input, size_t i,
- size_t end);
-#endif
-
+#ifdef ARCH_64_BIT
+size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end);
+#else
+size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end);
+#endif
+
size_t doAccel128(const m128 *s, const struct LimExNFA128 *limex,
const u8 *accelTable, const union AccelAux *aux,
const u8 *input, size_t i, size_t end);
diff --git a/contrib/libs/hyperscan/src/nfa/limex_common_impl.h b/contrib/libs/hyperscan/src/nfa/limex_common_impl.h
index 6d72ee464cd..e441945d700 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_common_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_common_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,22 +31,22 @@
/* impl of limex functions which depend only on state size */
-#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG) \
- || !defined(INLINE_ATTR)
-# error Must define SIZE, STATE_T, LOAD_FROM_ENG and INLINE_ATTR in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG) \
+ || !defined(INLINE_ATTR)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG and INLINE_ATTR in includer.
#endif
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
#define TESTEOD_FN JOIN(moNfaTestEod, SIZE)
#define LIMEX_INACCEPT_FN JOIN(limexInAccept, SIZE)
-#define LIMEX_INANYACCEPT_FN JOIN(limexInAnyAccept, SIZE)
+#define LIMEX_INANYACCEPT_FN JOIN(limexInAnyAccept, SIZE)
#define EXPIRE_ESTATE_FN JOIN(limexExpireExtendedState, SIZE)
#define REPORTCURRENT_FN JOIN(moNfaReportCurrent, SIZE)
#define INITIAL_FN JOIN(moNfaInitial, SIZE)
#define TOP_FN JOIN(moNfaTop, SIZE)
#define TOPN_FN JOIN(moNfaTopN, SIZE)
-#define PROCESS_ACCEPTS_IMPL_FN JOIN(moProcessAcceptsImpl, SIZE)
+#define PROCESS_ACCEPTS_IMPL_FN JOIN(moProcessAcceptsImpl, SIZE)
#define PROCESS_ACCEPTS_FN JOIN(moProcessAccepts, SIZE)
#define PROCESS_ACCEPTS_NOSQUASH_FN JOIN(moProcessAcceptsNoSquash, SIZE)
#define CONTEXT_T JOIN(NFAContext, SIZE)
@@ -61,20 +61,20 @@
#define SQUASH_UNTUG_BR_FN JOIN(lazyTug, SIZE)
#define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE)
-#if defined(ARCH_64_BIT) && (SIZE >= 64)
-#define CHUNK_T u64a
-#define FIND_AND_CLEAR_FN findAndClearLSB_64
-#define POPCOUNT_FN popcount64
-#define RANK_IN_MASK_FN rank_in_mask64
-#else
-#define CHUNK_T u32
-#define FIND_AND_CLEAR_FN findAndClearLSB_32
-#define POPCOUNT_FN popcount32
-#define RANK_IN_MASK_FN rank_in_mask32
-#endif
-
-#define NUM_STATE_CHUNKS (sizeof(STATE_T) / sizeof(CHUNK_T))
-
+#if defined(ARCH_64_BIT) && (SIZE >= 64)
+#define CHUNK_T u64a
+#define FIND_AND_CLEAR_FN findAndClearLSB_64
+#define POPCOUNT_FN popcount64
+#define RANK_IN_MASK_FN rank_in_mask64
+#else
+#define CHUNK_T u32
+#define FIND_AND_CLEAR_FN findAndClearLSB_32
+#define POPCOUNT_FN popcount32
+#define RANK_IN_MASK_FN rank_in_mask32
+#endif
+
+#define NUM_STATE_CHUNKS (sizeof(STATE_T) / sizeof(CHUNK_T))
+
static really_inline
void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
const union RepeatControl *repeat_ctrl,
@@ -96,7 +96,7 @@ void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
u32 cyclicState = info->cyclicState;
- if (!TESTBIT_STATE(*accstate, cyclicState)) {
+ if (!TESTBIT_STATE(*accstate, cyclicState)) {
continue;
}
@@ -113,85 +113,85 @@ void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
}
}
-static really_inline
-char PROCESS_ACCEPTS_IMPL_FN(const IMPL_NFA_T *limex, const STATE_T *s,
- STATE_T *squash, const STATE_T *acceptMask,
- const struct NFAAccept *acceptTable, u64a offset,
- NfaCallback callback, void *context) {
+static really_inline
+char PROCESS_ACCEPTS_IMPL_FN(const IMPL_NFA_T *limex, const STATE_T *s,
+ STATE_T *squash, const STATE_T *acceptMask,
+ const struct NFAAccept *acceptTable, u64a offset,
+ NfaCallback callback, void *context) {
assert(s);
assert(limex);
assert(callback);
- const STATE_T accept_mask = *acceptMask;
- STATE_T accepts = AND_STATE(*s, accept_mask);
-
- // Caller must ensure that we have at least one accept state on.
- assert(ISNONZERO_STATE(accepts));
-
- CHUNK_T chunks[NUM_STATE_CHUNKS];
- memcpy(chunks, &accepts, sizeof(accepts));
-
- CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
- memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
-
- u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
- for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
- CHUNK_T chunk = chunks[i];
- while (chunk != 0) {
- u32 bit = FIND_AND_CLEAR_FN(&chunk);
- u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
- u32 idx = local_idx + base_index;
- const struct NFAAccept *a = &acceptTable[idx];
- DEBUG_PRINTF("state %u: firing report list=%u, offset=%llu\n",
- bit + i * (u32)sizeof(chunk) * 8, a->reports, offset);
- int rv = limexRunAccept((const char *)limex, a, callback, context,
- offset);
+ const STATE_T accept_mask = *acceptMask;
+ STATE_T accepts = AND_STATE(*s, accept_mask);
+
+ // Caller must ensure that we have at least one accept state on.
+ assert(ISNONZERO_STATE(accepts));
+
+ CHUNK_T chunks[NUM_STATE_CHUNKS];
+ memcpy(chunks, &accepts, sizeof(accepts));
+
+ CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
+ memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
+
+ u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
+ for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
+ CHUNK_T chunk = chunks[i];
+ while (chunk != 0) {
+ u32 bit = FIND_AND_CLEAR_FN(&chunk);
+ u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
+ u32 idx = local_idx + base_index;
+ const struct NFAAccept *a = &acceptTable[idx];
+ DEBUG_PRINTF("state %u: firing report list=%u, offset=%llu\n",
+ bit + i * (u32)sizeof(chunk) * 8, a->reports, offset);
+ int rv = limexRunAccept((const char *)limex, a, callback, context,
+ offset);
if (unlikely(rv == MO_HALT_MATCHING)) {
return 1;
}
- if (squash != NULL && a->squash != MO_INVALID_IDX) {
- DEBUG_PRINTF("applying squash mask at offset %u\n", a->squash);
- const ENG_STATE_T *sq =
- (const ENG_STATE_T *)((const char *)limex + a->squash);
- *squash = AND_STATE(*squash, LOAD_FROM_ENG(sq));
+ if (squash != NULL && a->squash != MO_INVALID_IDX) {
+ DEBUG_PRINTF("applying squash mask at offset %u\n", a->squash);
+ const ENG_STATE_T *sq =
+ (const ENG_STATE_T *)((const char *)limex + a->squash);
+ *squash = AND_STATE(*squash, LOAD_FROM_ENG(sq));
}
}
- base_index += POPCOUNT_FN(mask_chunks[i]);
+ base_index += POPCOUNT_FN(mask_chunks[i]);
}
return 0;
}
static never_inline
-char PROCESS_ACCEPTS_FN(const IMPL_NFA_T *limex, STATE_T *s,
- const STATE_T *acceptMask,
- const struct NFAAccept *acceptTable, u64a offset,
- NfaCallback callback, void *context) {
- // We have squash masks we might have to apply after firing reports.
- STATE_T squash = ONES_STATE;
- return PROCESS_ACCEPTS_IMPL_FN(limex, s, &squash, acceptMask, acceptTable,
- offset, callback, context);
-
- *s = AND_STATE(*s, squash);
+char PROCESS_ACCEPTS_FN(const IMPL_NFA_T *limex, STATE_T *s,
+ const STATE_T *acceptMask,
+ const struct NFAAccept *acceptTable, u64a offset,
+ NfaCallback callback, void *context) {
+ // We have squash masks we might have to apply after firing reports.
+ STATE_T squash = ONES_STATE;
+ return PROCESS_ACCEPTS_IMPL_FN(limex, s, &squash, acceptMask, acceptTable,
+ offset, callback, context);
+
+ *s = AND_STATE(*s, squash);
+}
+
+static never_inline
+char PROCESS_ACCEPTS_NOSQUASH_FN(const IMPL_NFA_T *limex, const STATE_T *s,
+ const STATE_T *acceptMask,
+ const struct NFAAccept *acceptTable,
+ u64a offset, NfaCallback callback,
+ void *context) {
+ STATE_T *squash = NULL;
+ return PROCESS_ACCEPTS_IMPL_FN(limex, s, squash, acceptMask, acceptTable,
+ offset, callback, context);
}
-static never_inline
-char PROCESS_ACCEPTS_NOSQUASH_FN(const IMPL_NFA_T *limex, const STATE_T *s,
- const STATE_T *acceptMask,
- const struct NFAAccept *acceptTable,
- u64a offset, NfaCallback callback,
- void *context) {
- STATE_T *squash = NULL;
- return PROCESS_ACCEPTS_IMPL_FN(limex, s, squash, acceptMask, acceptTable,
- offset, callback, context);
-}
-
-// Run EOD accepts. Note that repeat_ctrl and repeat_state may be NULL if this
-// LimEx contains no repeat structures.
+// Run EOD accepts. Note that repeat_ctrl and repeat_state may be NULL if this
+// LimEx contains no repeat structures.
static really_inline
char TESTEOD_FN(const IMPL_NFA_T *limex, const STATE_T *s,
const union RepeatControl *repeat_ctrl,
- const char *repeat_state, u64a offset,
+ const char *repeat_state, u64a offset,
NfaCallback callback, void *context) {
assert(limex && s);
@@ -200,16 +200,16 @@ char TESTEOD_FN(const IMPL_NFA_T *limex, const STATE_T *s,
return MO_CONTINUE_MATCHING;
}
- const STATE_T acceptEodMask = LOAD_FROM_ENG(&limex->acceptAtEOD);
- STATE_T foundAccepts = AND_STATE(*s, acceptEodMask);
+ const STATE_T acceptEodMask = LOAD_FROM_ENG(&limex->acceptAtEOD);
+ STATE_T foundAccepts = AND_STATE(*s, acceptEodMask);
- SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state,
- offset + 1 /* EOD 'symbol' */, &foundAccepts);
+ SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state,
+ offset + 1 /* EOD 'symbol' */, &foundAccepts);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
const struct NFAAccept *acceptEodTable = getAcceptEodTable(limex);
- if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptEodMask,
- acceptEodTable, offset, callback,
+ if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptEodMask,
+ acceptEodTable, offset, callback,
context)) {
return MO_HALT_MATCHING;
}
@@ -225,8 +225,8 @@ char REPORTCURRENT_FN(const IMPL_NFA_T *limex, const struct mq *q) {
assert(q->state);
assert(q_cur_type(q) == MQE_START);
- STATE_T s = *(STATE_T *)q->state;
- STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T s = *(STATE_T *)q->state;
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
@@ -235,8 +235,8 @@ char REPORTCURRENT_FN(const IMPL_NFA_T *limex, const struct mq *q) {
const struct NFAAccept *acceptTable = getAcceptTable(limex);
u64a offset = q_cur_offset(q);
- if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptMask,
- acceptTable, offset, q->cb,
+ if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptMask,
+ acceptTable, offset, q->cb,
q->context)) {
return MO_HALT_MATCHING;
}
@@ -247,7 +247,7 @@ char REPORTCURRENT_FN(const IMPL_NFA_T *limex, const struct mq *q) {
static really_inline
STATE_T INITIAL_FN(const IMPL_NFA_T *impl, char onlyDs) {
- return LOAD_FROM_ENG(onlyDs ? &impl->initDS : &impl->init);
+ return LOAD_FROM_ENG(onlyDs ? &impl->initDS : &impl->init);
}
static really_inline
@@ -258,9 +258,9 @@ STATE_T TOP_FN(const IMPL_NFA_T *impl, char onlyDs, STATE_T state) {
static really_inline
STATE_T TOPN_FN(const IMPL_NFA_T *limex, STATE_T state, u32 n) {
assert(n < limex->topCount);
- const ENG_STATE_T *topsptr =
- (const ENG_STATE_T *)((const char *)limex + limex->topOffset);
- STATE_T top = LOAD_FROM_ENG(&topsptr[n]);
+ const ENG_STATE_T *topsptr =
+ (const ENG_STATE_T *)((const char *)limex + limex->topOffset);
+ STATE_T top = LOAD_FROM_ENG(&topsptr[n]);
return OR_STATE(top, state);
}
@@ -276,8 +276,8 @@ void EXPIRE_ESTATE_FN(const IMPL_NFA_T *limex, struct CONTEXT_T *ctx,
DEBUG_PRINTF("expire estate at offset %llu\n", offset);
- const STATE_T cyclics
- = AND_STATE(ctx->s, LOAD_FROM_ENG(&limex->repeatCyclicMask));
+ const STATE_T cyclics
+ = AND_STATE(ctx->s, LOAD_FROM_ENG(&limex->repeatCyclicMask));
if (ISZERO_STATE(cyclics)) {
DEBUG_PRINTF("no cyclic states are on\n");
return;
@@ -287,7 +287,7 @@ void EXPIRE_ESTATE_FN(const IMPL_NFA_T *limex, struct CONTEXT_T *ctx,
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
u32 cyclicState = info->cyclicState;
- if (!TESTBIT_STATE(cyclics, cyclicState)) {
+ if (!TESTBIT_STATE(cyclics, cyclicState)) {
continue;
}
@@ -307,14 +307,14 @@ void EXPIRE_ESTATE_FN(const IMPL_NFA_T *limex, struct CONTEXT_T *ctx,
last_top, repeat->repeatMax);
u64a adj = 0;
/* if the cycle's tugs are active at repeat max, it is still alive */
- if (TESTBIT_STATE(LOAD_FROM_ENG(&limex->accept), cyclicState) ||
- TESTBIT_STATE(LOAD_FROM_ENG(&limex->acceptAtEOD), cyclicState)) {
+ if (TESTBIT_STATE(LOAD_FROM_ENG(&limex->accept), cyclicState) ||
+ TESTBIT_STATE(LOAD_FROM_ENG(&limex->acceptAtEOD), cyclicState)) {
DEBUG_PRINTF("lazy tug possible - may still be inspected\n");
adj = 1;
} else {
- const ENG_STATE_T *tug_mask =
- (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
- if (ISNONZERO_STATE(AND_STATE(ctx->s, LOAD_FROM_ENG(tug_mask)))) {
+ const ENG_STATE_T *tug_mask =
+ (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
+ if (ISNONZERO_STATE(AND_STATE(ctx->s, LOAD_FROM_ENG(tug_mask)))) {
DEBUG_PRINTF("tug possible - may still be inspected\n");
adj = 1;
}
@@ -336,75 +336,75 @@ char LIMEX_INACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
u64a offset, ReportID report) {
assert(limex);
- const STATE_T accept_mask = LOAD_FROM_ENG(&limex->accept);
- STATE_T accepts = AND_STATE(state, accept_mask);
+ const STATE_T accept_mask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T accepts = AND_STATE(state, accept_mask);
// Are we in an accept state?
- if (ISZERO_STATE(accepts)) {
+ if (ISZERO_STATE(accepts)) {
DEBUG_PRINTF("no accept states are on\n");
return 0;
}
- SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accepts);
+ SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accepts);
DEBUG_PRINTF("looking for report %u\n", report);
- const struct NFAAccept *acceptTable = getAcceptTable(limex);
-
- CHUNK_T chunks[NUM_STATE_CHUNKS];
- memcpy(chunks, &accepts, sizeof(accepts));
-
- CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
- memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
-
- u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
- for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
- CHUNK_T chunk = chunks[i];
- while (chunk != 0) {
- u32 bit = FIND_AND_CLEAR_FN(&chunk);
- u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
- u32 idx = local_idx + base_index;
- assert(idx < limex->acceptCount);
- const struct NFAAccept *a = &acceptTable[idx];
- DEBUG_PRINTF("state %u is on, report list at %u\n",
- bit + i * (u32)sizeof(chunk) * 8, a->reports);
-
- if (limexAcceptHasReport((const char *)limex, a, report)) {
- DEBUG_PRINTF("report %u is on\n", report);
- return 1;
- }
+ const struct NFAAccept *acceptTable = getAcceptTable(limex);
+
+ CHUNK_T chunks[NUM_STATE_CHUNKS];
+ memcpy(chunks, &accepts, sizeof(accepts));
+
+ CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
+ memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
+
+ u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
+ for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
+ CHUNK_T chunk = chunks[i];
+ while (chunk != 0) {
+ u32 bit = FIND_AND_CLEAR_FN(&chunk);
+ u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
+ u32 idx = local_idx + base_index;
+ assert(idx < limex->acceptCount);
+ const struct NFAAccept *a = &acceptTable[idx];
+ DEBUG_PRINTF("state %u is on, report list at %u\n",
+ bit + i * (u32)sizeof(chunk) * 8, a->reports);
+
+ if (limexAcceptHasReport((const char *)limex, a, report)) {
+ DEBUG_PRINTF("report %u is on\n", report);
+ return 1;
+ }
}
- base_index += POPCOUNT_FN(mask_chunks[i]);
+ base_index += POPCOUNT_FN(mask_chunks[i]);
}
return 0;
}
-static really_inline
-char LIMEX_INANYACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
- union RepeatControl *repeat_ctrl, char *repeat_state,
- u64a offset) {
- assert(limex);
-
- const STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
- STATE_T accstate = AND_STATE(state, acceptMask);
-
- // Are we in an accept state?
- if (ISZERO_STATE(accstate)) {
- DEBUG_PRINTF("no accept states are on\n");
- return 0;
- }
-
- SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accstate);
-
- return ISNONZERO_STATE(accstate);
-}
-
+static really_inline
+char LIMEX_INANYACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
+ union RepeatControl *repeat_ctrl, char *repeat_state,
+ u64a offset) {
+ assert(limex);
+
+ const STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T accstate = AND_STATE(state, acceptMask);
+
+ // Are we in an accept state?
+ if (ISZERO_STATE(accstate)) {
+ DEBUG_PRINTF("no accept states are on\n");
+ return 0;
+ }
+
+ SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accstate);
+
+ return ISNONZERO_STATE(accstate);
+}
+
#undef TESTEOD_FN
#undef REPORTCURRENT_FN
#undef EXPIRE_ESTATE_FN
#undef LIMEX_INACCEPT_FN
-#undef LIMEX_INANYACCEPT_FN
+#undef LIMEX_INANYACCEPT_FN
#undef INITIAL_FN
#undef TOP_FN
#undef TOPN_FN
@@ -418,14 +418,14 @@ char LIMEX_INANYACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
#undef TESTBIT_STATE
#undef ISNONZERO_STATE
#undef ISZERO_STATE
-#undef PROCESS_ACCEPTS_IMPL_FN
+#undef PROCESS_ACCEPTS_IMPL_FN
#undef PROCESS_ACCEPTS_FN
#undef PROCESS_ACCEPTS_NOSQUASH_FN
#undef SQUASH_UNTUG_BR_FN
#undef GET_NFA_REPEAT_INFO_FN
-#undef CHUNK_T
-#undef FIND_AND_CLEAR_FN
-#undef POPCOUNT_FN
-#undef RANK_IN_MASK_FN
-#undef NUM_STATE_CHUNKS
+#undef CHUNK_T
+#undef FIND_AND_CLEAR_FN
+#undef POPCOUNT_FN
+#undef RANK_IN_MASK_FN
+#undef NUM_STATE_CHUNKS
diff --git a/contrib/libs/hyperscan/src/nfa/limex_compile.cpp b/contrib/libs/hyperscan/src/nfa/limex_compile.cpp
index 16985ec6e6b..9233ae515ef 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_compile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/limex_compile.cpp
@@ -26,11 +26,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Main NFA build code.
*/
-
+
#include "limex_compile.h"
#include "accel.h"
@@ -39,7 +39,7 @@
#include "limex_internal.h"
#include "limex_limits.h"
#include "nfa_build_util.h"
-#include "nfagraph/ng_dominators.h"
+#include "nfagraph/ng_dominators.h"
#include "nfagraph/ng_holder.h"
#include "nfagraph/ng_limex_accel.h"
#include "nfagraph/ng_repeat.h"
@@ -49,16 +49,16 @@
#include "repeatcompile.h"
#include "util/alloc.h"
#include "util/bitutils.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/charreach.h"
#include "util/compile_context.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include "util/order_check.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include "util/verify_types.h"
#include <algorithm>
@@ -69,22 +69,22 @@
#include <map>
#include <set>
#include <vector>
-
+
#include <boost/graph/breadth_first_search.hpp>
-#include <boost/graph/depth_first_search.hpp>
-#include <boost/range/adaptor/map.hpp>
+#include <boost/graph/depth_first_search.hpp>
+#include <boost/range/adaptor/map.hpp>
using namespace std;
-using boost::adaptors::map_values;
+using boost::adaptors::map_values;
namespace ue2 {
-/**
- * \brief Special state index value meaning that the vertex will not
- * participate in an (NFA/DFA/etc) implementation.
- */
-static constexpr u32 NO_STATE = ~0;
-
+/**
+ * \brief Special state index value meaning that the vertex will not
+ * participate in an (NFA/DFA/etc) implementation.
+ */
+static constexpr u32 NO_STATE = ~0;
+
/* Maximum number of states taken as a small NFA */
static constexpr u32 MAX_SMALL_NFA_STATES = 64;
@@ -109,21 +109,21 @@ struct precalcAccel {
u32 double_offset;
};
-struct limex_accel_info {
- unordered_set<NFAVertex> accelerable;
+struct limex_accel_info {
+ unordered_set<NFAVertex> accelerable;
map<NFAStateSet, precalcAccel> precalc;
- unordered_map<NFAVertex, flat_set<NFAVertex>> friends;
- unordered_map<NFAVertex, AccelScheme> accel_map;
+ unordered_map<NFAVertex, flat_set<NFAVertex>> friends;
+ unordered_map<NFAVertex, AccelScheme> accel_map;
};
static
-unordered_map<NFAVertex, NFAStateSet>
-reindexByStateId(const unordered_map<NFAVertex, NFAStateSet> &in,
- const NGHolder &g,
- const unordered_map<NFAVertex, u32> &state_ids,
+unordered_map<NFAVertex, NFAStateSet>
+reindexByStateId(const unordered_map<NFAVertex, NFAStateSet> &in,
+ const NGHolder &g,
+ const unordered_map<NFAVertex, u32> &state_ids,
const u32 num_states) {
- unordered_map<NFAVertex, NFAStateSet> out;
- out.reserve(in.size());
+ unordered_map<NFAVertex, NFAStateSet> out;
+ out.reserve(in.size());
vector<u32> indexToState(num_vertices(g), NO_STATE);
for (const auto &m : state_ids) {
@@ -153,20 +153,20 @@ reindexByStateId(const unordered_map<NFAVertex, NFAStateSet> &in,
struct build_info {
build_info(NGHolder &hi,
- const unordered_map<NFAVertex, u32> &states_in,
+ const unordered_map<NFAVertex, u32> &states_in,
const vector<BoundedRepeatData> &ri,
- const unordered_map<NFAVertex, NFAStateSet> &rsmi,
- const unordered_map<NFAVertex, NFAStateSet> &smi,
- const map<u32, set<NFAVertex>> &ti, const set<NFAVertex> &zi,
- bool dai, bool sci, const CompileContext &cci, u32 nsi)
- : h(hi), state_ids(states_in), repeats(ri), tops(ti), tugs(nsi),
- zombies(zi), do_accel(dai), stateCompression(sci), cc(cci),
+ const unordered_map<NFAVertex, NFAStateSet> &rsmi,
+ const unordered_map<NFAVertex, NFAStateSet> &smi,
+ const map<u32, set<NFAVertex>> &ti, const set<NFAVertex> &zi,
+ bool dai, bool sci, const CompileContext &cci, u32 nsi)
+ : h(hi), state_ids(states_in), repeats(ri), tops(ti), tugs(nsi),
+ zombies(zi), do_accel(dai), stateCompression(sci), cc(cci),
num_states(nsi) {
for (const auto &br : repeats) {
- for (auto v : br.tug_triggers) {
- assert(state_ids.at(v) != NO_STATE);
- tugs.set(state_ids.at(v));
- }
+ for (auto v : br.tug_triggers) {
+ assert(state_ids.at(v) != NO_STATE);
+ tugs.set(state_ids.at(v));
+ }
br_cyclic[br.cyclic] =
BoundedRepeatSummary(br.repeatMin, br.repeatMax);
}
@@ -178,28 +178,28 @@ struct build_info {
}
NGHolder &h;
- const unordered_map<NFAVertex, u32> &state_ids;
+ const unordered_map<NFAVertex, u32> &state_ids;
const vector<BoundedRepeatData> &repeats;
// Squash maps; state sets are indexed by state_id.
- unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
- unordered_map<NFAVertex, NFAStateSet> squashMap;
+ unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
+ unordered_map<NFAVertex, NFAStateSet> squashMap;
- const map<u32, set<NFAVertex>> &tops;
- NFAStateSet tugs;
+ const map<u32, set<NFAVertex>> &tops;
+ NFAStateSet tugs;
map<NFAVertex, BoundedRepeatSummary> br_cyclic;
const set<NFAVertex> &zombies;
bool do_accel;
bool stateCompression;
const CompileContext &cc;
u32 num_states;
- limex_accel_info accel;
+ limex_accel_info accel;
};
-#define LAST_LIMEX_NFA LIMEX_NFA_512
-
+#define LAST_LIMEX_NFA LIMEX_NFA_512
+
// Constants for scoring mechanism
-const int SHIFT_COST = 10; // limex: cost per shift mask
+const int SHIFT_COST = 10; // limex: cost per shift mask
const int EXCEPTION_COST = 4; // limex: per exception
template<NFAEngineType t> struct NFATraits { };
@@ -256,7 +256,7 @@ bool isLimitedTransition(int from, int to, int maxshift) {
// Fill a bit mask
template<class Mask>
-void maskFill(Mask &m, u8 c) {
+void maskFill(Mask &m, u8 c) {
memset(&m, c, sizeof(m));
}
@@ -288,17 +288,17 @@ void maskSetBits(Mask &m, const NFAStateSet &bits) {
}
}
-template<class Mask>
-bool isMaskZero(Mask &m) {
- u8 *m8 = (u8 *)&m;
- for (u32 i = 0; i < sizeof(m); i++) {
- if (m8[i]) {
- return false;
- }
- }
- return true;
-}
-
+template<class Mask>
+bool isMaskZero(Mask &m) {
+ u8 *m8 = (u8 *)&m;
+ for (u32 i = 0; i < sizeof(m); i++) {
+ if (m8[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Sets an entire byte in a mask to the given value
template<class Mask>
void maskSetByte(Mask &m, const unsigned int idx, const char val) {
@@ -374,7 +374,7 @@ void buildReachMapping(const build_info &args, vector<NFAStateSet> &reach,
}
struct AccelBuild {
- AccelBuild() : v(NGHolder::null_vertex()), state(0), offset(0) {}
+ AccelBuild() : v(NGHolder::null_vertex()), state(0), offset(0) {}
NFAVertex v;
u32 state;
u32 offset; // offset correction to apply
@@ -496,7 +496,7 @@ bool allow_wide_accel(const vector<NFAVertex> &vv, const NGHolder &g,
static
void nfaFindAccelSchemes(const NGHolder &g,
const map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
- unordered_map<NFAVertex, AccelScheme> *out) {
+ unordered_map<NFAVertex, AccelScheme> *out) {
vector<CharReach> refined_cr = reduced_cr(g, br_cyclic);
NFAVertex sds_or_proxy = get_sds_or_proxy(g);
@@ -505,7 +505,7 @@ void nfaFindAccelSchemes(const NGHolder &g,
// We want to skip any vertices that don't lead to at least one other
// (self-loops don't count) vertex.
if (!has_proper_successor(v, g)) {
- DEBUG_PRINTF("skipping vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("skipping vertex %zu\n", g[v].index);
continue;
}
@@ -513,7 +513,7 @@ void nfaFindAccelSchemes(const NGHolder &g,
AccelScheme as;
if (nfaCheckAccel(g, v, refined_cr, br_cyclic, &as, allow_wide)) {
- DEBUG_PRINTF("graph vertex %zu is accelerable with offset %u.\n",
+ DEBUG_PRINTF("graph vertex %zu is accelerable with offset %u.\n",
g[v].index, as.offset);
(*out)[v] = as;
}
@@ -521,11 +521,11 @@ void nfaFindAccelSchemes(const NGHolder &g,
}
struct fas_visitor : public boost::default_bfs_visitor {
- fas_visitor(const unordered_map<NFAVertex, AccelScheme> &am_in,
- unordered_map<NFAVertex, AccelScheme> *out_in)
+ fas_visitor(const unordered_map<NFAVertex, AccelScheme> &am_in,
+ unordered_map<NFAVertex, AccelScheme> *out_in)
: accel_map(am_in), out(out_in) {}
- void discover_vertex(NFAVertex v, const NGHolder &) {
+ void discover_vertex(NFAVertex v, const NGHolder &) {
if (accel_map.find(v) != accel_map.end()) {
(*out)[v] = accel_map.find(v)->second;
}
@@ -533,50 +533,50 @@ struct fas_visitor : public boost::default_bfs_visitor {
throw this; /* done */
}
}
- const unordered_map<NFAVertex, AccelScheme> &accel_map;
- unordered_map<NFAVertex, AccelScheme> *out;
+ const unordered_map<NFAVertex, AccelScheme> &accel_map;
+ unordered_map<NFAVertex, AccelScheme> *out;
};
static
-void filterAccelStates(NGHolder &g, const map<u32, set<NFAVertex>> &tops,
- unordered_map<NFAVertex, AccelScheme> *accel_map) {
+void filterAccelStates(NGHolder &g, const map<u32, set<NFAVertex>> &tops,
+ unordered_map<NFAVertex, AccelScheme> *accel_map) {
/* We want the NFA_MAX_ACCEL_STATES best acceleration states, everything
* else should be ditched. We use a simple BFS to choose accel states near
* the start. */
- vector<NFAEdge> tempEdges;
- for (const auto &vv : tops | map_values) {
- for (NFAVertex v : vv) {
- if (!edge(g.start, v, g).second) {
- tempEdges.push_back(add_edge(g.start, v, g).first);
- }
- }
- }
+ vector<NFAEdge> tempEdges;
+ for (const auto &vv : tops | map_values) {
+ for (NFAVertex v : vv) {
+ if (!edge(g.start, v, g).second) {
+ tempEdges.push_back(add_edge(g.start, v, g).first);
+ }
+ }
+ }
// Similarly, connect (start, startDs) if necessary.
if (!edge(g.start, g.startDs, g).second) {
- NFAEdge e = add_edge(g.start, g.startDs, g);
- tempEdges.push_back(e); // Remove edge later.
+ NFAEdge e = add_edge(g.start, g.startDs, g);
+ tempEdges.push_back(e); // Remove edge later.
}
- unordered_map<NFAVertex, AccelScheme> out;
+ unordered_map<NFAVertex, AccelScheme> out;
try {
- boost::breadth_first_search(g, g.start,
- visitor(fas_visitor(*accel_map, &out))
- .color_map(make_small_color_map(g)));
+ boost::breadth_first_search(g, g.start,
+ visitor(fas_visitor(*accel_map, &out))
+ .color_map(make_small_color_map(g)));
} catch (fas_visitor *) {
; /* found max accel_states */
}
- remove_edges(tempEdges, g);
+ remove_edges(tempEdges, g);
assert(out.size() <= NFA_MAX_ACCEL_STATES);
accel_map->swap(out);
}
static
-bool containsBadSubset(const limex_accel_info &accel,
+bool containsBadSubset(const limex_accel_info &accel,
const NFAStateSet &state_set, const u32 effective_sds) {
NFAStateSet subset(state_set.size());
for (size_t j = state_set.find_first(); j != state_set.npos;
@@ -597,28 +597,28 @@ bool containsBadSubset(const limex_accel_info &accel,
}
static
-bool is_too_wide(const AccelScheme &as) {
- return as.cr.count() > MAX_MERGED_ACCEL_STOPS;
-}
-
-static
-void fillAccelInfo(build_info &bi) {
- if (!bi.do_accel) {
- return;
- }
-
- NGHolder &g = bi.h;
- limex_accel_info &accel = bi.accel;
- unordered_map<NFAVertex, AccelScheme> &accel_map = accel.accel_map;
- const map<NFAVertex, BoundedRepeatSummary> &br_cyclic = bi.br_cyclic;
- const unordered_map<NFAVertex, u32> &state_ids = bi.state_ids;
- const u32 num_states = bi.num_states;
-
- nfaFindAccelSchemes(g, br_cyclic, &accel_map);
- filterAccelStates(g, bi.tops, &accel_map);
-
- assert(accel_map.size() <= NFA_MAX_ACCEL_STATES);
-
+bool is_too_wide(const AccelScheme &as) {
+ return as.cr.count() > MAX_MERGED_ACCEL_STOPS;
+}
+
+static
+void fillAccelInfo(build_info &bi) {
+ if (!bi.do_accel) {
+ return;
+ }
+
+ NGHolder &g = bi.h;
+ limex_accel_info &accel = bi.accel;
+ unordered_map<NFAVertex, AccelScheme> &accel_map = accel.accel_map;
+ const map<NFAVertex, BoundedRepeatSummary> &br_cyclic = bi.br_cyclic;
+ const unordered_map<NFAVertex, u32> &state_ids = bi.state_ids;
+ const u32 num_states = bi.num_states;
+
+ nfaFindAccelSchemes(g, br_cyclic, &accel_map);
+ filterAccelStates(g, bi.tops, &accel_map);
+
+ assert(accel_map.size() <= NFA_MAX_ACCEL_STATES);
+
vector<CharReach> refined_cr = reduced_cr(g, br_cyclic);
vector<NFAVertex> astates;
@@ -635,7 +635,7 @@ void fillAccelInfo(build_info &bi) {
/* for each subset of the accel keys need to find an accel scheme */
assert(astates.size() < 32);
- sort(astates.begin(), astates.end());
+ sort(astates.begin(), astates.end());
for (u32 i = 1, i_end = 1U << astates.size(); i < i_end; i++) {
DEBUG_PRINTF("saving info for accel %u\n", i);
@@ -649,7 +649,7 @@ void fillAccelInfo(build_info &bi) {
}
}
- if (containsBadSubset(accel, state_set, effective_sds)) {
+ if (containsBadSubset(accel, state_set, effective_sds)) {
DEBUG_PRINTF("accel %u has bad subset\n", i);
continue; /* if a subset failed to build we would too */
}
@@ -657,27 +657,27 @@ void fillAccelInfo(build_info &bi) {
const bool allow_wide = allow_wide_accel(states, g, sds_or_proxy);
AccelScheme as = nfaFindAccel(g, states, refined_cr, br_cyclic,
- allow_wide, true);
- if (is_too_wide(as)) {
+ allow_wide, true);
+ if (is_too_wide(as)) {
DEBUG_PRINTF("accel %u too wide (%zu, %d)\n", i,
as.cr.count(), MAX_MERGED_ACCEL_STOPS);
continue;
}
- DEBUG_PRINTF("accel %u ok with offset s%u, d%u\n", i, as.offset,
- as.double_offset);
+ DEBUG_PRINTF("accel %u ok with offset s%u, d%u\n", i, as.offset,
+ as.double_offset);
- precalcAccel &pa = accel.precalc[state_set];
+ precalcAccel &pa = accel.precalc[state_set];
pa.single_offset = as.offset;
pa.single_cr = as.cr;
- if (as.double_byte.size() != 0) {
- pa.double_offset = as.double_offset;
- pa.double_lits = as.double_byte;
- pa.double_cr = as.double_cr;
+ if (as.double_byte.size() != 0) {
+ pa.double_offset = as.double_offset;
+ pa.double_lits = as.double_byte;
+ pa.double_cr = as.double_cr;
}
-
- useful |= state_set;
+
+ useful |= state_set;
}
for (const auto &m : accel_map) {
@@ -694,169 +694,169 @@ void fillAccelInfo(build_info &bi) {
state_set.reset();
state_set.set(state_id);
- accel.accelerable.insert(v);
- findAccelFriends(g, v, br_cyclic, offset, &accel.friends[v]);
+ accel.accelerable.insert(v);
+ findAccelFriends(g, v, br_cyclic, offset, &accel.friends[v]);
}
}
-/** The AccelAux structure has large alignment specified, and this makes some
- * compilers do odd things unless we specify a custom allocator. */
-typedef vector<AccelAux, AlignedAllocator<AccelAux, alignof(AccelAux)>>
- AccelAuxVector;
-
-#define IMPOSSIBLE_ACCEL_MASK (~0U)
-
+/** The AccelAux structure has large alignment specified, and this makes some
+ * compilers do odd things unless we specify a custom allocator. */
+typedef vector<AccelAux, AlignedAllocator<AccelAux, alignof(AccelAux)>>
+ AccelAuxVector;
+
+#define IMPOSSIBLE_ACCEL_MASK (~0U)
+
static
-u32 getEffectiveAccelStates(const build_info &args,
- const unordered_map<NFAVertex, NFAVertex> &dom_map,
- u32 active_accel_mask,
- const vector<AccelBuild> &accelStates) {
- /* accelStates is indexed by the acceleration bit index and contains a
- * reference to the original vertex & state_id */
-
- /* Cases to consider:
- *
- * 1: Accel states a and b are on and b can squash a
- * --> we can ignore a. This will result in a no longer being accurately
- * modelled - we may miss escapes turning it off and we may also miss
- * its successors being activated.
- *
- * 2: Accel state b is on but accel state a is off and a is .* and must be
- * seen before b is reached (and would not be covered by (1))
- * --> if a is squashable (or may die unexpectedly) we should continue
- * as is
- * --> if a is not squashable we can treat this as a+b or as a no accel,
- * impossible case
- * --> this case could be extended to handle non dot reaches by
- * effectively creating something similar to squash masks for the
- * reverse graph
- *
- *
- * Other cases:
- *
- * 3: Accel states a and b are on but have incompatible reaches
- * --> we should treat this as an impossible case. Actually, this case
- * is unlikely to arise as we pick states with wide reaches to
- * accelerate so an empty intersection is unlikely.
- *
- * Note: we need to be careful when dealing with accel states corresponding
- * to bounded repeat cyclics - they may 'turn off' based on a max bound and
- * so we may still require on earlier states to be accurately modelled.
- */
- const NGHolder &h = args.h;
-
- /* map from accel_id to mask of accel_ids that it is dominated by */
- vector<u32> dominated_by(accelStates.size());
-
- map<NFAVertex, u32> accel_id_map;
- for (u32 accel_id = 0; accel_id < accelStates.size(); accel_id++) {
- NFAVertex v = accelStates[accel_id].v;
- accel_id_map[v] = accel_id;
- }
-
- /* Note: we want a slightly less strict defn of dominate as skip edges
- * prevent .* 'truly' dominating */
- for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
- u32 accel_id = findAndClearLSB_32(&local_accel_mask);
- assert(accel_id < accelStates.size());
- NFAVertex v = accelStates[accel_id].v;
- while (contains(dom_map, v) && dom_map.at(v)) {
- v = dom_map.at(v);
- if (contains(accel_id_map, v)) {
- dominated_by[accel_id] |= 1U << accel_id_map[v];
- }
- /* TODO: could also look at inv_adj vertices to handle fan-in */
- for (NFAVertex a : adjacent_vertices_range(v, h)) {
- if (a == v || !contains(accel_id_map, a)
- || a == accelStates[accel_id].v /* not likely */) {
- continue;
- }
- if (!is_subset_of(h[v].reports, h[a].reports)) {
- continue;
- }
- auto v_succ = succs(v, h);
- auto a_succ = succs(a, h);
- if (is_subset_of(v_succ, a_succ)) {
- dominated_by[accel_id] |= 1U << accel_id_map[a];
- }
- }
- }
- }
-
- u32 may_turn_off = 0; /* BR with max bound, non-dots, squashed, etc */
- for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
- u32 accel_id = findAndClearLSB_32(&local_accel_mask);
- NFAVertex v = accelStates[accel_id].v;
- u32 state_id = accelStates[accel_id].state;
- assert(contains(args.accel.accelerable, v));
- if (!h[v].char_reach.all()) {
- may_turn_off |= 1U << accel_id;
- continue;
- }
- if (contains(args.br_cyclic, v)
- && args.br_cyclic.at(v).repeatMax != depth::infinity()) {
- may_turn_off |= 1U << accel_id;
- continue;
- }
- for (const auto &s_mask : args.squashMap | map_values) {
- if (!s_mask.test(state_id)) {
- may_turn_off |= 1U << accel_id;
- break;
- }
- }
- for (const auto &s_mask : args.reportSquashMap | map_values) {
- if (!s_mask.test(state_id)) {
- may_turn_off |= 1U << accel_id;
- break;
- }
- }
- }
-
- /* Case 1: */
- u32 ignored = 0;
- for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
- u32 accel_id_b = findAndClearLSB_32(&local_accel_mask);
- NFAVertex v = accelStates[accel_id_b].v;
- if (!contains(args.squashMap, v)) {
- continue;
- }
- assert(!contains(args.br_cyclic, v)
- || args.br_cyclic.at(v).repeatMax == depth::infinity());
- NFAStateSet squashed = args.squashMap.at(v);
- squashed.flip(); /* default sense for mask of survivors */
-
- for (u32 local_accel_mask2 = active_accel_mask; local_accel_mask2; ) {
- u32 accel_id_a = findAndClearLSB_32(&local_accel_mask2);
- if (squashed.test(accelStates[accel_id_a].state)) {
- ignored |= 1U << accel_id_a;
- }
- }
- }
-
- /* Case 2: */
- for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
- u32 accel_id = findAndClearLSB_32(&local_accel_mask);
-
- u32 stuck_dominators = dominated_by[accel_id] & ~may_turn_off;
- if ((stuck_dominators & active_accel_mask) != stuck_dominators) {
- DEBUG_PRINTF("only %08x on, but we require %08x\n",
- active_accel_mask, stuck_dominators);
- return IMPOSSIBLE_ACCEL_MASK;
- }
- }
-
- if (ignored) {
- DEBUG_PRINTF("in %08x, ignoring %08x\n", active_accel_mask, ignored);
- }
-
- return active_accel_mask & ~ignored;
+u32 getEffectiveAccelStates(const build_info &args,
+ const unordered_map<NFAVertex, NFAVertex> &dom_map,
+ u32 active_accel_mask,
+ const vector<AccelBuild> &accelStates) {
+ /* accelStates is indexed by the acceleration bit index and contains a
+ * reference to the original vertex & state_id */
+
+ /* Cases to consider:
+ *
+ * 1: Accel states a and b are on and b can squash a
+ * --> we can ignore a. This will result in a no longer being accurately
+ * modelled - we may miss escapes turning it off and we may also miss
+ * its successors being activated.
+ *
+ * 2: Accel state b is on but accel state a is off and a is .* and must be
+ * seen before b is reached (and would not be covered by (1))
+ * --> if a is squashable (or may die unexpectedly) we should continue
+ * as is
+ * --> if a is not squashable we can treat this as a+b or as a no accel,
+ * impossible case
+ * --> this case could be extended to handle non dot reaches by
+ * effectively creating something similar to squash masks for the
+ * reverse graph
+ *
+ *
+ * Other cases:
+ *
+ * 3: Accel states a and b are on but have incompatible reaches
+ * --> we should treat this as an impossible case. Actually, this case
+ * is unlikely to arise as we pick states with wide reaches to
+ * accelerate so an empty intersection is unlikely.
+ *
+ * Note: we need to be careful when dealing with accel states corresponding
+ * to bounded repeat cyclics - they may 'turn off' based on a max bound and
+ * so we may still require on earlier states to be accurately modelled.
+ */
+ const NGHolder &h = args.h;
+
+ /* map from accel_id to mask of accel_ids that it is dominated by */
+ vector<u32> dominated_by(accelStates.size());
+
+ map<NFAVertex, u32> accel_id_map;
+ for (u32 accel_id = 0; accel_id < accelStates.size(); accel_id++) {
+ NFAVertex v = accelStates[accel_id].v;
+ accel_id_map[v] = accel_id;
+ }
+
+ /* Note: we want a slightly less strict defn of dominate as skip edges
+ * prevent .* 'truly' dominating */
+ for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
+ u32 accel_id = findAndClearLSB_32(&local_accel_mask);
+ assert(accel_id < accelStates.size());
+ NFAVertex v = accelStates[accel_id].v;
+ while (contains(dom_map, v) && dom_map.at(v)) {
+ v = dom_map.at(v);
+ if (contains(accel_id_map, v)) {
+ dominated_by[accel_id] |= 1U << accel_id_map[v];
+ }
+ /* TODO: could also look at inv_adj vertices to handle fan-in */
+ for (NFAVertex a : adjacent_vertices_range(v, h)) {
+ if (a == v || !contains(accel_id_map, a)
+ || a == accelStates[accel_id].v /* not likely */) {
+ continue;
+ }
+ if (!is_subset_of(h[v].reports, h[a].reports)) {
+ continue;
+ }
+ auto v_succ = succs(v, h);
+ auto a_succ = succs(a, h);
+ if (is_subset_of(v_succ, a_succ)) {
+ dominated_by[accel_id] |= 1U << accel_id_map[a];
+ }
+ }
+ }
+ }
+
+ u32 may_turn_off = 0; /* BR with max bound, non-dots, squashed, etc */
+ for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
+ u32 accel_id = findAndClearLSB_32(&local_accel_mask);
+ NFAVertex v = accelStates[accel_id].v;
+ u32 state_id = accelStates[accel_id].state;
+ assert(contains(args.accel.accelerable, v));
+ if (!h[v].char_reach.all()) {
+ may_turn_off |= 1U << accel_id;
+ continue;
+ }
+ if (contains(args.br_cyclic, v)
+ && args.br_cyclic.at(v).repeatMax != depth::infinity()) {
+ may_turn_off |= 1U << accel_id;
+ continue;
+ }
+ for (const auto &s_mask : args.squashMap | map_values) {
+ if (!s_mask.test(state_id)) {
+ may_turn_off |= 1U << accel_id;
+ break;
+ }
+ }
+ for (const auto &s_mask : args.reportSquashMap | map_values) {
+ if (!s_mask.test(state_id)) {
+ may_turn_off |= 1U << accel_id;
+ break;
+ }
+ }
+ }
+
+ /* Case 1: */
+ u32 ignored = 0;
+ for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
+ u32 accel_id_b = findAndClearLSB_32(&local_accel_mask);
+ NFAVertex v = accelStates[accel_id_b].v;
+ if (!contains(args.squashMap, v)) {
+ continue;
+ }
+ assert(!contains(args.br_cyclic, v)
+ || args.br_cyclic.at(v).repeatMax == depth::infinity());
+ NFAStateSet squashed = args.squashMap.at(v);
+ squashed.flip(); /* default sense for mask of survivors */
+
+ for (u32 local_accel_mask2 = active_accel_mask; local_accel_mask2; ) {
+ u32 accel_id_a = findAndClearLSB_32(&local_accel_mask2);
+ if (squashed.test(accelStates[accel_id_a].state)) {
+ ignored |= 1U << accel_id_a;
+ }
+ }
+ }
+
+ /* Case 2: */
+ for (u32 local_accel_mask = active_accel_mask; local_accel_mask; ) {
+ u32 accel_id = findAndClearLSB_32(&local_accel_mask);
+
+ u32 stuck_dominators = dominated_by[accel_id] & ~may_turn_off;
+ if ((stuck_dominators & active_accel_mask) != stuck_dominators) {
+ DEBUG_PRINTF("only %08x on, but we require %08x\n",
+ active_accel_mask, stuck_dominators);
+ return IMPOSSIBLE_ACCEL_MASK;
+ }
+ }
+
+ if (ignored) {
+ DEBUG_PRINTF("in %08x, ignoring %08x\n", active_accel_mask, ignored);
+ }
+
+ return active_accel_mask & ~ignored;
}
static
void buildAccel(const build_info &args, NFAStateSet &accelMask,
NFAStateSet &accelFriendsMask, AccelAuxVector &auxvec,
vector<u8> &accelTable) {
- const limex_accel_info &accel = args.accel;
+ const limex_accel_info &accel = args.accel;
// Init, all zeroes.
accelMask.resize(args.num_states);
@@ -874,8 +874,8 @@ void buildAccel(const build_info &args, NFAStateSet &accelMask,
return;
}
- const auto dom_map = findDominators(args.h);
-
+ const auto dom_map = findDominators(args.h);
+
// We have 2^n different accel entries, one for each possible
// combination of accelerable states.
assert(accelStates.size() < 32);
@@ -885,24 +885,24 @@ void buildAccel(const build_info &args, NFAStateSet &accelMask,
// Set up a unioned AccelBuild for every possible combination of the set
// bits in accelStates.
vector<AccelBuild> accelOuts(accelCount);
- vector<u32> effective_accel_set;
- effective_accel_set.push_back(0); /* empty is effectively empty */
-
+ vector<u32> effective_accel_set;
+ effective_accel_set.push_back(0); /* empty is effectively empty */
+
for (u32 i = 1; i < accelCount; i++) {
- u32 effective_i = getEffectiveAccelStates(args, dom_map, i,
- accelStates);
- effective_accel_set.push_back(effective_i);
-
- if (effective_i == IMPOSSIBLE_ACCEL_MASK) {
- DEBUG_PRINTF("this combination of accel states is not possible\n");
- accelOuts[i].stop1 = CharReach::dot();
- continue;
- }
-
- while (effective_i) {
- u32 base_accel_state = findAndClearLSB_32(&effective_i);
- combineAccel(accelStates[base_accel_state], accelOuts[i]);
- }
+ u32 effective_i = getEffectiveAccelStates(args, dom_map, i,
+ accelStates);
+ effective_accel_set.push_back(effective_i);
+
+ if (effective_i == IMPOSSIBLE_ACCEL_MASK) {
+ DEBUG_PRINTF("this combination of accel states is not possible\n");
+ accelOuts[i].stop1 = CharReach::dot();
+ continue;
+ }
+
+ while (effective_i) {
+ u32 base_accel_state = findAndClearLSB_32(&effective_i);
+ combineAccel(accelStates[base_accel_state], accelOuts[i]);
+ }
minimiseAccel(accelOuts[i]);
}
@@ -921,25 +921,25 @@ void buildAccel(const build_info &args, NFAStateSet &accelMask,
for (u32 i = 1; i < accelCount; i++) {
memset(&aux, 0, sizeof(aux));
- NFAStateSet effective_states(args.num_states);
- u32 effective_i = effective_accel_set[i];
+ NFAStateSet effective_states(args.num_states);
+ u32 effective_i = effective_accel_set[i];
AccelInfo ainfo;
ainfo.double_offset = accelOuts[i].offset;
ainfo.double_stop1 = accelOuts[i].stop1;
ainfo.double_stop2 = accelOuts[i].stop2;
- if (effective_i != IMPOSSIBLE_ACCEL_MASK) {
- while (effective_i) {
- u32 base_accel_id = findAndClearLSB_32(&effective_i);
- effective_states.set(accelStates[base_accel_id].state);
- }
-
- if (contains(accel.precalc, effective_states)) {
- const auto &precalc = accel.precalc.at(effective_states);
- ainfo.single_offset = precalc.single_offset;
- ainfo.single_stops = precalc.single_cr;
- }
+ if (effective_i != IMPOSSIBLE_ACCEL_MASK) {
+ while (effective_i) {
+ u32 base_accel_id = findAndClearLSB_32(&effective_i);
+ effective_states.set(accelStates[base_accel_id].state);
+ }
+
+ if (contains(accel.precalc, effective_states)) {
+ const auto &precalc = accel.precalc.at(effective_states);
+ ainfo.single_offset = precalc.single_offset;
+ ainfo.single_stops = precalc.single_cr;
+ }
}
buildAccelAux(ainfo, &aux);
@@ -981,105 +981,105 @@ void buildAccel(const build_info &args, NFAStateSet &accelMask,
}
static
-u32 addSquashMask(const build_info &args, const NFAVertex &v,
- vector<NFAStateSet> &squash) {
- auto sit = args.reportSquashMap.find(v);
- if (sit == args.reportSquashMap.end()) {
- return MO_INVALID_IDX;
- }
-
- // This state has a squash mask. Paw through the existing vector to
- // see if we've already seen it, otherwise add a new one.
- auto it = find(squash.begin(), squash.end(), sit->second);
- if (it != squash.end()) {
+u32 addSquashMask(const build_info &args, const NFAVertex &v,
+ vector<NFAStateSet> &squash) {
+ auto sit = args.reportSquashMap.find(v);
+ if (sit == args.reportSquashMap.end()) {
+ return MO_INVALID_IDX;
+ }
+
+ // This state has a squash mask. Paw through the existing vector to
+ // see if we've already seen it, otherwise add a new one.
+ auto it = find(squash.begin(), squash.end(), sit->second);
+ if (it != squash.end()) {
return verify_u32(std::distance(squash.begin(), it));
- }
- u32 idx = verify_u32(squash.size());
- squash.push_back(sit->second);
- return idx;
-}
-
-using ReportListCache = ue2_unordered_map<vector<ReportID>, u32>;
-
-static
-u32 addReports(const flat_set<ReportID> &r, vector<ReportID> &reports,
- ReportListCache &reports_cache) {
- assert(!r.empty());
-
- vector<ReportID> my_reports(begin(r), end(r));
- my_reports.push_back(MO_INVALID_IDX); // sentinel
-
- auto cache_it = reports_cache.find(my_reports);
- if (cache_it != end(reports_cache)) {
- u32 offset = cache_it->second;
- DEBUG_PRINTF("reusing cached report list at %u\n", offset);
- return offset;
- }
-
- auto it = search(begin(reports), end(reports), begin(my_reports),
- end(my_reports));
- if (it != end(reports)) {
+ }
+ u32 idx = verify_u32(squash.size());
+ squash.push_back(sit->second);
+ return idx;
+}
+
+using ReportListCache = ue2_unordered_map<vector<ReportID>, u32>;
+
+static
+u32 addReports(const flat_set<ReportID> &r, vector<ReportID> &reports,
+ ReportListCache &reports_cache) {
+ assert(!r.empty());
+
+ vector<ReportID> my_reports(begin(r), end(r));
+ my_reports.push_back(MO_INVALID_IDX); // sentinel
+
+ auto cache_it = reports_cache.find(my_reports);
+ if (cache_it != end(reports_cache)) {
+ u32 offset = cache_it->second;
+ DEBUG_PRINTF("reusing cached report list at %u\n", offset);
+ return offset;
+ }
+
+ auto it = search(begin(reports), end(reports), begin(my_reports),
+ end(my_reports));
+ if (it != end(reports)) {
u32 offset = verify_u32(std::distance(begin(reports), it));
- DEBUG_PRINTF("reusing found report list at %u\n", offset);
- return offset;
- }
-
- u32 offset = verify_u32(reports.size());
- insert(&reports, reports.end(), my_reports);
- reports_cache.emplace(move(my_reports), offset);
- return offset;
-}
-
-static
-void buildAcceptsList(const build_info &args, ReportListCache &reports_cache,
- vector<NFAVertex> &verts, vector<NFAAccept> &accepts,
- vector<ReportID> &reports, vector<NFAStateSet> &squash) {
- if (verts.empty()) {
- return;
- }
-
- DEBUG_PRINTF("building accept lists for %zu states\n", verts.size());
-
- auto cmp_state_id = [&args](NFAVertex a, NFAVertex b) {
- u32 a_state = args.state_ids.at(a);
- u32 b_state = args.state_ids.at(b);
- assert(a_state != b_state || a == b);
- return a_state < b_state;
- };
-
- sort(begin(verts), end(verts), cmp_state_id);
-
+ DEBUG_PRINTF("reusing found report list at %u\n", offset);
+ return offset;
+ }
+
+ u32 offset = verify_u32(reports.size());
+ insert(&reports, reports.end(), my_reports);
+ reports_cache.emplace(move(my_reports), offset);
+ return offset;
+}
+
+static
+void buildAcceptsList(const build_info &args, ReportListCache &reports_cache,
+ vector<NFAVertex> &verts, vector<NFAAccept> &accepts,
+ vector<ReportID> &reports, vector<NFAStateSet> &squash) {
+ if (verts.empty()) {
+ return;
+ }
+
+ DEBUG_PRINTF("building accept lists for %zu states\n", verts.size());
+
+ auto cmp_state_id = [&args](NFAVertex a, NFAVertex b) {
+ u32 a_state = args.state_ids.at(a);
+ u32 b_state = args.state_ids.at(b);
+ assert(a_state != b_state || a == b);
+ return a_state < b_state;
+ };
+
+ sort(begin(verts), end(verts), cmp_state_id);
+
const NGHolder &h = args.h;
- for (const auto &v : verts) {
- DEBUG_PRINTF("state=%u, reports: [%s]\n", args.state_ids.at(v),
- as_string_list(h[v].reports).c_str());
- NFAAccept a;
- memset(&a, 0, sizeof(a));
- assert(!h[v].reports.empty());
- if (h[v].reports.size() == 1) {
- a.single_report = 1;
- a.reports = *h[v].reports.begin();
- } else {
- a.single_report = 0;
- a.reports = addReports(h[v].reports, reports, reports_cache);
- }
- a.squash = addSquashMask(args, v, squash);
- accepts.push_back(move(a));
- }
-}
-
-static
-void buildAccepts(const build_info &args, ReportListCache &reports_cache,
- NFAStateSet &acceptMask, NFAStateSet &acceptEodMask,
- vector<NFAAccept> &accepts, vector<NFAAccept> &acceptsEod,
- vector<ReportID> &reports, vector<NFAStateSet> &squash) {
- const NGHolder &h = args.h;
-
+ for (const auto &v : verts) {
+ DEBUG_PRINTF("state=%u, reports: [%s]\n", args.state_ids.at(v),
+ as_string_list(h[v].reports).c_str());
+ NFAAccept a;
+ memset(&a, 0, sizeof(a));
+ assert(!h[v].reports.empty());
+ if (h[v].reports.size() == 1) {
+ a.single_report = 1;
+ a.reports = *h[v].reports.begin();
+ } else {
+ a.single_report = 0;
+ a.reports = addReports(h[v].reports, reports, reports_cache);
+ }
+ a.squash = addSquashMask(args, v, squash);
+ accepts.push_back(move(a));
+ }
+}
+
+static
+void buildAccepts(const build_info &args, ReportListCache &reports_cache,
+ NFAStateSet &acceptMask, NFAStateSet &acceptEodMask,
+ vector<NFAAccept> &accepts, vector<NFAAccept> &acceptsEod,
+ vector<ReportID> &reports, vector<NFAStateSet> &squash) {
+ const NGHolder &h = args.h;
+
acceptMask.resize(args.num_states);
acceptEodMask.resize(args.num_states);
- vector<NFAVertex> verts_accept, verts_accept_eod;
-
+ vector<NFAVertex> verts_accept, verts_accept_eod;
+
for (auto v : vertices_range(h)) {
u32 state_id = args.state_ids.at(v);
@@ -1089,18 +1089,18 @@ void buildAccepts(const build_info &args, ReportListCache &reports_cache,
if (edge(v, h.accept, h).second) {
acceptMask.set(state_id);
- verts_accept.push_back(v);
+ verts_accept.push_back(v);
} else {
assert(edge(v, h.acceptEod, h).second);
acceptEodMask.set(state_id);
- verts_accept_eod.push_back(v);
+ verts_accept_eod.push_back(v);
}
- }
+ }
- buildAcceptsList(args, reports_cache, verts_accept, accepts, reports,
- squash);
- buildAcceptsList(args, reports_cache, verts_accept_eod, acceptsEod, reports,
- squash);
+ buildAcceptsList(args, reports_cache, verts_accept, accepts, reports,
+ squash);
+ buildAcceptsList(args, reports_cache, verts_accept_eod, acceptsEod, reports,
+ squash);
}
static
@@ -1116,15 +1116,15 @@ void buildTopMasks(const build_info &args, vector<NFAStateSet> &topMasks) {
for (const auto &m : args.tops) {
u32 mask_idx = m.first;
- for (NFAVertex v : m.second) {
- u32 state_id = args.state_ids.at(v);
- DEBUG_PRINTF("state %u is in top mask %u\n", state_id, mask_idx);
+ for (NFAVertex v : m.second) {
+ u32 state_id = args.state_ids.at(v);
+ DEBUG_PRINTF("state %u is in top mask %u\n", state_id, mask_idx);
- assert(mask_idx < numMasks);
- assert(state_id != NO_STATE);
+ assert(mask_idx < numMasks);
+ assert(state_id != NO_STATE);
- topMasks[mask_idx].set(state_id);
- }
+ topMasks[mask_idx].set(state_id);
+ }
}
}
@@ -1136,7 +1136,7 @@ u32 uncompressedStateSize(u32 num_states) {
static
u32 compressedStateSize(const NGHolder &h, const NFAStateSet &maskedStates,
- const unordered_map<NFAVertex, u32> &state_ids) {
+ const unordered_map<NFAVertex, u32> &state_ids) {
// Shrink state requirement to enough to fit the compressed largest reach.
vector<u32> allreach(N_CHARS, 0);
@@ -1207,7 +1207,7 @@ bool hasSquashableInitDs(const build_info &args) {
static
bool hasInitDsStates(const NGHolder &h,
- const unordered_map<NFAVertex, u32> &state_ids) {
+ const unordered_map<NFAVertex, u32> &state_ids) {
if (state_ids.at(h.startDs) != NO_STATE) {
return true;
}
@@ -1236,8 +1236,8 @@ void findMaskedCompressionStates(const build_info &args,
// Suffixes and outfixes can mask out leaf states, which should all be
// accepts. Right now we can only do this when there is nothing in initDs,
// as we switch that on unconditionally in the expand call.
- if (!inspects_states_for_accepts(h)
- && !hasInitDsStates(h, args.state_ids)) {
+ if (!inspects_states_for_accepts(h)
+ && !hasInitDsStates(h, args.state_ids)) {
NFAStateSet nonleaf(args.num_states);
for (const auto &e : edges_range(h)) {
u32 from = args.state_ids.at(source(e, h));
@@ -1375,16 +1375,16 @@ struct ExceptionProto {
};
static
-u32 buildExceptionMap(const build_info &args, ReportListCache &reports_cache,
- const unordered_set<NFAEdge> &exceptional,
- map<ExceptionProto, vector<u32>> &exceptionMap,
- vector<ReportID> &reportList) {
+u32 buildExceptionMap(const build_info &args, ReportListCache &reports_cache,
+ const unordered_set<NFAEdge> &exceptional,
+ map<ExceptionProto, vector<u32>> &exceptionMap,
+ vector<ReportID> &reportList) {
const NGHolder &h = args.h;
const u32 num_states = args.num_states;
- u32 exceptionCount = 0;
+ u32 exceptionCount = 0;
- unordered_map<NFAVertex, u32> pos_trigger;
- unordered_map<NFAVertex, u32> tug_trigger;
+ unordered_map<NFAVertex, u32> pos_trigger;
+ unordered_map<NFAVertex, u32> tug_trigger;
for (u32 i = 0; i < args.repeats.size(); i++) {
const BoundedRepeatData &br = args.repeats[i];
@@ -1414,12 +1414,12 @@ u32 buildExceptionMap(const build_info &args, ReportListCache &reports_cache,
DEBUG_PRINTF("state %u is exceptional due to accept "
"(%zu reports)\n", i, reports.size());
- if (reports.empty()) {
- e.reports_index = MO_INVALID_IDX;
- } else {
- e.reports_index =
- addReports(reports, reportList, reports_cache);
- }
+ if (reports.empty()) {
+ e.reports_index = MO_INVALID_IDX;
+ } else {
+ e.reports_index =
+ addReports(reports, reportList, reports_cache);
+ }
// We may be applying a report squash too.
auto mi = args.reportSquashMap.find(v);
@@ -1511,13 +1511,13 @@ u32 buildExceptionMap(const build_info &args, ReportListCache &reports_cache,
assert(e.succ_states.size() == num_states);
assert(e.squash_states.size() == num_states);
exceptionMap[e].push_back(i);
- exceptionCount++;
+ exceptionCount++;
}
}
- DEBUG_PRINTF("%u exceptions found (%zu unique)\n", exceptionCount,
- exceptionMap.size());
- return exceptionCount;
+ DEBUG_PRINTF("%u exceptions found (%zu unique)\n", exceptionCount,
+ exceptionMap.size());
+ return exceptionCount;
}
static
@@ -1532,164 +1532,164 @@ u32 depth_to_u32(const depth &d) {
return d_val;
}
-static
-bool isExceptionalTransition(u32 from, u32 to, const build_info &args,
- u32 maxShift) {
- if (!isLimitedTransition(from, to, maxShift)) {
- return true;
- }
-
- // All transitions out of a tug trigger are exceptional.
- if (args.tugs.test(from)) {
- return true;
- }
- return false;
-}
-
-static
-u32 findMaxVarShift(const build_info &args, u32 nShifts) {
- const NGHolder &h = args.h;
- u32 shiftMask = 0;
- for (const auto &e : edges_range(h)) {
- u32 from = args.state_ids.at(source(e, h));
- u32 to = args.state_ids.at(target(e, h));
- if (from == NO_STATE || to == NO_STATE) {
- continue;
- }
- if (!isExceptionalTransition(from, to, args, MAX_SHIFT_AMOUNT)) {
- shiftMask |= (1UL << (to - from));
- }
- }
-
- u32 maxVarShift = 0;
- for (u32 shiftCnt = 0; shiftMask != 0 && shiftCnt < nShifts; shiftCnt++) {
- maxVarShift = findAndClearLSB_32(&shiftMask);
- }
-
- return maxVarShift;
-}
-
-static
-int getLimexScore(const build_info &args, u32 nShifts) {
- const NGHolder &h = args.h;
- u32 maxVarShift = nShifts;
- int score = 0;
-
- score += SHIFT_COST * nShifts;
- maxVarShift = findMaxVarShift(args, nShifts);
-
- NFAStateSet exceptionalStates(args.num_states);
- for (const auto &e : edges_range(h)) {
- u32 from = args.state_ids.at(source(e, h));
- u32 to = args.state_ids.at(target(e, h));
- if (from == NO_STATE || to == NO_STATE) {
- continue;
- }
- if (isExceptionalTransition(from, to, args, maxVarShift)) {
- exceptionalStates.set(from);
- }
- }
- score += EXCEPTION_COST * exceptionalStates.count();
- return score;
-}
-
-// This function finds the best shift scheme with highest score
-// Returns number of shifts and score calculated for appropriate scheme
-// Returns zero if no appropriate scheme was found
-static
-u32 findBestNumOfVarShifts(const build_info &args,
- int *bestScoreRet = nullptr) {
- u32 bestNumOfVarShifts = 0;
- int bestScore = INT_MAX;
- for (u32 shiftCount = 1; shiftCount <= MAX_SHIFT_COUNT; shiftCount++) {
- int score = getLimexScore(args, shiftCount);
- if (score < bestScore) {
- bestScore = score;
- bestNumOfVarShifts = shiftCount;
- }
- }
- if (bestScoreRet != nullptr) {
- *bestScoreRet = bestScore;
- }
- return bestNumOfVarShifts;
-}
-
-static
-bool cannotDie(const build_info &args, const set<NFAVertex> &tops) {
- const auto &h = args.h;
-
- // When this top is activated, all of the vertices in 'tops' are switched
- // on. If any of those lead to a graph that cannot die, then this top
- // cannot die.
-
- // For each top, we use a depth-first search to traverse the graph from the
- // top, looking for a cyclic path consisting of vertices of dot reach. If
- // one exists, than the NFA cannot die after this top is triggered.
-
- auto colour_map = make_small_color_map(h);
-
- struct CycleFound {};
- struct CannotDieVisitor : public boost::default_dfs_visitor {
- void back_edge(const NFAEdge &e, const NGHolder &g) const {
- DEBUG_PRINTF("back-edge %zu,%zu\n", g[source(e, g)].index,
- g[target(e, g)].index);
- if (g[target(e, g)].char_reach.all()) {
- assert(g[source(e, g)].char_reach.all());
- throw CycleFound();
- }
- }
- };
-
- try {
- for (const auto &top : tops) {
- DEBUG_PRINTF("checking top vertex %zu\n", h[top].index);
-
- // Constrain the search to the top vertices and any dot vertices it
- // can reach.
- auto term_func = [&](NFAVertex v, const NGHolder &g) {
- if (v == top) {
- return false;
- }
- if (!g[v].char_reach.all()) {
- return true;
- }
- if (contains(args.br_cyclic, v) &&
- args.br_cyclic.at(v).repeatMax != depth::infinity()) {
- // Bounded repeat vertices without inf max can be turned
- // off.
- return true;
- }
- return false;
- };
-
- boost::depth_first_visit(h, top, CannotDieVisitor(), colour_map,
- term_func);
- }
- } catch (const CycleFound &) {
- DEBUG_PRINTF("cycle found\n");
- return true;
- }
-
- return false;
-}
-
-/** \brief True if this NFA cannot ever be in no states at all. */
-static
-bool cannotDie(const build_info &args) {
- const auto &h = args.h;
- const auto &state_ids = args.state_ids;
-
- // If we have a startDs we're actually using, we can't die.
- if (state_ids.at(h.startDs) != NO_STATE) {
- DEBUG_PRINTF("is using startDs\n");
- return true;
- }
-
- return all_of_in(args.tops | map_values, [&](const set<NFAVertex> &verts) {
- return cannotDie(args, verts);
- });
-}
-
+static
+bool isExceptionalTransition(u32 from, u32 to, const build_info &args,
+ u32 maxShift) {
+ if (!isLimitedTransition(from, to, maxShift)) {
+ return true;
+ }
+
+ // All transitions out of a tug trigger are exceptional.
+ if (args.tugs.test(from)) {
+ return true;
+ }
+ return false;
+}
+
+static
+u32 findMaxVarShift(const build_info &args, u32 nShifts) {
+ const NGHolder &h = args.h;
+ u32 shiftMask = 0;
+ for (const auto &e : edges_range(h)) {
+ u32 from = args.state_ids.at(source(e, h));
+ u32 to = args.state_ids.at(target(e, h));
+ if (from == NO_STATE || to == NO_STATE) {
+ continue;
+ }
+ if (!isExceptionalTransition(from, to, args, MAX_SHIFT_AMOUNT)) {
+ shiftMask |= (1UL << (to - from));
+ }
+ }
+
+ u32 maxVarShift = 0;
+ for (u32 shiftCnt = 0; shiftMask != 0 && shiftCnt < nShifts; shiftCnt++) {
+ maxVarShift = findAndClearLSB_32(&shiftMask);
+ }
+
+ return maxVarShift;
+}
+
+static
+int getLimexScore(const build_info &args, u32 nShifts) {
+ const NGHolder &h = args.h;
+ u32 maxVarShift = nShifts;
+ int score = 0;
+
+ score += SHIFT_COST * nShifts;
+ maxVarShift = findMaxVarShift(args, nShifts);
+
+ NFAStateSet exceptionalStates(args.num_states);
+ for (const auto &e : edges_range(h)) {
+ u32 from = args.state_ids.at(source(e, h));
+ u32 to = args.state_ids.at(target(e, h));
+ if (from == NO_STATE || to == NO_STATE) {
+ continue;
+ }
+ if (isExceptionalTransition(from, to, args, maxVarShift)) {
+ exceptionalStates.set(from);
+ }
+ }
+ score += EXCEPTION_COST * exceptionalStates.count();
+ return score;
+}
+
+// This function finds the best shift scheme with highest score
+// Returns number of shifts and score calculated for appropriate scheme
+// Returns zero if no appropriate scheme was found
+static
+u32 findBestNumOfVarShifts(const build_info &args,
+ int *bestScoreRet = nullptr) {
+ u32 bestNumOfVarShifts = 0;
+ int bestScore = INT_MAX;
+ for (u32 shiftCount = 1; shiftCount <= MAX_SHIFT_COUNT; shiftCount++) {
+ int score = getLimexScore(args, shiftCount);
+ if (score < bestScore) {
+ bestScore = score;
+ bestNumOfVarShifts = shiftCount;
+ }
+ }
+ if (bestScoreRet != nullptr) {
+ *bestScoreRet = bestScore;
+ }
+ return bestNumOfVarShifts;
+}
+
+static
+bool cannotDie(const build_info &args, const set<NFAVertex> &tops) {
+ const auto &h = args.h;
+
+ // When this top is activated, all of the vertices in 'tops' are switched
+ // on. If any of those lead to a graph that cannot die, then this top
+ // cannot die.
+
+ // For each top, we use a depth-first search to traverse the graph from the
+ // top, looking for a cyclic path consisting of vertices of dot reach. If
+ // one exists, than the NFA cannot die after this top is triggered.
+
+ auto colour_map = make_small_color_map(h);
+
+ struct CycleFound {};
+ struct CannotDieVisitor : public boost::default_dfs_visitor {
+ void back_edge(const NFAEdge &e, const NGHolder &g) const {
+ DEBUG_PRINTF("back-edge %zu,%zu\n", g[source(e, g)].index,
+ g[target(e, g)].index);
+ if (g[target(e, g)].char_reach.all()) {
+ assert(g[source(e, g)].char_reach.all());
+ throw CycleFound();
+ }
+ }
+ };
+
+ try {
+ for (const auto &top : tops) {
+ DEBUG_PRINTF("checking top vertex %zu\n", h[top].index);
+
+ // Constrain the search to the top vertices and any dot vertices it
+ // can reach.
+ auto term_func = [&](NFAVertex v, const NGHolder &g) {
+ if (v == top) {
+ return false;
+ }
+ if (!g[v].char_reach.all()) {
+ return true;
+ }
+ if (contains(args.br_cyclic, v) &&
+ args.br_cyclic.at(v).repeatMax != depth::infinity()) {
+ // Bounded repeat vertices without inf max can be turned
+ // off.
+ return true;
+ }
+ return false;
+ };
+
+ boost::depth_first_visit(h, top, CannotDieVisitor(), colour_map,
+ term_func);
+ }
+ } catch (const CycleFound &) {
+ DEBUG_PRINTF("cycle found\n");
+ return true;
+ }
+
+ return false;
+}
+
+/** \brief True if this NFA cannot ever be in no states at all. */
+static
+bool cannotDie(const build_info &args) {
+ const auto &h = args.h;
+ const auto &state_ids = args.state_ids;
+
+ // If we have a startDs we're actually using, we can't die.
+ if (state_ids.at(h.startDs) != NO_STATE) {
+ DEBUG_PRINTF("is using startDs\n");
+ return true;
+ }
+
+ return all_of_in(args.tops | map_values, [&](const set<NFAVertex> &verts) {
+ return cannotDie(args, verts);
+ });
+}
+
template<NFAEngineType dtype>
struct Factory {
// typedefs for readability, for types derived from traits
@@ -1713,8 +1713,8 @@ struct Factory {
sizeof(limex->init), stateSize, repeatscratchStateSize,
repeatStreamState);
- size_t scratchStateSize = NFATraits<dtype>::scratch_state_size;
-
+ size_t scratchStateSize = NFATraits<dtype>::scratch_state_size;
+
if (repeatscratchStateSize) {
scratchStateSize
= ROUNDUP_N(scratchStateSize, alignof(RepeatControl));
@@ -1753,8 +1753,8 @@ struct Factory {
static
void buildRepeats(const build_info &args,
- vector<bytecode_ptr<NFARepeatInfo>> &out,
- u32 *scratchStateSize, u32 *streamState) {
+ vector<bytecode_ptr<NFARepeatInfo>> &out,
+ u32 *scratchStateSize, u32 *streamState) {
out.reserve(args.repeats.size());
u32 repeat_idx = 0;
@@ -1765,7 +1765,7 @@ struct Factory {
u32 tableOffset, tugMaskOffset;
size_t len = repeatAllocSize(br, &tableOffset, &tugMaskOffset);
- auto info = make_zeroed_bytecode_ptr<NFARepeatInfo>(len);
+ auto info = make_zeroed_bytecode_ptr<NFARepeatInfo>(len);
char *info_ptr = (char *)info.get();
// Collect state space info.
@@ -1819,7 +1819,7 @@ struct Factory {
*streamState += streamStateLen;
*scratchStateSize += sizeof(RepeatControl);
- out.emplace_back(move(info));
+ out.emplace_back(move(info));
}
}
@@ -1856,19 +1856,19 @@ struct Factory {
assert(cyclic != NO_STATE);
maskSetBit(limex->repeatCyclicMask, cyclic);
}
- /* also include tugs in repeat cyclic mask */
- for (size_t i = args.tugs.find_first(); i != args.tugs.npos;
- i = args.tugs.find_next(i)) {
- maskSetBit(limex->repeatCyclicMask, i);
- }
+ /* also include tugs in repeat cyclic mask */
+ for (size_t i = args.tugs.find_first(); i != args.tugs.npos;
+ i = args.tugs.find_next(i)) {
+ maskSetBit(limex->repeatCyclicMask, i);
+ }
}
static
void writeShiftMasks(const build_info &args, implNFA_t *limex) {
const NGHolder &h = args.h;
- u32 maxShift = findMaxVarShift(args, limex->shiftCount);
- u32 shiftMask = 0;
- int shiftMaskIdx = 0;
+ u32 maxShift = findMaxVarShift(args, limex->shiftCount);
+ u32 shiftMask = 0;
+ int shiftMaskIdx = 0;
for (const auto &e : edges_range(h)) {
u32 from = args.state_ids.at(source(e, h));
@@ -1880,32 +1880,32 @@ struct Factory {
// We check for exceptional transitions here, as we don't want tug
// trigger transitions emitted as limited transitions (even if they
// could be in this model).
- if (!isExceptionalTransition(from, to, args, maxShift)) {
- u32 shift = to - from;
- if ((shiftMask & (1UL << shift)) == 0UL) {
- shiftMask |= (1UL << shift);
- limex->shiftAmount[shiftMaskIdx++] = (u8)shift;
- }
- assert(limex->shiftCount <= MAX_SHIFT_COUNT);
- for (u32 i = 0; i < limex->shiftCount; i++) {
- if (limex->shiftAmount[i] == (u8)shift) {
- maskSetBit(limex->shift[i], from);
- break;
- }
- }
+ if (!isExceptionalTransition(from, to, args, maxShift)) {
+ u32 shift = to - from;
+ if ((shiftMask & (1UL << shift)) == 0UL) {
+ shiftMask |= (1UL << shift);
+ limex->shiftAmount[shiftMaskIdx++] = (u8)shift;
+ }
+ assert(limex->shiftCount <= MAX_SHIFT_COUNT);
+ for (u32 i = 0; i < limex->shiftCount; i++) {
+ if (limex->shiftAmount[i] == (u8)shift) {
+ maskSetBit(limex->shift[i], from);
+ break;
+ }
+ }
+ }
+ }
+ if (maxShift && limex->shiftCount > 1) {
+ for (u32 i = 0; i < limex->shiftCount; i++) {
+ assert(!isMaskZero(limex->shift[i]));
}
}
- if (maxShift && limex->shiftCount > 1) {
- for (u32 i = 0; i < limex->shiftCount; i++) {
- assert(!isMaskZero(limex->shift[i]));
- }
- }
}
static
void findExceptionalTransitions(const build_info &args,
- unordered_set<NFAEdge> &exceptional,
- u32 maxShift) {
+ unordered_set<NFAEdge> &exceptional,
+ u32 maxShift) {
const NGHolder &h = args.h;
for (const auto &e : edges_range(h)) {
@@ -1915,7 +1915,7 @@ struct Factory {
continue;
}
- if (isExceptionalTransition(from, to, args, maxShift)) {
+ if (isExceptionalTransition(from, to, args, maxShift)) {
exceptional.insert(e);
}
}
@@ -1924,41 +1924,41 @@ struct Factory {
static
void writeExceptions(const build_info &args,
const map<ExceptionProto, vector<u32>> &exceptionMap,
- const vector<u32> &repeatOffsets, implNFA_t *limex,
- const u32 exceptionsOffset,
- const u32 reportListOffset) {
+ const vector<u32> &repeatOffsets, implNFA_t *limex,
+ const u32 exceptionsOffset,
+ const u32 reportListOffset) {
DEBUG_PRINTF("exceptionsOffset=%u\n", exceptionsOffset);
exception_t *etable = (exception_t *)((char *)limex + exceptionsOffset);
assert(ISALIGNED(etable));
- map<u32, ExceptionProto> exception_by_state;
+ map<u32, ExceptionProto> exception_by_state;
for (const auto &m : exceptionMap) {
const ExceptionProto &proto = m.first;
const vector<u32> &states = m.second;
- for (u32 i : states) {
- assert(!contains(exception_by_state, i));
- exception_by_state.emplace(i, proto);
- }
- }
-
- u32 ecount = 0;
- for (const auto &m : exception_by_state) {
- const ExceptionProto &proto = m.second;
- u32 state_id = m.first;
- DEBUG_PRINTF("exception %u, triggered by state %u\n", ecount,
- state_id);
-
+ for (u32 i : states) {
+ assert(!contains(exception_by_state, i));
+ exception_by_state.emplace(i, proto);
+ }
+ }
+
+ u32 ecount = 0;
+ for (const auto &m : exception_by_state) {
+ const ExceptionProto &proto = m.second;
+ u32 state_id = m.first;
+ DEBUG_PRINTF("exception %u, triggered by state %u\n", ecount,
+ state_id);
+
// Write the exception entry.
exception_t &e = etable[ecount];
maskSetBits(e.squash, proto.squash_states);
maskSetBits(e.successors, proto.succ_states);
- if (proto.reports_index == MO_INVALID_IDX) {
- e.reports = MO_INVALID_IDX;
- } else {
- e.reports = reportListOffset +
- proto.reports_index * sizeof(ReportID);
- }
+ if (proto.reports_index == MO_INVALID_IDX) {
+ e.reports = MO_INVALID_IDX;
+ } else {
+ e.reports = reportListOffset +
+ proto.reports_index * sizeof(ReportID);
+ }
e.hasSquash = verify_u8(proto.squash);
e.trigger = verify_u8(proto.trigger);
u32 repeat_offset = proto.repeat_index == MO_INVALID_IDX
@@ -1966,10 +1966,10 @@ struct Factory {
: repeatOffsets[proto.repeat_index];
e.repeatOffset = repeat_offset;
- // for the state that can switch it on
- // set this bit in the exception mask
- maskSetBit(limex->exceptionMask, state_id);
-
+ // for the state that can switch it on
+ // set this bit in the exception mask
+ maskSetBit(limex->exceptionMask, state_id);
+
ecount++;
}
@@ -2130,9 +2130,9 @@ struct Factory {
const vector<NFAAccept> &acceptsEod,
const vector<NFAStateSet> &squash, implNFA_t *limex,
const u32 acceptsOffset, const u32 acceptsEodOffset,
- const u32 squashOffset, const u32 reportListOffset) {
- char *limex_base = (char *)limex;
-
+ const u32 squashOffset, const u32 reportListOffset) {
+ char *limex_base = (char *)limex;
+
DEBUG_PRINTF("acceptsOffset=%u, acceptsEodOffset=%u, squashOffset=%u\n",
acceptsOffset, acceptsEodOffset, squashOffset);
@@ -2140,39 +2140,39 @@ struct Factory {
maskSetBits(limex->accept, acceptMask);
maskSetBits(limex->acceptAtEOD, acceptEodMask);
- // Transforms the indices (report list, squash mask) into offsets
- // relative to the base of the limex.
- auto transform_offset_fn = [&](NFAAccept a) {
- if (!a.single_report) {
- a.reports = reportListOffset + a.reports * sizeof(ReportID);
- }
- a.squash = squashOffset + a.squash * sizeof(tableRow_t);
- return a;
- };
-
+ // Transforms the indices (report list, squash mask) into offsets
+ // relative to the base of the limex.
+ auto transform_offset_fn = [&](NFAAccept a) {
+ if (!a.single_report) {
+ a.reports = reportListOffset + a.reports * sizeof(ReportID);
+ }
+ a.squash = squashOffset + a.squash * sizeof(tableRow_t);
+ return a;
+ };
+
// Write accept table.
limex->acceptOffset = acceptsOffset;
limex->acceptCount = verify_u32(accepts.size());
DEBUG_PRINTF("NFA has %zu accepts\n", accepts.size());
- NFAAccept *acceptsTable = (NFAAccept *)(limex_base + acceptsOffset);
+ NFAAccept *acceptsTable = (NFAAccept *)(limex_base + acceptsOffset);
assert(ISALIGNED(acceptsTable));
- transform(accepts.begin(), accepts.end(), acceptsTable,
- transform_offset_fn);
+ transform(accepts.begin(), accepts.end(), acceptsTable,
+ transform_offset_fn);
// Write eod accept table.
limex->acceptEodOffset = acceptsEodOffset;
limex->acceptEodCount = verify_u32(acceptsEod.size());
DEBUG_PRINTF("NFA has %zu EOD accepts\n", acceptsEod.size());
- NFAAccept *acceptsEodTable = (NFAAccept *)(limex_base + acceptsEodOffset);
+ NFAAccept *acceptsEodTable = (NFAAccept *)(limex_base + acceptsEodOffset);
assert(ISALIGNED(acceptsEodTable));
- transform(acceptsEod.begin(), acceptsEod.end(), acceptsEodTable,
- transform_offset_fn);
+ transform(acceptsEod.begin(), acceptsEod.end(), acceptsEodTable,
+ transform_offset_fn);
// Write squash mask table.
limex->squashCount = verify_u32(squash.size());
limex->squashOffset = squashOffset;
DEBUG_PRINTF("NFA has %zu report squash masks\n", squash.size());
- tableRow_t *mask = (tableRow_t *)(limex_base + squashOffset);
+ tableRow_t *mask = (tableRow_t *)(limex_base + squashOffset);
assert(ISALIGNED(mask));
for (size_t i = 0, end = squash.size(); i < end; i++) {
maskSetBits(mask[i], squash[i]);
@@ -2180,7 +2180,7 @@ struct Factory {
}
static
- void writeRepeats(const vector<bytecode_ptr<NFARepeatInfo>> &repeats,
+ void writeRepeats(const vector<bytecode_ptr<NFARepeatInfo>> &repeats,
vector<u32> &repeatOffsets, implNFA_t *limex,
const u32 repeatOffsetsOffset, const u32 repeatOffset) {
const u32 num_repeats = verify_u32(repeats.size());
@@ -2193,9 +2193,9 @@ struct Factory {
for (u32 i = 0; i < num_repeats; i++) {
repeatOffsets[i] = offset;
- assert(repeats[i]);
- memcpy((char *)limex + offset, repeats[i].get(), repeats[i].size());
- offset += repeats[i].size();
+ assert(repeats[i]);
+ memcpy((char *)limex + offset, repeats[i].get(), repeats[i].size());
+ offset += repeats[i].size();
}
// Write repeat offset lookup table.
@@ -2207,48 +2207,48 @@ struct Factory {
}
static
- void writeReportList(const vector<ReportID> &reports, implNFA_t *limex,
- const u32 reportListOffset) {
- DEBUG_PRINTF("reportListOffset=%u\n", reportListOffset);
- assert(ISALIGNED_N((char *)limex + reportListOffset,
+ void writeReportList(const vector<ReportID> &reports, implNFA_t *limex,
+ const u32 reportListOffset) {
+ DEBUG_PRINTF("reportListOffset=%u\n", reportListOffset);
+ assert(ISALIGNED_N((char *)limex + reportListOffset,
alignof(ReportID)));
- copy_bytes((char *)limex + reportListOffset, reports);
+ copy_bytes((char *)limex + reportListOffset, reports);
}
static
- bytecode_ptr<NFA> generateNfa(const build_info &args) {
+ bytecode_ptr<NFA> generateNfa(const build_info &args) {
if (args.num_states > NFATraits<dtype>::maxStates) {
return nullptr;
}
// Build bounded repeat structures.
- vector<bytecode_ptr<NFARepeatInfo>> repeats;
+ vector<bytecode_ptr<NFARepeatInfo>> repeats;
u32 repeats_full_state = 0;
u32 repeats_stream_state = 0;
buildRepeats(args, repeats, &repeats_full_state, &repeats_stream_state);
size_t repeatSize = 0;
for (size_t i = 0; i < repeats.size(); i++) {
- repeatSize += repeats[i].size();
+ repeatSize += repeats[i].size();
}
- // We track report lists that have already been written into the global
- // list in case we can reuse them.
- ReportListCache reports_cache;
+ // We track report lists that have already been written into the global
+ // list in case we can reuse them.
+ ReportListCache reports_cache;
+
+ unordered_set<NFAEdge> exceptional;
+ u32 shiftCount = findBestNumOfVarShifts(args);
+ assert(shiftCount);
+ u32 maxShift = findMaxVarShift(args, shiftCount);
+ findExceptionalTransitions(args, exceptional, maxShift);
+
+ map<ExceptionProto, vector<u32>> exceptionMap;
+ vector<ReportID> reportList;
- unordered_set<NFAEdge> exceptional;
- u32 shiftCount = findBestNumOfVarShifts(args);
- assert(shiftCount);
- u32 maxShift = findMaxVarShift(args, shiftCount);
- findExceptionalTransitions(args, exceptional, maxShift);
+ u32 exceptionCount = buildExceptionMap(args, reports_cache, exceptional,
+ exceptionMap, reportList);
- map<ExceptionProto, vector<u32>> exceptionMap;
- vector<ReportID> reportList;
+ assert(exceptionCount <= args.num_states);
- u32 exceptionCount = buildExceptionMap(args, reports_cache, exceptional,
- exceptionMap, reportList);
-
- assert(exceptionCount <= args.num_states);
-
// Build reach table and character mapping.
vector<NFAStateSet> reach;
vector<u8> reachMap;
@@ -2262,8 +2262,8 @@ struct Factory {
NFAStateSet acceptMask, acceptEodMask;
vector<NFAAccept> accepts, acceptsEod;
vector<NFAStateSet> squash;
- buildAccepts(args, reports_cache, acceptMask, acceptEodMask, accepts,
- acceptsEod, reportList, squash);
+ buildAccepts(args, reports_cache, acceptMask, acceptEodMask, accepts,
+ acceptsEod, reportList, squash);
// Build all our accel info.
NFAStateSet accelMask, accelFriendsMask;
@@ -2302,10 +2302,10 @@ struct Factory {
offset = ROUNDUP_CL(offset);
const u32 exceptionsOffset = offset;
- offset += sizeof(exception_t) * exceptionCount;
+ offset += sizeof(exception_t) * exceptionCount;
- const u32 reportListOffset = offset;
- offset += sizeof(ReportID) * reportList.size();
+ const u32 reportListOffset = offset;
+ offset += sizeof(ReportID) * reportList.size();
const u32 repeatOffsetsOffset = offset;
offset += sizeof(u32) * args.repeats.size();
@@ -2318,7 +2318,7 @@ struct Factory {
size_t nfaSize = sizeof(NFA) + offset;
DEBUG_PRINTF("nfa size %zu\n", nfaSize);
- auto nfa = make_zeroed_bytecode_ptr<NFA>(nfaSize);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(nfaSize);
assert(nfa); // otherwise we would have thrown std::bad_alloc
implNFA_t *limex = (implNFA_t *)getMutableImplNfa(nfa.get());
@@ -2332,21 +2332,21 @@ struct Factory {
limex, accelTableOffset, accelAuxOffset);
writeAccepts(acceptMask, acceptEodMask, accepts, acceptsEod, squash,
- limex, acceptsOffset, acceptsEodOffset, squashOffset,
- reportListOffset);
+ limex, acceptsOffset, acceptsEodOffset, squashOffset,
+ reportListOffset);
- limex->shiftCount = shiftCount;
+ limex->shiftCount = shiftCount;
writeShiftMasks(args, limex);
- if (cannotDie(args)) {
- DEBUG_PRINTF("nfa cannot die\n");
- setLimexFlag(limex, LIMEX_FLAG_CANNOT_DIE);
- }
-
+ if (cannotDie(args)) {
+ DEBUG_PRINTF("nfa cannot die\n");
+ setLimexFlag(limex, LIMEX_FLAG_CANNOT_DIE);
+ }
+
// Determine the state required for our state vector.
findStateSize(args, limex);
- writeReportList(reportList, limex, reportListOffset);
+ writeReportList(reportList, limex, reportListOffset);
// Repeat structures and offset table.
vector<u32> repeatOffsets;
@@ -2354,7 +2354,7 @@ struct Factory {
repeatsOffset);
writeExceptions(args, exceptionMap, repeatOffsets, limex, exceptionsOffset,
- reportListOffset);
+ reportListOffset);
writeLimexMasks(args, limex);
@@ -2393,10 +2393,10 @@ struct Factory {
// We are of the right size, calculate a score based on the number
// of exceptions and the number of shifts used by this LimEx.
- int score;
- u32 shiftCount = findBestNumOfVarShifts(args, &score);
- if (shiftCount == 0) {
- return -1;
+ int score;
+ u32 shiftCount = findBestNumOfVarShifts(args, &score);
+ if (shiftCount == 0) {
+ return -1;
}
return score;
}
@@ -2404,7 +2404,7 @@ struct Factory {
template<NFAEngineType dtype>
struct generateNfa {
- static bytecode_ptr<NFA> call(const build_info &args) {
+ static bytecode_ptr<NFA> call(const build_info &args) {
return Factory<dtype>::generateNfa(args);
}
};
@@ -2416,40 +2416,40 @@ struct scoreNfa {
}
};
-#define MAKE_LIMEX_TRAITS(mlt_size) \
- template<> struct NFATraits<LIMEX_NFA_##mlt_size> { \
- typedef LimExNFA##mlt_size implNFA_t; \
- typedef u_##mlt_size tableRow_t; \
- typedef NFAException##mlt_size exception_t; \
- static const size_t maxStates = mlt_size; \
- static const size_t scratch_state_size = mlt_size == 64 ? sizeof(m128) \
- : sizeof(tableRow_t); \
- };
-
-MAKE_LIMEX_TRAITS(32)
-MAKE_LIMEX_TRAITS(64)
-MAKE_LIMEX_TRAITS(128)
-MAKE_LIMEX_TRAITS(256)
-MAKE_LIMEX_TRAITS(384)
-MAKE_LIMEX_TRAITS(512)
+#define MAKE_LIMEX_TRAITS(mlt_size) \
+ template<> struct NFATraits<LIMEX_NFA_##mlt_size> { \
+ typedef LimExNFA##mlt_size implNFA_t; \
+ typedef u_##mlt_size tableRow_t; \
+ typedef NFAException##mlt_size exception_t; \
+ static const size_t maxStates = mlt_size; \
+ static const size_t scratch_state_size = mlt_size == 64 ? sizeof(m128) \
+ : sizeof(tableRow_t); \
+ };
+
+MAKE_LIMEX_TRAITS(32)
+MAKE_LIMEX_TRAITS(64)
+MAKE_LIMEX_TRAITS(128)
+MAKE_LIMEX_TRAITS(256)
+MAKE_LIMEX_TRAITS(384)
+MAKE_LIMEX_TRAITS(512)
} // namespace
#ifndef NDEBUG
// Some sanity tests, called by an assertion in generate().
static UNUSED
-bool isSane(const NGHolder &h, const map<u32, set<NFAVertex>> &tops,
- const unordered_map<NFAVertex, u32> &state_ids,
+bool isSane(const NGHolder &h, const map<u32, set<NFAVertex>> &tops,
+ const unordered_map<NFAVertex, u32> &state_ids,
u32 num_states) {
- unordered_set<u32> seen;
- unordered_set<NFAVertex> top_starts;
- for (const auto &vv : tops | map_values) {
- insert(&top_starts, vv);
+ unordered_set<u32> seen;
+ unordered_set<NFAVertex> top_starts;
+ for (const auto &vv : tops | map_values) {
+ insert(&top_starts, vv);
}
for (auto v : vertices_range(h)) {
if (!contains(state_ids, v)) {
- DEBUG_PRINTF("no entry for vertex %zu in state map\n", h[v].index);
+ DEBUG_PRINTF("no entry for vertex %zu in state map\n", h[v].index);
return false;
}
const u32 i = state_ids.at(v);
@@ -2457,7 +2457,7 @@ bool isSane(const NGHolder &h, const map<u32, set<NFAVertex>> &tops,
continue;
}
- DEBUG_PRINTF("checking vertex %zu (state %u)\n", h[v].index, i);
+ DEBUG_PRINTF("checking vertex %zu (state %u)\n", h[v].index, i);
if (i >= num_states || contains(seen, i)) {
DEBUG_PRINTF("vertex %u/%u has invalid state\n", i, num_states);
@@ -2467,7 +2467,7 @@ bool isSane(const NGHolder &h, const map<u32, set<NFAVertex>> &tops,
// All our states should be reachable and have a state assigned.
if (h[v].char_reach.none()) {
- DEBUG_PRINTF("vertex %zu has empty reachability\n", h[v].index);
+ DEBUG_PRINTF("vertex %zu has empty reachability\n", h[v].index);
return false;
}
@@ -2475,7 +2475,7 @@ bool isSane(const NGHolder &h, const map<u32, set<NFAVertex>> &tops,
// must have at least one predecessor that is not itself.
if (v != h.start && v != h.startDs && !contains(top_starts, v)
&& !proper_in_degree(v, h)) {
- DEBUG_PRINTF("vertex %zu has no pred\n", h[v].index);
+ DEBUG_PRINTF("vertex %zu has no pred\n", h[v].index);
return false;
}
}
@@ -2551,7 +2551,7 @@ bool isFast(const build_info &args) {
}
static
-u32 max_state(const unordered_map<NFAVertex, u32> &state_ids) {
+u32 max_state(const unordered_map<NFAVertex, u32> &state_ids) {
u32 rv = 0;
for (const auto &m : state_ids) {
DEBUG_PRINTF("state %u\n", m.second);
@@ -2563,15 +2563,15 @@ u32 max_state(const unordered_map<NFAVertex, u32> &state_ids) {
return rv;
}
-bytecode_ptr<NFA> generate(NGHolder &h,
- const unordered_map<NFAVertex, u32> &states,
- const vector<BoundedRepeatData> &repeats,
- const unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
- const unordered_map<NFAVertex, NFAStateSet> &squashMap,
- const map<u32, set<NFAVertex>> &tops,
- const set<NFAVertex> &zombies, bool do_accel,
+bytecode_ptr<NFA> generate(NGHolder &h,
+ const unordered_map<NFAVertex, u32> &states,
+ const vector<BoundedRepeatData> &repeats,
+ const unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
+ const unordered_map<NFAVertex, NFAStateSet> &squashMap,
+ const map<u32, set<NFAVertex>> &tops,
+ const set<NFAVertex> &zombies, bool do_accel,
bool stateCompression, bool &fast, u32 hint,
- const CompileContext &cc) {
+ const CompileContext &cc) {
const u32 num_states = max_state(states) + 1;
DEBUG_PRINTF("total states: %u\n", num_states);
@@ -2594,18 +2594,18 @@ bytecode_ptr<NFA> generate(NGHolder &h,
// Acceleration analysis.
fillAccelInfo(arg);
- vector<pair<int, NFAEngineType>> scores;
+ vector<pair<int, NFAEngineType>> scores;
if (hint != INVALID_NFA) {
// The caller has told us what to (attempt to) build.
- scores.emplace_back(0, (NFAEngineType)hint);
+ scores.emplace_back(0, (NFAEngineType)hint);
} else {
for (size_t i = 0; i <= LAST_LIMEX_NFA; i++) {
NFAEngineType ntype = (NFAEngineType)i;
int score = DISPATCH_BY_LIMEX_TYPE(ntype, scoreNfa, arg);
if (score >= 0) {
DEBUG_PRINTF("%s scores %d\n", nfa_type_name(ntype), score);
- scores.emplace_back(score, ntype);
+ scores.emplace_back(score, ntype);
}
}
}
@@ -2615,39 +2615,39 @@ bytecode_ptr<NFA> generate(NGHolder &h,
return nullptr;
}
- // Sort acceptable models in priority order, lowest score first.
- sort(scores.begin(), scores.end());
+ // Sort acceptable models in priority order, lowest score first.
+ sort(scores.begin(), scores.end());
- for (const auto &elem : scores) {
- assert(elem.first >= 0);
- NFAEngineType limex_model = elem.second;
- auto nfa = DISPATCH_BY_LIMEX_TYPE(limex_model, generateNfa, arg);
- if (nfa) {
- DEBUG_PRINTF("successful build with NFA engine: %s\n",
- nfa_type_name(limex_model));
+ for (const auto &elem : scores) {
+ assert(elem.first >= 0);
+ NFAEngineType limex_model = elem.second;
+ auto nfa = DISPATCH_BY_LIMEX_TYPE(limex_model, generateNfa, arg);
+ if (nfa) {
+ DEBUG_PRINTF("successful build with NFA engine: %s\n",
+ nfa_type_name(limex_model));
fast = isFast(arg);
- return nfa;
- }
+ return nfa;
+ }
}
- DEBUG_PRINTF("NFA build failed.\n");
- return nullptr;
+ DEBUG_PRINTF("NFA build failed.\n");
+ return nullptr;
}
u32 countAccelStates(NGHolder &h,
- const unordered_map<NFAVertex, u32> &states,
- const vector<BoundedRepeatData> &repeats,
- const unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
- const unordered_map<NFAVertex, NFAStateSet> &squashMap,
- const map<u32, set<NFAVertex>> &tops,
- const set<NFAVertex> &zombies,
- const CompileContext &cc) {
+ const unordered_map<NFAVertex, u32> &states,
+ const vector<BoundedRepeatData> &repeats,
+ const unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
+ const unordered_map<NFAVertex, NFAStateSet> &squashMap,
+ const map<u32, set<NFAVertex>> &tops,
+ const set<NFAVertex> &zombies,
+ const CompileContext &cc) {
const u32 num_states = max_state(states) + 1;
DEBUG_PRINTF("total states: %u\n", num_states);
if (!cc.grey.allowLimExNFA) {
DEBUG_PRINTF("limex not allowed\n");
- return 0;
+ return 0;
}
// Sanity check the input data.
@@ -2661,11 +2661,11 @@ u32 countAccelStates(NGHolder &h,
do_accel, state_compression, cc, num_states);
// Acceleration analysis.
- nfaFindAccelSchemes(bi.h, bi.br_cyclic, &bi.accel.accel_map);
+ nfaFindAccelSchemes(bi.h, bi.br_cyclic, &bi.accel.accel_map);
- u32 num_accel = verify_u32(bi.accel.accel_map.size());
+ u32 num_accel = verify_u32(bi.accel.accel_map.size());
DEBUG_PRINTF("found %u accel states\n", num_accel);
- return num_accel;
+ return num_accel;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/limex_compile.h b/contrib/libs/hyperscan/src/nfa/limex_compile.h
index e657d6f44e3..4afdcdb3e41 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_compile.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_compile.h
@@ -26,23 +26,23 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Main NFA build code.
*/
#ifndef LIMEX_COMPILE_H
#define LIMEX_COMPILE_H
-#include "nfagraph/ng_holder.h"
-#include "nfagraph/ng_squash.h" // for NFAStateSet
-#include "ue2common.h"
-#include "util/bytecode_ptr.h"
-
-#include <set>
+#include "nfagraph/ng_holder.h"
+#include "nfagraph/ng_squash.h" // for NFAStateSet
+#include "ue2common.h"
+#include "util/bytecode_ptr.h"
+
+#include <set>
#include <map>
#include <memory>
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
struct NFA;
@@ -52,8 +52,8 @@ namespace ue2 {
struct BoundedRepeatData;
struct CompileContext;
-/**
- * \brief Construct a LimEx NFA from an NGHolder.
+/**
+ * \brief Construct a LimEx NFA from an NGHolder.
*
* \param g Input NFA graph. Must have state IDs assigned.
* \param repeats Bounded repeat information, if any.
@@ -69,33 +69,33 @@ struct CompileContext;
* \return a built NFA, or nullptr if no NFA could be constructed for this
* graph.
*/
-bytecode_ptr<NFA> generate(NGHolder &g,
- const std::unordered_map<NFAVertex, u32> &states,
- const std::vector<BoundedRepeatData> &repeats,
- const std::unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
- const std::unordered_map<NFAVertex, NFAStateSet> &squashMap,
- const std::map<u32, std::set<NFAVertex>> &tops,
- const std::set<NFAVertex> &zombies,
- bool do_accel,
- bool stateCompression,
+bytecode_ptr<NFA> generate(NGHolder &g,
+ const std::unordered_map<NFAVertex, u32> &states,
+ const std::vector<BoundedRepeatData> &repeats,
+ const std::unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
+ const std::unordered_map<NFAVertex, NFAStateSet> &squashMap,
+ const std::map<u32, std::set<NFAVertex>> &tops,
+ const std::set<NFAVertex> &zombies,
+ bool do_accel,
+ bool stateCompression,
bool &fast,
- u32 hint,
- const CompileContext &cc);
+ u32 hint,
+ const CompileContext &cc);
/**
- * \brief For a given graph, count the number of accelerable states it has.
+ * \brief For a given graph, count the number of accelerable states it has.
*
- * Note that this number may be greater than the number that are actually
- * implementable.
+ * Note that this number may be greater than the number that are actually
+ * implementable.
*/
u32 countAccelStates(NGHolder &h,
- const std::unordered_map<NFAVertex, u32> &states,
- const std::vector<BoundedRepeatData> &repeats,
- const std::unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
- const std::unordered_map<NFAVertex, NFAStateSet> &squashMap,
- const std::map<u32, std::set<NFAVertex>> &tops,
- const std::set<NFAVertex> &zombies,
- const CompileContext &cc);
+ const std::unordered_map<NFAVertex, u32> &states,
+ const std::vector<BoundedRepeatData> &repeats,
+ const std::unordered_map<NFAVertex, NFAStateSet> &reportSquashMap,
+ const std::unordered_map<NFAVertex, NFAStateSet> &squashMap,
+ const std::map<u32, std::set<NFAVertex>> &tops,
+ const std::set<NFAVertex> &zombies,
+ const CompileContext &cc);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/limex_context.h b/contrib/libs/hyperscan/src/nfa/limex_context.h
index 25972bcd13a..60d2087935b 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_context.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_context.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,16 +39,16 @@
// Runtime context structures.
-/* Note: The size of the context structures may vary from platform to platform
- * (notably, for the Limex64 structure). As a result, information based on the
- * size and other detail of these structures should not be written into the
- * bytecode -- really, the details of the structure should not be accessed by
- * the ue2 compile side at all.
- */
-#ifdef __cplusplus
-#error ue2 runtime only file
-#endif
-
+/* Note: The size of the context structures may vary from platform to platform
+ * (notably, for the Limex64 structure). As a result, information based on the
+ * size and other detail of these structures should not be written into the
+ * bytecode -- really, the details of the structure should not be accessed by
+ * the ue2 compile side at all.
+ */
+#ifdef __cplusplus
+#error ue2 runtime only file
+#endif
+
/* cached_estate/esucc etc...
*
* If the exception state matches the cached_estate we will apply
@@ -76,11 +76,11 @@ struct ALIGN_CL_DIRECTIVE NFAContext##nsize { \
};
GEN_CONTEXT_STRUCT(32, u32)
-#ifdef ARCH_64_BIT
-GEN_CONTEXT_STRUCT(64, u64a)
-#else
-GEN_CONTEXT_STRUCT(64, m128)
-#endif
+#ifdef ARCH_64_BIT
+GEN_CONTEXT_STRUCT(64, u64a)
+#else
+GEN_CONTEXT_STRUCT(64, m128)
+#endif
GEN_CONTEXT_STRUCT(128, m128)
GEN_CONTEXT_STRUCT(256, m256)
GEN_CONTEXT_STRUCT(384, m384)
diff --git a/contrib/libs/hyperscan/src/nfa/limex_exceptional.h b/contrib/libs/hyperscan/src/nfa/limex_exceptional.h
index fce8b2ca983..6c7335f1b98 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_exceptional.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_exceptional.h
@@ -32,8 +32,8 @@
* X-macro generic impl, included into the various LimEx model implementations.
*/
-#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
-# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
#include "config.h"
@@ -59,7 +59,7 @@
#define ESTATE_ARG STATE_T estate
#else
#define ESTATE_ARG const STATE_T *estatep
-#define estate (*estatep)
+#define estate (*estatep)
#endif
#ifdef STATE_ON_STACK
@@ -79,13 +79,13 @@
#ifdef ARCH_64_BIT
#define CHUNK_T u64a
#define FIND_AND_CLEAR_FN findAndClearLSB_64
-#define POPCOUNT_FN popcount64
-#define RANK_IN_MASK_FN rank_in_mask64
+#define POPCOUNT_FN popcount64
+#define RANK_IN_MASK_FN rank_in_mask64
#else
#define CHUNK_T u32
#define FIND_AND_CLEAR_FN findAndClearLSB_32
-#define POPCOUNT_FN popcount32
-#define RANK_IN_MASK_FN rank_in_mask32
+#define POPCOUNT_FN popcount32
+#define RANK_IN_MASK_FN rank_in_mask32
#endif
/** \brief Process a single exception. Returns 1 if exception handling should
@@ -132,7 +132,7 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
char *repeat_state = ctx->repeat_state + info->stateOffset;
if (e->trigger == LIMEX_TRIGGER_POS) {
- char cyclic_on = TESTBIT_STATE(*STATE_ARG_P, info->cyclicState);
+ char cyclic_on = TESTBIT_STATE(*STATE_ARG_P, info->cyclicState);
processPosTrigger(repeat, repeat_ctrl, repeat_state, offset,
cyclic_on);
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
@@ -148,7 +148,7 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
DEBUG_PRINTF("stale history, squashing cyclic state\n");
assert(e->hasSquash == LIMEX_SQUASH_TUG);
- *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
+ *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
return 1; // continue
} else if (rv == TRIGGER_SUCCESS_CACHE) {
new_cache->br = 1;
@@ -162,8 +162,8 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
// Some exceptions fire accepts.
if (e->reports != MO_INVALID_IDX) {
if (flags & CALLBACK_OUTPUT) {
- const ReportID *reports =
- (const ReportID *)((const char *)limex + e->reports);
+ const ReportID *reports =
+ (const ReportID *)((const char *)limex + e->reports);
if (unlikely(limexRunReports(reports, ctx->callback,
ctx->context, offset)
== MO_HALT_MATCHING)) {
@@ -187,16 +187,16 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
// Most exceptions have a set of successors to switch on. `local_succ' is
// ORed into `succ' at the end of the caller's loop.
#ifndef BIG_MODEL
- *local_succ = OR_STATE(*local_succ, LOAD_FROM_ENG(&e->successors));
+ *local_succ = OR_STATE(*local_succ, LOAD_FROM_ENG(&e->successors));
#else
- ctx->local_succ = OR_STATE(ctx->local_succ, LOAD_FROM_ENG(&e->successors));
+ ctx->local_succ = OR_STATE(ctx->local_succ, LOAD_FROM_ENG(&e->successors));
#endif
// Some exceptions squash states behind them. Note that we squash states in
// 'succ', not local_succ.
- if (e->hasSquash == LIMEX_SQUASH_CYCLIC
- || e->hasSquash == LIMEX_SQUASH_REPORT) {
- *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
+ if (e->hasSquash == LIMEX_SQUASH_CYCLIC
+ || e->hasSquash == LIMEX_SQUASH_REPORT) {
+ *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
if (*cacheable == CACHE_RESULT) {
*cacheable = DO_NOT_CACHE_RESULT;
}
@@ -207,17 +207,17 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
#ifndef RUN_EXCEPTION_FN_ONLY
-/** \brief Process all of the exceptions associated with the states in the \a
- * estate. */
+/** \brief Process all of the exceptions associated with the states in the \a
+ * estate. */
static really_inline
int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
- const struct IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
+ const struct IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
u64a offset, struct CONTEXT_T *ctx, char in_rev, char flags) {
assert(diffmask > 0); // guaranteed by caller macro
- if (EQ_STATE(estate, ctx->cached_estate)) {
+ if (EQ_STATE(estate, ctx->cached_estate)) {
DEBUG_PRINTF("using cached succ from previous state\n");
- *succ = OR_STATE(*succ, ctx->cached_esucc);
+ *succ = OR_STATE(*succ, ctx->cached_esucc);
if (ctx->cached_reports && (flags & CALLBACK_OUTPUT)) {
DEBUG_PRINTF("firing cached reports from previous state\n");
if (unlikely(limexRunReports(ctx->cached_reports, ctx->callback,
@@ -232,7 +232,7 @@ int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
#ifndef BIG_MODEL
STATE_T local_succ = ZERO_STATE;
#else
- ctx->local_succ = ZERO_STATE;
+ ctx->local_succ = ZERO_STATE;
#endif
struct proto_cache new_cache = {0, NULL};
@@ -303,20 +303,20 @@ int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
#else
// A copy of the estate as an array of GPR-sized chunks.
CHUNK_T chunks[sizeof(STATE_T) / sizeof(CHUNK_T)];
- CHUNK_T emask_chunks[sizeof(STATE_T) / sizeof(CHUNK_T)];
+ CHUNK_T emask_chunks[sizeof(STATE_T) / sizeof(CHUNK_T)];
#ifdef ESTATE_ON_STACK
memcpy(chunks, &estate, sizeof(STATE_T));
#else
memcpy(chunks, estatep, sizeof(STATE_T));
#endif
- memcpy(emask_chunks, &limex->exceptionMask, sizeof(STATE_T));
-
- u32 base_index[sizeof(STATE_T) / sizeof(CHUNK_T)];
- base_index[0] = 0;
- for (s32 i = 0; i < (s32)ARRAY_LENGTH(base_index) - 1; i++) {
- base_index[i + 1] = base_index[i] + POPCOUNT_FN(emask_chunks[i]);
- }
-
+ memcpy(emask_chunks, &limex->exceptionMask, sizeof(STATE_T));
+
+ u32 base_index[sizeof(STATE_T) / sizeof(CHUNK_T)];
+ base_index[0] = 0;
+ for (s32 i = 0; i < (s32)ARRAY_LENGTH(base_index) - 1; i++) {
+ base_index[i + 1] = base_index[i] + POPCOUNT_FN(emask_chunks[i]);
+ }
+
do {
u32 t = findAndClearLSB_32(&diffmask);
#ifdef ARCH_64_BIT
@@ -326,17 +326,17 @@ int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
CHUNK_T word = chunks[t];
assert(word != 0);
do {
- u32 bit = FIND_AND_CLEAR_FN(&word);
- u32 local_index = RANK_IN_MASK_FN(emask_chunks[t], bit);
- u32 idx = local_index + base_index[t];
+ u32 bit = FIND_AND_CLEAR_FN(&word);
+ u32 local_index = RANK_IN_MASK_FN(emask_chunks[t], bit);
+ u32 idx = local_index + base_index[t];
const EXCEPTION_T *e = &exceptions[idx];
if (!RUN_EXCEPTION_FN(e, STATE_ARG_NAME, succ,
#ifndef BIG_MODEL
&local_succ,
#endif
- limex, offset, ctx, &new_cache, &cacheable,
- in_rev, flags)) {
+ limex, offset, ctx, &new_cache, &cacheable,
+ in_rev, flags)) {
return PE_RV_HALT;
}
} while (word);
@@ -344,23 +344,23 @@ int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
#endif
#ifndef BIG_MODEL
- *succ = OR_STATE(*succ, local_succ);
+ *succ = OR_STATE(*succ, local_succ);
#else
- *succ = OR_STATE(*succ, ctx->local_succ);
+ *succ = OR_STATE(*succ, ctx->local_succ);
#endif
if (cacheable == CACHE_RESULT) {
- ctx->cached_estate = estate;
+ ctx->cached_estate = estate;
#ifndef BIG_MODEL
ctx->cached_esucc = local_succ;
#else
- ctx->cached_esucc = ctx->local_succ;
+ ctx->cached_esucc = ctx->local_succ;
#endif
ctx->cached_reports = new_cache.reports;
ctx->cached_br = new_cache.br;
} else if (cacheable == DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES) {
if (ctx->cached_br) {
- ctx->cached_estate = ZERO_STATE;
+ ctx->cached_estate = ZERO_STATE;
}
}
@@ -393,9 +393,9 @@ int PE_FN(STATE_ARG, ESTATE_ARG, UNUSED u32 diffmask, STATE_T *succ,
#undef STATE_ARG_NAME
#undef STATE_ARG_P
-#undef IMPL_NFA_T
-
+#undef IMPL_NFA_T
+
#undef CHUNK_T
#undef FIND_AND_CLEAR_FN
-#undef POPCOUNT_FN
-#undef RANK_IN_MASK_FN
+#undef POPCOUNT_FN
+#undef RANK_IN_MASK_FN
diff --git a/contrib/libs/hyperscan/src/nfa/limex_internal.h b/contrib/libs/hyperscan/src/nfa/limex_internal.h
index 2b0ba02a772..23b1bd97071 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_internal.h
@@ -68,9 +68,9 @@
The value of NFA.stateSize gives the total state size in bytes (the sum of
all the above).
- Number of shifts should be always greater or equal to 1
- Number of shifts 0 means that no appropriate NFA engine was found.
-
+ Number of shifts should be always greater or equal to 1
+ Number of shifts 0 means that no appropriate NFA engine was found.
+
*/
#ifndef LIMEX_INTERNAL_H
@@ -80,12 +80,12 @@
#include "repeat_internal.h"
// Constants
-#define MAX_SHIFT_COUNT 8 /**< largest number of shifts used by a LimEx NFA */
-#define MAX_SHIFT_AMOUNT 16 /**< largest shift amount used by a LimEx NFA */
+#define MAX_SHIFT_COUNT 8 /**< largest number of shifts used by a LimEx NFA */
+#define MAX_SHIFT_AMOUNT 16 /**< largest shift amount used by a LimEx NFA */
#define LIMEX_FLAG_COMPRESS_STATE 1 /**< pack state into stream state */
#define LIMEX_FLAG_COMPRESS_MASKED 2 /**< use reach mask-based compression */
-#define LIMEX_FLAG_CANNOT_DIE 4 /**< limex cannot have no states on */
+#define LIMEX_FLAG_CANNOT_DIE 4 /**< limex cannot have no states on */
#define LIMEX_FLAG_EXTRACT_EXP 8 /**< use limex exception bit extraction */
enum LimExTrigger {
@@ -121,7 +121,7 @@ struct NFAException##size { \
u8 trigger; /**< from enum LimExTrigger */ \
}; \
\
-struct LimExNFA##size { \
+struct LimExNFA##size { \
u8 reachMap[N_CHARS]; /**< map of char -> entry in reach[] */ \
u32 reachSize; /**< number of reach masks */ \
u32 accelCount; /**< number of entries in accel table */ \
@@ -153,18 +153,18 @@ struct LimExNFA##size { \
* followers */ \
u_##size compressMask; /**< switch off before compress */ \
u_##size exceptionMask; \
- u_##size repeatCyclicMask; /**< also includes tug states */ \
+ u_##size repeatCyclicMask; /**< also includes tug states */ \
u_##size zombieMask; /**< zombie if in any of the set states */ \
- u_##size shift[MAX_SHIFT_COUNT]; \
- u32 shiftCount; /**< number of shift masks used */ \
- u8 shiftAmount[MAX_SHIFT_COUNT]; /**< shift amount for each mask */ \
+ u_##size shift[MAX_SHIFT_COUNT]; \
+ u32 shiftCount; /**< number of shift masks used */ \
+ u8 shiftAmount[MAX_SHIFT_COUNT]; /**< shift amount for each mask */ \
m512 exceptionShufMask; /**< exception byte shuffle mask */ \
m512 exceptionBitMask; /**< exception bit mask */ \
m512 exceptionAndMask; /**< exception and mask */ \
};
CREATE_NFA_LIMEX(32)
-CREATE_NFA_LIMEX(64)
+CREATE_NFA_LIMEX(64)
CREATE_NFA_LIMEX(128)
CREATE_NFA_LIMEX(256)
CREATE_NFA_LIMEX(384)
@@ -188,16 +188,16 @@ struct NFARepeatInfo {
};
struct NFAAccept {
- u8 single_report; //!< If true, 'reports' is report id.
-
- /**
- * \brief If single report is true, this is the report id to fire.
- * Otherwise, it is the offset (relative to the start of the LimExNFA
- * structure) of a list of reports, terminated with MO_INVALID_IDX.
- */
- u32 reports;
-
- u32 squash; //!< Offset (from LimEx) into squash masks, or MO_INVALID_IDX.
+ u8 single_report; //!< If true, 'reports' is report id.
+
+ /**
+ * \brief If single report is true, this is the report id to fire.
+ * Otherwise, it is the offset (relative to the start of the LimExNFA
+ * structure) of a list of reports, terminated with MO_INVALID_IDX.
+ */
+ u32 reports;
+
+ u32 squash; //!< Offset (from LimEx) into squash masks, or MO_INVALID_IDX.
};
#endif
diff --git a/contrib/libs/hyperscan/src/nfa/limex_limits.h b/contrib/libs/hyperscan/src/nfa/limex_limits.h
index 37a496dee9c..f4df54a4b0c 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_limits.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_limits.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/nfa/limex_native.c b/contrib/libs/hyperscan/src/nfa/limex_native.c
index 5a5e92d2409..f6f5809c363 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_native.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_native.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -49,11 +49,11 @@
#include "limex_runtime.h"
// Other implementation code from X-Macro impl.
-#define SIZE 32
-#define STATE_T u32
-#define ENG_STATE_T u32
-#define LOAD_FROM_ENG load_u32
-
+#define SIZE 32
+#define STATE_T u32
+#define ENG_STATE_T u32
+#define LOAD_FROM_ENG load_u32
+
#include "limex_state_impl.h"
#define INLINE_ATTR really_inline
@@ -73,7 +73,7 @@
static really_inline
int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ,
const struct LimExNFA32 *limex,
- const struct NFAException32 *exceptions, u64a offset,
+ const struct NFAException32 *exceptions, u64a offset,
struct NFAContext32 *ctx, char in_rev, char flags) {
assert(estate != 0); // guaranteed by calling macro
@@ -101,10 +101,10 @@ int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ,
do {
u32 bit = findAndClearLSB_32(&estate);
- u32 idx = rank_in_mask32(limex->exceptionMask, bit);
+ u32 idx = rank_in_mask32(limex->exceptionMask, bit);
const struct NFAException32 *e = &exceptions[idx];
- if (!runException32(e, s, succ, &local_succ, limex, offset, ctx,
- &new_cache, &cacheable, in_rev, flags)) {
+ if (!runException32(e, s, succ, &local_succ, limex, offset, ctx,
+ &new_cache, &cacheable, in_rev, flags)) {
return PE_RV_HALT;
}
} while (estate != 0);
diff --git a/contrib/libs/hyperscan/src/nfa/limex_runtime.h b/contrib/libs/hyperscan/src/nfa/limex_runtime.h
index f307b219092..6109d382d8d 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_runtime.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_runtime.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,8 +30,8 @@
\brief Limex Execution Engine Or:
How I Learned To Stop Worrying And Love The Preprocessor
- This file includes utility functions which do not depend on the size of the
- state or shift masks directly.
+ This file includes utility functions which do not depend on the size of the
+ state or shift masks directly.
*/
#ifndef LIMEX_RUNTIME_H
@@ -95,7 +95,7 @@ int limexRunReports(const ReportID *reports, NfaCallback callback,
for (; *reports != MO_INVALID_IDX; ++reports) {
DEBUG_PRINTF("firing report for id %u at offset %llu\n",
*reports, offset);
- int rv = callback(0, offset, *reports, context);
+ int rv = callback(0, offset, *reports, context);
if (rv == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
}
@@ -103,38 +103,38 @@ int limexRunReports(const ReportID *reports, NfaCallback callback,
return MO_CONTINUE_MATCHING; // continue
}
-static really_inline
-int limexRunAccept(const char *limex_base, const struct NFAAccept *accept,
- NfaCallback callback, void *context, u64a offset) {
- if (accept->single_report) {
- const ReportID report = accept->reports;
- DEBUG_PRINTF("firing single report for id %u at offset %llu\n", report,
- offset);
- return callback(0, offset, report, context);
- }
- const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
- return limexRunReports(reports, callback, context, offset);
-}
-
-static really_inline
-int limexAcceptHasReport(const char *limex_base, const struct NFAAccept *accept,
- ReportID report) {
- if (accept->single_report) {
- return accept->reports == report;
- }
-
- const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
- assert(*reports != MO_INVALID_IDX);
- do {
- if (*reports == report) {
- return 1;
- }
- reports++;
- } while (*reports != MO_INVALID_IDX);
-
- return 0;
-}
-
+static really_inline
+int limexRunAccept(const char *limex_base, const struct NFAAccept *accept,
+ NfaCallback callback, void *context, u64a offset) {
+ if (accept->single_report) {
+ const ReportID report = accept->reports;
+ DEBUG_PRINTF("firing single report for id %u at offset %llu\n", report,
+ offset);
+ return callback(0, offset, report, context);
+ }
+ const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
+ return limexRunReports(reports, callback, context, offset);
+}
+
+static really_inline
+int limexAcceptHasReport(const char *limex_base, const struct NFAAccept *accept,
+ ReportID report) {
+ if (accept->single_report) {
+ return accept->reports == report;
+ }
+
+ const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
+ assert(*reports != MO_INVALID_IDX);
+ do {
+ if (*reports == report) {
+ return 1;
+ }
+ reports++;
+ } while (*reports != MO_INVALID_IDX);
+
+ return 0;
+}
+
/** \brief Return a (correctly typed) pointer to the exception table. */
#define getExceptionTable(exc_type, lim) \
((const exc_type *)((const char *)(lim) + (lim)->exceptionOffset))
@@ -163,7 +163,7 @@ int limexAcceptHasReport(const char *limex_base, const struct NFAAccept *accept,
}
MAKE_GET_NFA_REPEAT_INFO(32)
-MAKE_GET_NFA_REPEAT_INFO(64)
+MAKE_GET_NFA_REPEAT_INFO(64)
MAKE_GET_NFA_REPEAT_INFO(128)
MAKE_GET_NFA_REPEAT_INFO(256)
MAKE_GET_NFA_REPEAT_INFO(384)
diff --git a/contrib/libs/hyperscan/src/nfa/limex_runtime_impl.h b/contrib/libs/hyperscan/src/nfa/limex_runtime_impl.h
index 6486ffe8d78..7b89182bea6 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_runtime_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_runtime_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,12 +36,12 @@
* Version 2.0: now with X-Macros, so you get line numbers in your debugger.
*/
-
-#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
-# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
+
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
-#define LIMEX_API_ROOT JOIN(nfaExecLimEx, SIZE)
+#define LIMEX_API_ROOT JOIN(nfaExecLimEx, SIZE)
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
@@ -60,7 +60,7 @@
#define RUN_ACCEL_FN JOIN(LIMEX_API_ROOT, _Run_Accel)
#define RUN_EXCEPTIONS_FN JOIN(LIMEX_API_ROOT, _Run_Exceptions)
#define REV_STREAM_FN JOIN(LIMEX_API_ROOT, _Rev_Stream)
-#define LOOP_NOACCEL_FN JOIN(LIMEX_API_ROOT, _Loop_No_Accel)
+#define LOOP_NOACCEL_FN JOIN(LIMEX_API_ROOT, _Loop_No_Accel)
#define STREAM_FN JOIN(LIMEX_API_ROOT, _Stream)
#define STREAMCB_FN JOIN(LIMEX_API_ROOT, _Stream_CB)
#define STREAMFIRST_FN JOIN(LIMEX_API_ROOT, _Stream_First)
@@ -70,9 +70,9 @@
#define AND_STATE JOIN(and_, STATE_T)
#define ANDNOT_STATE JOIN(andnot_, STATE_T)
#define OR_STATE JOIN(or_, STATE_T)
-#define LSHIFT_STATE JOIN(lshift_, STATE_T)
+#define LSHIFT_STATE JOIN(lshift_, STATE_T)
#define TESTBIT_STATE JOIN(testbit_, STATE_T)
-#define CLEARBIT_STATE JOIN(clearbit_, STATE_T)
+#define CLEARBIT_STATE JOIN(clearbit_, STATE_T)
#define ZERO_STATE JOIN(zero_, STATE_T)
#define ISNONZERO_STATE JOIN(isNonZero_, STATE_T)
#define ISZERO_STATE JOIN(isZero_, STATE_T)
@@ -95,9 +95,9 @@
#define ACCEL_AND_FRIENDS_MASK accel_and_friendsMask
#define EXCEPTION_MASK exceptionMask
#else
-#define ACCEL_MASK LOAD_FROM_ENG(&limex->accel)
-#define ACCEL_AND_FRIENDS_MASK LOAD_FROM_ENG(&limex->accel_and_friends)
-#define EXCEPTION_MASK LOAD_FROM_ENG(&limex->exceptionMask)
+#define ACCEL_MASK LOAD_FROM_ENG(&limex->accel)
+#define ACCEL_AND_FRIENDS_MASK LOAD_FROM_ENG(&limex->accel_and_friends)
+#define EXCEPTION_MASK LOAD_FROM_ENG(&limex->exceptionMask)
#endif
// Run exception processing, if necessary. Returns 0 if scanning should
@@ -115,13 +115,13 @@ char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
}
if (first_match && i) {
- STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
DEBUG_PRINTF("first match at %zu\n", i);
DEBUG_PRINTF("for nfa %p\n", limex);
assert(final_loc);
- ctx->s = s;
+ ctx->s = s;
*final_loc = i;
return 1; // Halt matching.
}
@@ -131,8 +131,8 @@ char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
char localflags = (!i && !in_rev) ? NO_OUTPUT | FIRST_BYTE : flags;
int rv = JOIN(processExceptional, SIZE)(
- pass_state, pass_estate, diffmask, succ, limex, exceptions,
- callback_offset, ctx, in_rev, localflags);
+ pass_state, pass_estate, diffmask, succ, limex, exceptions,
+ callback_offset, ctx, in_rev, localflags);
if (rv == PE_RV_HALT) {
return 1; // Halt matching.
}
@@ -159,107 +159,107 @@ size_t RUN_ACCEL_FN(const STATE_T s, UNUSED const STATE_T accelMask,
return j;
}
-// Shift macros for Limited NFAs. Defined in terms of uniform ops.
-// LimExNFAxxx ptr in 'limex' and the current state in 's'
-#define NFA_EXEC_LIM_SHIFT(limex_m, curr_m, shift_idx) \
- LSHIFT_STATE(AND_STATE(curr_m, LOAD_FROM_ENG(&limex_m->shift[shift_idx])), \
- limex_m->shiftAmount[shift_idx])
-
-// Calculate the (limited model) successors for a number of variable shifts.
-// Assumes current state in 'curr_m' and places the successors in 'succ_m'.
-#define NFA_EXEC_GET_LIM_SUCC(limex_m, curr_m, succ_m) \
- do { \
- succ_m = NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 0); \
- switch (limex_m->shiftCount) { \
- case 8: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 7)); \
- /* fallthrough */ \
- case 7: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 6)); \
- /* fallthrough */ \
- case 6: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 5)); \
- /* fallthrough */ \
- case 5: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 4)); \
- /* fallthrough */ \
- case 4: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 3)); \
- /* fallthrough */ \
- case 3: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 2)); \
- /* fallthrough */ \
- case 2: \
- succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 1)); \
- /* fallthrough */ \
- case 1: \
- /* fallthrough */ \
- case 0: \
- ; \
- } \
- } while (0)
-
-/**
- * \brief LimEx NFAS inner loop without accel.
- *
- * Note that the "all zeroes" early death check is only performed if can_die is
- * true.
- *
- */
+// Shift macros for Limited NFAs. Defined in terms of uniform ops.
+// LimExNFAxxx ptr in 'limex' and the current state in 's'
+#define NFA_EXEC_LIM_SHIFT(limex_m, curr_m, shift_idx) \
+ LSHIFT_STATE(AND_STATE(curr_m, LOAD_FROM_ENG(&limex_m->shift[shift_idx])), \
+ limex_m->shiftAmount[shift_idx])
+
+// Calculate the (limited model) successors for a number of variable shifts.
+// Assumes current state in 'curr_m' and places the successors in 'succ_m'.
+#define NFA_EXEC_GET_LIM_SUCC(limex_m, curr_m, succ_m) \
+ do { \
+ succ_m = NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 0); \
+ switch (limex_m->shiftCount) { \
+ case 8: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 7)); \
+ /* fallthrough */ \
+ case 7: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 6)); \
+ /* fallthrough */ \
+ case 6: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 5)); \
+ /* fallthrough */ \
+ case 5: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 4)); \
+ /* fallthrough */ \
+ case 4: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 3)); \
+ /* fallthrough */ \
+ case 3: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 2)); \
+ /* fallthrough */ \
+ case 2: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 1)); \
+ /* fallthrough */ \
+ case 1: \
+ /* fallthrough */ \
+ case 0: \
+ ; \
+ } \
+ } while (0)
+
+/**
+ * \brief LimEx NFAS inner loop without accel.
+ *
+ * Note that the "all zeroes" early death check is only performed if can_die is
+ * true.
+ *
+ */
+static really_inline
+char LOOP_NOACCEL_FN(const IMPL_NFA_T *limex, const u8 *input, size_t *loc,
+ size_t length, STATE_T *s_ptr, struct CONTEXT_T *ctx,
+ u64a offset, const char flags, u64a *final_loc,
+ const char first_match, const char can_die) {
+ const ENG_STATE_T *reach = get_reach_table(limex);
+#if SIZE < 256
+ const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
+#endif
+ const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
+ STATE_T s = *s_ptr;
+
+ size_t i = *loc;
+ for (; i != length; i++) {
+ DUMP_INPUT(i);
+ if (can_die && ISZERO_STATE(s)) {
+ DEBUG_PRINTF("no states are switched on, early exit\n");
+ break;
+ }
+
+ STATE_T succ;
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
+
+ if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
+ &succ, final_loc, ctx, flags, 0, first_match)) {
+ return MO_HALT_MATCHING;
+ }
+
+ u8 c = input[i];
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
+ }
+
+ *loc = i;
+ *s_ptr = s;
+ return MO_CONTINUE_MATCHING;
+}
+
static really_inline
-char LOOP_NOACCEL_FN(const IMPL_NFA_T *limex, const u8 *input, size_t *loc,
- size_t length, STATE_T *s_ptr, struct CONTEXT_T *ctx,
- u64a offset, const char flags, u64a *final_loc,
- const char first_match, const char can_die) {
- const ENG_STATE_T *reach = get_reach_table(limex);
-#if SIZE < 256
- const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
-#endif
- const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
- STATE_T s = *s_ptr;
-
- size_t i = *loc;
- for (; i != length; i++) {
- DUMP_INPUT(i);
- if (can_die && ISZERO_STATE(s)) {
- DEBUG_PRINTF("no states are switched on, early exit\n");
- break;
- }
-
- STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
-
- if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
- &succ, final_loc, ctx, flags, 0, first_match)) {
- return MO_HALT_MATCHING;
- }
-
- u8 c = input[i];
- s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
- }
-
- *loc = i;
- *s_ptr = s;
- return MO_CONTINUE_MATCHING;
-}
-
-static really_inline
char STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
struct CONTEXT_T *ctx, u64a offset, const char flags,
u64a *final_loc, const char first_match) {
- const ENG_STATE_T *reach = get_reach_table(limex);
+ const ENG_STATE_T *reach = get_reach_table(limex);
#if SIZE < 256
- const STATE_T accelMask = LOAD_FROM_ENG(&limex->accel);
- const STATE_T accel_and_friendsMask
- = LOAD_FROM_ENG(&limex->accel_and_friends);
- const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
+ const STATE_T accelMask = LOAD_FROM_ENG(&limex->accel);
+ const STATE_T accel_and_friendsMask
+ = LOAD_FROM_ENG(&limex->accel_and_friends);
+ const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
#endif
- const u8 *accelTable =
- (const u8 *)((const char *)limex + limex->accelTableOffset);
+ const u8 *accelTable =
+ (const u8 *)((const char *)limex + limex->accelTableOffset);
const union AccelAux *accelAux =
(const union AccelAux *)((const char *)limex + limex->accelAuxOffset);
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
- STATE_T s = ctx->s;
+ STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */
/* assert(ISALIGNED_16(reach)); */
@@ -274,18 +274,18 @@ char STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
}
without_accel:
- if (limex->flags & LIMEX_FLAG_CANNOT_DIE) {
- const char can_die = 0;
- if (LOOP_NOACCEL_FN(limex, input, &i, min_accel_offset, &s, ctx, offset,
- flags, final_loc, first_match,
- can_die) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
+ if (limex->flags & LIMEX_FLAG_CANNOT_DIE) {
+ const char can_die = 0;
+ if (LOOP_NOACCEL_FN(limex, input, &i, min_accel_offset, &s, ctx, offset,
+ flags, final_loc, first_match,
+ can_die) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
}
- } else {
- const char can_die = 1;
- if (LOOP_NOACCEL_FN(limex, input, &i, min_accel_offset, &s, ctx, offset,
- flags, final_loc, first_match,
- can_die) == MO_HALT_MATCHING) {
+ } else {
+ const char can_die = 1;
+ if (LOOP_NOACCEL_FN(limex, input, &i, min_accel_offset, &s, ctx, offset,
+ flags, final_loc, first_match,
+ can_die) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
}
}
@@ -329,31 +329,31 @@ with_accel:
}
STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
- if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
- &succ, final_loc, ctx, flags, 0, first_match)) {
+ if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
+ &succ, final_loc, ctx, flags, 0, first_match)) {
return MO_HALT_MATCHING;
}
- u8 c = input[i];
- s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
+ u8 c = input[i];
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
}
- ctx->s = s;
+ ctx->s = s;
if ((first_match || (flags & CALLBACK_OUTPUT)) && limex->acceptCount) {
- STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
const struct NFAAccept *acceptTable = getAcceptTable(limex);
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
if (first_match) {
- ctx->s = s;
+ ctx->s = s;
assert(final_loc);
*final_loc = length;
return MO_HALT_MATCHING;
- } else if (PROCESS_ACCEPTS_FN(limex, &ctx->s, &acceptMask,
- acceptTable, offset + length,
+ } else if (PROCESS_ACCEPTS_FN(limex, &ctx->s, &acceptMask,
+ acceptTable, offset + length,
ctx->callback, ctx->context)) {
return MO_HALT_MATCHING;
}
@@ -369,12 +369,12 @@ with_accel:
static never_inline
char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
struct CONTEXT_T *ctx, u64a offset) {
- const ENG_STATE_T *reach = get_reach_table(limex);
+ const ENG_STATE_T *reach = get_reach_table(limex);
#if SIZE < 256
- const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
+ const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
#endif
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
- STATE_T s = ctx->s;
+ STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */
/* assert(ISALIGNED_16(reach)); */
@@ -382,36 +382,36 @@ char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
u64a *final_loc = NULL;
for (size_t i = length; i != 0; i--) {
- DUMP_INPUT(i - 1);
+ DUMP_INPUT(i - 1);
if (ISZERO_STATE(s)) {
DEBUG_PRINTF("no states are switched on, early exit\n");
- ctx->s = s;
+ ctx->s = s;
return MO_CONTINUE_MATCHING;
}
STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
- if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
- &succ, final_loc, ctx, flags, 1, 0)) {
+ if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
+ &succ, final_loc, ctx, flags, 1, 0)) {
return MO_HALT_MATCHING;
}
- u8 c = input[i - 1];
- s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
+ u8 c = input[i - 1];
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
}
- ctx->s = s;
+ ctx->s = s;
- STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
const struct NFAAccept *acceptTable = getAcceptTable(limex);
const u32 acceptCount = limex->acceptCount;
assert(flags & CALLBACK_OUTPUT);
if (acceptCount) {
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
- if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &ctx->s, &acceptMask,
- acceptTable, offset, ctx->callback,
+ if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &ctx->s, &acceptMask,
+ acceptTable, offset, ctx->callback,
ctx->context)) {
return MO_HALT_MATCHING;
}
@@ -421,53 +421,53 @@ char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
}
static really_inline
-void COMPRESS_REPEATS_FN(const IMPL_NFA_T *limex, void *dest, void *src,
+void COMPRESS_REPEATS_FN(const IMPL_NFA_T *limex, void *dest, void *src,
u64a offset) {
if (!limex->repeatCount) {
return;
}
- STATE_T s = *(STATE_T *)src;
+ STATE_T s = *(STATE_T *)src;
+
+ if (ISZERO_STATE(AND_STATE(LOAD_FROM_ENG(&limex->repeatCyclicMask), s))) {
+ DEBUG_PRINTF("no cyclics are on\n");
+ return;
+ }
- if (ISZERO_STATE(AND_STATE(LOAD_FROM_ENG(&limex->repeatCyclicMask), s))) {
- DEBUG_PRINTF("no cyclics are on\n");
- return;
- }
-
const union RepeatControl *ctrl =
getRepeatControlBaseConst((const char *)src, sizeof(STATE_T));
char *state_base = (char *)dest + limex->stateSize;
for (u32 i = 0; i < limex->repeatCount; i++) {
- DEBUG_PRINTF("repeat %u\n", i);
+ DEBUG_PRINTF("repeat %u\n", i);
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
-
- const ENG_STATE_T *tug_mask =
- (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
- /* repeat may still be inspected if its tug state is on */
- if (!TESTBIT_STATE(s, info->cyclicState)
- && ISZERO_STATE(AND_STATE(s, LOAD_FROM_ENG(tug_mask)))) {
- DEBUG_PRINTF("is dead\n");
- continue;
- }
-
+
+ const ENG_STATE_T *tug_mask =
+ (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
+ /* repeat may still be inspected if its tug state is on */
+ if (!TESTBIT_STATE(s, info->cyclicState)
+ && ISZERO_STATE(AND_STATE(s, LOAD_FROM_ENG(tug_mask)))) {
+ DEBUG_PRINTF("is dead\n");
+ continue;
+ }
+
const struct RepeatInfo *repeat = getRepeatInfo(info);
- DEBUG_PRINTF("packing state (packedCtrlOffset=%u)\n",
- info->packedCtrlOffset);
+ DEBUG_PRINTF("packing state (packedCtrlOffset=%u)\n",
+ info->packedCtrlOffset);
repeatPack(state_base + info->packedCtrlOffset, repeat, &ctrl[i],
offset);
}
-
- *(STATE_T *)src = s;
+
+ *(STATE_T *)src = s;
}
char JOIN(LIMEX_API_ROOT, _queueCompressState)(const struct NFA *n,
- const struct mq *q, s64a loc) {
+ const struct mq *q, s64a loc) {
void *dest = q->streamState;
- void *src = q->state;
+ void *src = q->state;
u8 key = queue_prev_byte(q, loc);
const IMPL_NFA_T *limex = getImplNfa(n);
- COMPRESS_REPEATS_FN(limex, dest, src, q->offset + loc);
+ COMPRESS_REPEATS_FN(limex, dest, src, q->offset + loc);
COMPRESS_FN(limex, dest, src, key);
return 0;
}
@@ -479,32 +479,32 @@ void EXPAND_REPEATS_FN(const IMPL_NFA_T *limex, void *dest, const void *src,
return;
}
- // Note: state has already been expanded into 'dest'.
- const STATE_T cyclics =
- AND_STATE(*(STATE_T *)dest, LOAD_FROM_ENG(&limex->repeatCyclicMask));
- if (ISZERO_STATE(cyclics)) {
- DEBUG_PRINTF("no cyclics are on\n");
- return;
- }
+ // Note: state has already been expanded into 'dest'.
+ const STATE_T cyclics =
+ AND_STATE(*(STATE_T *)dest, LOAD_FROM_ENG(&limex->repeatCyclicMask));
+ if (ISZERO_STATE(cyclics)) {
+ DEBUG_PRINTF("no cyclics are on\n");
+ return;
+ }
union RepeatControl *ctrl =
getRepeatControlBase((char *)dest, sizeof(STATE_T));
const char *state_base = (const char *)src + limex->stateSize;
for (u32 i = 0; i < limex->repeatCount; i++) {
- DEBUG_PRINTF("repeat %u\n", i);
+ DEBUG_PRINTF("repeat %u\n", i);
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
- const ENG_STATE_T *tug_mask =
- (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
-
- if (!TESTBIT_STATE(cyclics, info->cyclicState)
- && ISZERO_STATE(AND_STATE(cyclics, LOAD_FROM_ENG(tug_mask)))) {
- DEBUG_PRINTF("is dead\n");
- continue;
- }
-
- DEBUG_PRINTF("unpacking state (packedCtrlOffset=%u)\n",
- info->packedCtrlOffset);
+ const ENG_STATE_T *tug_mask =
+ (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
+
+ if (!TESTBIT_STATE(cyclics, info->cyclicState)
+ && ISZERO_STATE(AND_STATE(cyclics, LOAD_FROM_ENG(tug_mask)))) {
+ DEBUG_PRINTF("is dead\n");
+ continue;
+ }
+
+ DEBUG_PRINTF("unpacking state (packedCtrlOffset=%u)\n",
+ info->packedCtrlOffset);
const struct RepeatInfo *repeat = getRepeatInfo(info);
repeatUnpack(state_base + info->packedCtrlOffset, repeat, offset,
&ctrl[i]);
@@ -520,8 +520,8 @@ char JOIN(LIMEX_API_ROOT, _expandState)(const struct NFA *n, void *dest,
return 0;
}
-char JOIN(LIMEX_API_ROOT, _queueInitState)(const struct NFA *n, struct mq *q) {
- *(STATE_T *)q->state = ZERO_STATE;
+char JOIN(LIMEX_API_ROOT, _queueInitState)(const struct NFA *n, struct mq *q) {
+ *(STATE_T *)q->state = ZERO_STATE;
// Zero every bounded repeat control block in state.
const IMPL_NFA_T *limex = getImplNfa(n);
@@ -601,7 +601,7 @@ void JOIN(LIMEX_API_ROOT, _HandleEvent)(const IMPL_NFA_T *limex,
u32 e = q->items[q->cur].type;
switch (e) {
DEFINE_CASE(MQE_TOP)
- ctx->s = TOP_FN(limex, !!sp, ctx->s);
+ ctx->s = TOP_FN(limex, !!sp, ctx->s);
break;
DEFINE_CASE(MQE_START)
break;
@@ -611,7 +611,7 @@ void JOIN(LIMEX_API_ROOT, _HandleEvent)(const IMPL_NFA_T *limex,
assert(e >= MQE_TOP_FIRST);
assert(e < MQE_INVALID);
DEBUG_PRINTF("MQE_TOP + %d\n", ((int)e - MQE_TOP_FIRST));
- ctx->s = TOPN_FN(limex, ctx->s, e - MQE_TOP_FIRST);
+ ctx->s = TOPN_FN(limex, ctx->s, e - MQE_TOP_FIRST);
}
#undef DEFINE_CASE
}
@@ -636,17 +636,17 @@ char JOIN(LIMEX_API_ROOT, _Q)(const struct NFA *n, struct mq *q, s64a end) {
assert(q->cur + 1 < q->end); /* require at least two items */
- struct CONTEXT_T ctx;
- ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
- ctx.repeat_state = q->streamState + limex->stateSize;
- ctx.callback = q->cb;
- ctx.context = q->context;
- ctx.cached_estate = ZERO_STATE;
- ctx.cached_br = 0;
+ struct CONTEXT_T ctx;
+ ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
+ ctx.repeat_state = q->streamState + limex->stateSize;
+ ctx.callback = q->cb;
+ ctx.context = q->context;
+ ctx.cached_estate = ZERO_STATE;
+ ctx.cached_br = 0;
assert(q->items[q->cur].location >= 0);
DEBUG_PRINTF("LOAD STATE\n");
- ctx.s = *(STATE_T *)q->state;
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
@@ -668,9 +668,9 @@ char JOIN(LIMEX_API_ROOT, _Q)(const struct NFA *n, struct mq *q, s64a end) {
/* do main buffer region */
DEBUG_PRINTF("MAIN BUFFER SCAN\n");
assert(ep - offset <= q->length);
- if (STREAMCB_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp)
+ if (STREAMCB_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp)
== MO_HALT_MATCHING) {
- *(STATE_T *)q->state = ZERO_STATE;
+ *(STATE_T *)q->state = ZERO_STATE;
return 0;
}
@@ -687,19 +687,19 @@ char JOIN(LIMEX_API_ROOT, _Q)(const struct NFA *n, struct mq *q, s64a end) {
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp - offset;
DEBUG_PRINTF("bailing q->cur %u q->end %u\n", q->cur, q->end);
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
return MO_ALIVE;
}
- JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
+ JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
q->cur++;
}
- EXPIRE_ESTATE_FN(limex, &ctx, sp);
+ EXPIRE_ESTATE_FN(limex, &ctx, sp);
DEBUG_PRINTF("END\n");
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
if (q->cur != q->end) {
q->cur--;
@@ -708,7 +708,7 @@ char JOIN(LIMEX_API_ROOT, _Q)(const struct NFA *n, struct mq *q, s64a end) {
return MO_ALIVE;
}
- return ISNONZERO_STATE(ctx.s);
+ return ISNONZERO_STATE(ctx.s);
}
/* used by suffix execution in Rose */
@@ -731,16 +731,16 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
assert(q->cur + 1 < q->end); /* require at least two items */
- struct CONTEXT_T ctx;
- ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
- ctx.repeat_state = q->streamState + limex->stateSize;
- ctx.callback = q->cb;
- ctx.context = q->context;
- ctx.cached_estate = ZERO_STATE;
- ctx.cached_br = 0;
+ struct CONTEXT_T ctx;
+ ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
+ ctx.repeat_state = q->streamState + limex->stateSize;
+ ctx.callback = q->cb;
+ ctx.context = q->context;
+ ctx.cached_estate = ZERO_STATE;
+ ctx.cached_br = 0;
DEBUG_PRINTF("LOAD STATE\n");
- ctx.s = *(STATE_T *)q->state;
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
@@ -755,28 +755,28 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
ep = MIN(ep, end_abs);
assert(ep >= sp);
- if (sp < offset) {
- DEBUG_PRINTF("HISTORY BUFFER SCAN\n");
- assert(offset - sp <= q->hlength);
- u64a local_ep = MIN(offset, ep);
- u64a final_look = 0;
- /* we are starting inside the history buffer */
- if (STREAMFIRST_FN(limex, q->history + q->hlength + sp - offset,
- local_ep - sp, &ctx, sp,
- &final_look) == MO_HALT_MATCHING) {
- DEBUG_PRINTF("final_look:%llu sp:%llu end_abs:%llu "
- "offset:%llu\n", final_look, sp, end_abs, offset);
- assert(q->cur);
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = sp + final_look - offset;
- *(STATE_T *)q->state = ctx.s;
- return MO_MATCHES_PENDING;
- }
-
- sp = local_ep;
- }
-
+ if (sp < offset) {
+ DEBUG_PRINTF("HISTORY BUFFER SCAN\n");
+ assert(offset - sp <= q->hlength);
+ u64a local_ep = MIN(offset, ep);
+ u64a final_look = 0;
+ /* we are starting inside the history buffer */
+ if (STREAMFIRST_FN(limex, q->history + q->hlength + sp - offset,
+ local_ep - sp, &ctx, sp,
+ &final_look) == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("final_look:%llu sp:%llu end_abs:%llu "
+ "offset:%llu\n", final_look, sp, end_abs, offset);
+ assert(q->cur);
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = sp + final_look - offset;
+ *(STATE_T *)q->state = ctx.s;
+ return MO_MATCHES_PENDING;
+ }
+
+ sp = local_ep;
+ }
+
if (sp >= ep) {
goto scan_done;
}
@@ -784,7 +784,7 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
/* do main buffer region */
u64a final_look = 0;
assert(ep - offset <= q->length);
- if (STREAMFIRST_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp,
+ if (STREAMFIRST_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp,
&final_look) == MO_HALT_MATCHING) {
DEBUG_PRINTF("final_look:%llu sp:%llu end_abs:%llu offset:%llu\n",
final_look, sp, end_abs, offset);
@@ -792,7 +792,7 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
q->cur--;
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp + final_look - offset;
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
return MO_MATCHES_PENDING;
}
@@ -808,19 +808,19 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp - offset;
DEBUG_PRINTF("bailing q->cur %u q->end %u\n", q->cur, q->end);
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
return MO_ALIVE;
}
- JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
+ JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
q->cur++;
}
- EXPIRE_ESTATE_FN(limex, &ctx, sp);
+ EXPIRE_ESTATE_FN(limex, &ctx, sp);
DEBUG_PRINTF("END\n");
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
if (q->cur != q->end) {
q->cur--;
@@ -829,7 +829,7 @@ char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
return MO_ALIVE;
}
- return ISNONZERO_STATE(ctx.s);
+ return ISNONZERO_STATE(ctx.s);
}
// Used for execution Rose prefix/infixes.
@@ -843,16 +843,16 @@ char JOIN(LIMEX_API_ROOT, _QR)(const struct NFA *n, struct mq *q,
assert(q->cur + 1 < q->end); /* require at least two items */
- struct CONTEXT_T ctx;
- ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
- ctx.repeat_state = q->streamState + limex->stateSize;
- ctx.callback = NULL;
- ctx.context = NULL;
- ctx.cached_estate = ZERO_STATE;
- ctx.cached_br = 0;
+ struct CONTEXT_T ctx;
+ ctx.repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
+ ctx.repeat_state = q->streamState + limex->stateSize;
+ ctx.callback = NULL;
+ ctx.context = NULL;
+ ctx.cached_estate = ZERO_STATE;
+ ctx.cached_br = 0;
DEBUG_PRINTF("LOAD STATE\n");
- ctx.s = *(STATE_T *)q->state;
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
@@ -864,7 +864,7 @@ char JOIN(LIMEX_API_ROOT, _QR)(const struct NFA *n, struct mq *q,
if (n->maxWidth) {
if (ep - sp > n->maxWidth) {
sp = ep - n->maxWidth;
- ctx.s = INITIAL_FN(limex, !!sp);
+ ctx.s = INITIAL_FN(limex, !!sp);
}
}
assert(ep >= sp);
@@ -875,7 +875,7 @@ char JOIN(LIMEX_API_ROOT, _QR)(const struct NFA *n, struct mq *q,
u64a local_ep = MIN(offset, ep);
/* we are starting inside the history buffer */
STREAMSILENT_FN(limex, q->history + q->hlength + sp - offset,
- local_ep - sp, &ctx, sp);
+ local_ep - sp, &ctx, sp);
sp = local_ep;
}
@@ -887,35 +887,35 @@ char JOIN(LIMEX_API_ROOT, _QR)(const struct NFA *n, struct mq *q,
/* do main buffer region */
DEBUG_PRINTF("MAIN BUFFER SCAN\n");
assert(ep - offset <= q->length);
- STREAMSILENT_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp);
+ STREAMSILENT_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp);
DEBUG_PRINTF("SCAN DONE\n");
scan_done:
sp = ep;
- JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
+ JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, &ctx, sp);
q->cur++;
}
- EXPIRE_ESTATE_FN(limex, &ctx, sp);
+ EXPIRE_ESTATE_FN(limex, &ctx, sp);
DEBUG_PRINTF("END, nfa is %s\n",
- ISNONZERO_STATE(ctx.s) ? "still alive" : "dead");
+ ISNONZERO_STATE(ctx.s) ? "still alive" : "dead");
- *(STATE_T *)q->state = ctx.s;
+ *(STATE_T *)q->state = ctx.s;
- if (JOIN(limexInAccept, SIZE)(limex, ctx.s, ctx.repeat_ctrl,
- ctx.repeat_state, sp + 1, report)) {
+ if (JOIN(limexInAccept, SIZE)(limex, ctx.s, ctx.repeat_ctrl,
+ ctx.repeat_state, sp + 1, report)) {
return MO_MATCHES_PENDING;
}
- return ISNONZERO_STATE(ctx.s);
+ return ISNONZERO_STATE(ctx.s);
}
char JOIN(LIMEX_API_ROOT, _testEOD)(const struct NFA *n, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
assert(n && state);
const IMPL_NFA_T *limex = getImplNfa(n);
@@ -923,8 +923,8 @@ char JOIN(LIMEX_API_ROOT, _testEOD)(const struct NFA *n, const char *state,
const union RepeatControl *repeat_ctrl =
getRepeatControlBaseConst(state, sizeof(STATE_T));
const char *repeat_state = streamState + limex->stateSize;
- return TESTEOD_FN(limex, sptr, repeat_ctrl, repeat_state, offset, callback,
- context);
+ return TESTEOD_FN(limex, sptr, repeat_ctrl, repeat_state, offset, callback,
+ context);
}
char JOIN(LIMEX_API_ROOT, _reportCurrent)(const struct NFA *n, struct mq *q) {
@@ -935,43 +935,43 @@ char JOIN(LIMEX_API_ROOT, _reportCurrent)(const struct NFA *n, struct mq *q) {
// Block mode reverse scan.
char JOIN(LIMEX_API_ROOT, _B_Reverse)(const struct NFA *n, u64a offset,
- const u8 *buf, size_t buflen,
- const u8 *hbuf, size_t hlen,
- NfaCallback cb, void *context) {
+ const u8 *buf, size_t buflen,
+ const u8 *hbuf, size_t hlen,
+ NfaCallback cb, void *context) {
assert(buf || hbuf);
assert(buflen || hlen);
- struct CONTEXT_T ctx;
- ctx.repeat_ctrl = NULL;
- ctx.repeat_state = NULL;
- ctx.callback = cb;
- ctx.context = context;
- ctx.cached_estate = ZERO_STATE;
- ctx.cached_br = 0;
+ struct CONTEXT_T ctx;
+ ctx.repeat_ctrl = NULL;
+ ctx.repeat_state = NULL;
+ ctx.callback = cb;
+ ctx.context = context;
+ ctx.cached_estate = ZERO_STATE;
+ ctx.cached_br = 0;
const IMPL_NFA_T *limex = getImplNfa(n);
- ctx.s = INITIAL_FN(limex, 0); // always anchored
+ ctx.s = INITIAL_FN(limex, 0); // always anchored
// 'buf' may be null, for example when we're scanning at EOD time.
if (buflen) {
assert(buf);
DEBUG_PRINTF("MAIN BUFFER SCAN, %zu bytes\n", buflen);
offset -= buflen;
- REV_STREAM_FN(limex, buf, buflen, &ctx, offset);
+ REV_STREAM_FN(limex, buf, buflen, &ctx, offset);
}
if (hlen) {
assert(hbuf);
DEBUG_PRINTF("HISTORY BUFFER SCAN, %zu bytes\n", hlen);
offset -= hlen;
- REV_STREAM_FN(limex, hbuf, hlen, &ctx, offset);
+ REV_STREAM_FN(limex, hbuf, hlen, &ctx, offset);
}
- if (offset == 0 && limex->acceptEodCount && ISNONZERO_STATE(ctx.s)) {
- const union RepeatControl *repeat_ctrl = NULL;
- const char *repeat_state = NULL;
- TESTEOD_FN(limex, &ctx.s, repeat_ctrl, repeat_state, offset, cb,
- context);
+ if (offset == 0 && limex->acceptEodCount && ISNONZERO_STATE(ctx.s)) {
+ const union RepeatControl *repeat_ctrl = NULL;
+ const char *repeat_state = NULL;
+ TESTEOD_FN(limex, &ctx.s, repeat_ctrl, repeat_state, offset, cb,
+ context);
}
// NOTE: return value is unused.
@@ -987,36 +987,36 @@ char JOIN(LIMEX_API_ROOT, _inAccept)(const struct NFA *nfa,
union RepeatControl *repeat_ctrl =
getRepeatControlBase(q->state, sizeof(STATE_T));
char *repeat_state = q->streamState + limex->stateSize;
- STATE_T state = *(STATE_T *)q->state;
+ STATE_T state = *(STATE_T *)q->state;
u64a offset = q->offset + q_last_loc(q) + 1;
return JOIN(limexInAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
offset, report);
}
-char JOIN(LIMEX_API_ROOT, _inAnyAccept)(const struct NFA *nfa, struct mq *q) {
- assert(nfa && q);
- assert(q->state && q->streamState);
-
- const IMPL_NFA_T *limex = getImplNfa(nfa);
- union RepeatControl *repeat_ctrl =
- getRepeatControlBase(q->state, sizeof(STATE_T));
- char *repeat_state = q->streamState + limex->stateSize;
- STATE_T state = *(STATE_T *)q->state;
- u64a offset = q->offset + q_last_loc(q) + 1;
-
- return JOIN(limexInAnyAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
- offset);
-}
-
+char JOIN(LIMEX_API_ROOT, _inAnyAccept)(const struct NFA *nfa, struct mq *q) {
+ assert(nfa && q);
+ assert(q->state && q->streamState);
+
+ const IMPL_NFA_T *limex = getImplNfa(nfa);
+ union RepeatControl *repeat_ctrl =
+ getRepeatControlBase(q->state, sizeof(STATE_T));
+ char *repeat_state = q->streamState + limex->stateSize;
+ STATE_T state = *(STATE_T *)q->state;
+ u64a offset = q->offset + q_last_loc(q) + 1;
+
+ return JOIN(limexInAnyAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
+ offset);
+}
+
enum nfa_zombie_status JOIN(LIMEX_API_ROOT, _zombie_status)(
const struct NFA *nfa,
struct mq *q,
s64a loc) {
assert(nfa->flags & NFA_ZOMBIE);
const IMPL_NFA_T *limex = getImplNfa(nfa);
- STATE_T state = *(STATE_T *)q->state;
- STATE_T zmask = LOAD_FROM_ENG(&limex->zombieMask);
+ STATE_T state = *(STATE_T *)q->state;
+ STATE_T zmask = LOAD_FROM_ENG(&limex->zombieMask);
if (limex->repeatCount) {
u64a offset = q->offset + loc + 1;
@@ -1048,7 +1048,7 @@ enum nfa_zombie_status JOIN(LIMEX_API_ROOT, _zombie_status)(
#undef RUN_ACCEL_FN
#undef RUN_EXCEPTIONS_FN
#undef REV_STREAM_FN
-#undef LOOP_NOACCEL_FN
+#undef LOOP_NOACCEL_FN
#undef STREAM_FN
#undef STREAMCB_FN
#undef STREAMFIRST_FN
@@ -1058,9 +1058,9 @@ enum nfa_zombie_status JOIN(LIMEX_API_ROOT, _zombie_status)(
#undef AND_STATE
#undef ANDNOT_STATE
#undef OR_STATE
-#undef LSHIFT_STATE
+#undef LSHIFT_STATE
#undef TESTBIT_STATE
-#undef CLEARBIT_STATE
+#undef CLEARBIT_STATE
#undef ZERO_STATE
#undef ISNONZERO_STATE
#undef ISZERO_STATE
diff --git a/contrib/libs/hyperscan/src/nfa/limex_shuffle.h b/contrib/libs/hyperscan/src/nfa/limex_shuffle.h
index 7786ed8b073..365d47296e7 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_shuffle.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_shuffle.h
@@ -1,78 +1,78 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Naive dynamic shuffles.
- *
- * These are written with the assumption that the provided masks are sparsely
- * populated and never contain more than 32 on bits. Other implementations will
- * be faster and actually correct if these assumptions don't hold true.
- */
-
-#ifndef LIMEX_SHUFFLE_H
-#define LIMEX_SHUFFLE_H
-
-#include "ue2common.h"
-#include "util/arch.h"
-#include "util/bitutils.h"
-#include "util/simd_utils.h"
-
-static really_inline
-u32 packedExtract128(m128 s, const m128 permute, const m128 compare) {
- m128 shuffled = pshufb_m128(s, permute);
- m128 compared = and128(shuffled, compare);
- u16 rv = ~movemask128(eq128(compared, shuffled));
- return (u32)rv;
-}
-
-#if defined(HAVE_AVX2)
-static really_inline
-u32 packedExtract256(m256 s, const m256 permute, const m256 compare) {
- // vpshufb doesn't cross lanes, so this is a bit of a cheat
- m256 shuffled = pshufb_m256(s, permute);
- m256 compared = and256(shuffled, compare);
- u32 rv = ~movemask256(eq256(compared, shuffled));
- // stitch the lane-wise results back together
- return (u32)((rv >> 16) | (rv & 0xffffU));
-}
-#endif // AVX2
-
-#if defined(HAVE_AVX512)
-static really_inline
-u32 packedExtract512(m512 s, const m512 permute, const m512 compare) {
- // vpshufb doesn't cross lanes, so this is a bit of a cheat
- m512 shuffled = pshufb_m512(s, permute);
- m512 compared = and512(shuffled, compare);
- u64a rv = ~eq512mask(compared, shuffled);
- // stitch the lane-wise results back together
- rv = rv >> 32 | rv;
- return (u32)(((rv >> 16) | rv) & 0xffffU);
-}
-#endif // AVX512
-
-#endif // LIMEX_SHUFFLE_H
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Naive dynamic shuffles.
+ *
+ * These are written with the assumption that the provided masks are sparsely
+ * populated and never contain more than 32 on bits. Other implementations will
+ * be faster and actually correct if these assumptions don't hold true.
+ */
+
+#ifndef LIMEX_SHUFFLE_H
+#define LIMEX_SHUFFLE_H
+
+#include "ue2common.h"
+#include "util/arch.h"
+#include "util/bitutils.h"
+#include "util/simd_utils.h"
+
+static really_inline
+u32 packedExtract128(m128 s, const m128 permute, const m128 compare) {
+ m128 shuffled = pshufb_m128(s, permute);
+ m128 compared = and128(shuffled, compare);
+ u16 rv = ~movemask128(eq128(compared, shuffled));
+ return (u32)rv;
+}
+
+#if defined(HAVE_AVX2)
+static really_inline
+u32 packedExtract256(m256 s, const m256 permute, const m256 compare) {
+ // vpshufb doesn't cross lanes, so this is a bit of a cheat
+ m256 shuffled = pshufb_m256(s, permute);
+ m256 compared = and256(shuffled, compare);
+ u32 rv = ~movemask256(eq256(compared, shuffled));
+ // stitch the lane-wise results back together
+ return (u32)((rv >> 16) | (rv & 0xffffU));
+}
+#endif // AVX2
+
+#if defined(HAVE_AVX512)
+static really_inline
+u32 packedExtract512(m512 s, const m512 permute, const m512 compare) {
+ // vpshufb doesn't cross lanes, so this is a bit of a cheat
+ m512 shuffled = pshufb_m512(s, permute);
+ m512 compared = and512(shuffled, compare);
+ u64a rv = ~eq512mask(compared, shuffled);
+ // stitch the lane-wise results back together
+ rv = rv >> 32 | rv;
+ return (u32)(((rv >> 16) | rv) & 0xffffU);
+}
+#endif // AVX512
+
+#endif // LIMEX_SHUFFLE_H
diff --git a/contrib/libs/hyperscan/src/nfa/limex_simd128.c b/contrib/libs/hyperscan/src/nfa/limex_simd128.c
index f6f86ac27b5..c5f2b33e3e3 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_simd128.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_simd128.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -48,11 +48,11 @@
#include "limex_runtime.h"
-#define SIZE 128
-#define STATE_T m128
-#define ENG_STATE_T m128
-#define LOAD_FROM_ENG load_m128
-
+#define SIZE 128
+#define STATE_T m128
+#define ENG_STATE_T m128
+#define LOAD_FROM_ENG load_m128
+
#include "limex_exceptional.h"
#include "limex_state_impl.h"
diff --git a/contrib/libs/hyperscan/src/nfa/limex_simd256.c b/contrib/libs/hyperscan/src/nfa/limex_simd256.c
index 2de8c162cd6..cc232908106 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_simd256.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_simd256.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,11 +45,11 @@
// Common code
#include "limex_runtime.h"
-#define SIZE 256
-#define STATE_T m256
-#define ENG_STATE_T m256
-#define LOAD_FROM_ENG load_m256
-
+#define SIZE 256
+#define STATE_T m256
+#define ENG_STATE_T m256
+#define LOAD_FROM_ENG load_m256
+
#include "limex_exceptional.h"
#include "limex_state_impl.h"
diff --git a/contrib/libs/hyperscan/src/nfa/limex_simd384.c b/contrib/libs/hyperscan/src/nfa/limex_simd384.c
index 6a7e5c94ace..7e596e48b0a 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_simd384.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_simd384.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,11 +45,11 @@
// Common code
#include "limex_runtime.h"
-#define SIZE 384
-#define STATE_T m384
-#define ENG_STATE_T m384
-#define LOAD_FROM_ENG load_m384
-
+#define SIZE 384
+#define STATE_T m384
+#define ENG_STATE_T m384
+#define LOAD_FROM_ENG load_m384
+
#include "limex_exceptional.h"
#include "limex_state_impl.h"
diff --git a/contrib/libs/hyperscan/src/nfa/limex_simd512.c b/contrib/libs/hyperscan/src/nfa/limex_simd512.c
index a85da3138c9..f779f335d29 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_simd512.c
+++ b/contrib/libs/hyperscan/src/nfa/limex_simd512.c
@@ -1,60 +1,60 @@
-/*
- * Copyright (c) 2015-2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief LimEx NFA: 512-bit SIMD runtime implementations.
- */
-
-//#define DEBUG_INPUT
-//#define DEBUG_EXCEPTIONS
-
-#include "limex.h"
-
-#include "accel.h"
-#include "limex_internal.h"
-#include "nfa_internal.h"
-#include "ue2common.h"
-#include "util/bitutils.h"
-#include "util/simd_utils.h"
-
-// Common code
-#include "limex_runtime.h"
-
-#define SIZE 512
-#define STATE_T m512
-#define ENG_STATE_T m512
-#define LOAD_FROM_ENG load_m512
-
-#include "limex_exceptional.h"
-
-#include "limex_state_impl.h"
-
-#define INLINE_ATTR really_inline
-#include "limex_common_impl.h"
-
-#include "limex_runtime_impl.h"
+/*
+ * Copyright (c) 2015-2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief LimEx NFA: 512-bit SIMD runtime implementations.
+ */
+
+//#define DEBUG_INPUT
+//#define DEBUG_EXCEPTIONS
+
+#include "limex.h"
+
+#include "accel.h"
+#include "limex_internal.h"
+#include "nfa_internal.h"
+#include "ue2common.h"
+#include "util/bitutils.h"
+#include "util/simd_utils.h"
+
+// Common code
+#include "limex_runtime.h"
+
+#define SIZE 512
+#define STATE_T m512
+#define ENG_STATE_T m512
+#define LOAD_FROM_ENG load_m512
+
+#include "limex_exceptional.h"
+
+#include "limex_state_impl.h"
+
+#define INLINE_ATTR really_inline
+#include "limex_common_impl.h"
+
+#include "limex_runtime_impl.h"
diff --git a/contrib/libs/hyperscan/src/nfa/limex_state_impl.h b/contrib/libs/hyperscan/src/nfa/limex_state_impl.h
index 7d1721432de..81153f71715 100644
--- a/contrib/libs/hyperscan/src/nfa/limex_state_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/limex_state_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,8 +35,8 @@
#include "util/state_compress.h"
#include <string.h>
-#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
-# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
@@ -44,8 +44,8 @@
#define REACHMASK_FN JOIN(moNfaReachMask, SIZE)
#define COMPRESS_FN JOIN(moNfaCompressState, SIZE)
#define EXPAND_FN JOIN(moNfaExpandState, SIZE)
-#define COMPRESSED_STORE_FN JOIN(store_compressed_, STATE_T)
-#define COMPRESSED_LOAD_FN JOIN(load_compressed_, STATE_T)
+#define COMPRESSED_STORE_FN JOIN(store_compressed_, STATE_T)
+#define COMPRESSED_LOAD_FN JOIN(load_compressed_, STATE_T)
#define PARTIAL_STORE_FN JOIN(partial_store_, STATE_T)
#define PARTIAL_LOAD_FN JOIN(partial_load_, STATE_T)
#define OR_STATE JOIN(or_, STATE_T)
@@ -53,24 +53,24 @@
#define ISZERO_STATE JOIN(isZero_, STATE_T)
static really_inline
-const ENG_STATE_T *get_reach_table(const IMPL_NFA_T *limex) {
- const ENG_STATE_T *reach
- = (const ENG_STATE_T *)((const char *)limex + sizeof(*limex));
- assert(ISALIGNED_N(reach, alignof(ENG_STATE_T)));
- return reach;
+const ENG_STATE_T *get_reach_table(const IMPL_NFA_T *limex) {
+ const ENG_STATE_T *reach
+ = (const ENG_STATE_T *)((const char *)limex + sizeof(*limex));
+ assert(ISALIGNED_N(reach, alignof(ENG_STATE_T)));
+ return reach;
+}
+
+static really_inline
+STATE_T REACHMASK_FN(const IMPL_NFA_T *limex, const u8 key) {
+ const ENG_STATE_T *reach = get_reach_table(limex);
+ return LOAD_FROM_ENG(&reach[limex->reachMap[key]]);
}
static really_inline
-STATE_T REACHMASK_FN(const IMPL_NFA_T *limex, const u8 key) {
- const ENG_STATE_T *reach = get_reach_table(limex);
- return LOAD_FROM_ENG(&reach[limex->reachMap[key]]);
-}
-
-static really_inline
void COMPRESS_FN(const IMPL_NFA_T *limex, u8 *dest, const STATE_T *src,
u8 key) {
assert(ISALIGNED_N(src, alignof(STATE_T)));
- STATE_T a_src = *src;
+ STATE_T a_src = *src;
DEBUG_PRINTF("compress state: %p -> %p\n", src, dest);
@@ -81,30 +81,30 @@ void COMPRESS_FN(const IMPL_NFA_T *limex, u8 *dest, const STATE_T *src,
} else {
DEBUG_PRINTF("compress state, key=%hhx\n", key);
- STATE_T reachmask = REACHMASK_FN(limex, key);
+ STATE_T reachmask = REACHMASK_FN(limex, key);
// Masked compression means that we mask off the initDs states and
// provide a shortcut for the all-zeroes case. Note that these must be
// switched on in the EXPAND call below.
if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
- STATE_T s = AND_STATE(LOAD_FROM_ENG(&limex->compressMask), a_src);
+ STATE_T s = AND_STATE(LOAD_FROM_ENG(&limex->compressMask), a_src);
if (ISZERO_STATE(s)) {
DEBUG_PRINTF("after compression mask, all states are zero\n");
memset(dest, 0, limex->stateSize);
return;
}
- STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
- reachmask);
+ STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
+ reachmask);
COMPRESSED_STORE_FN(dest, &s, &mask, limex->stateSize);
} else {
- COMPRESSED_STORE_FN(dest, src, &reachmask, limex->stateSize);
+ COMPRESSED_STORE_FN(dest, src, &reachmask, limex->stateSize);
}
}
}
static really_inline
-void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src, u8 key) {
+void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src, u8 key) {
assert(ISALIGNED_N(dest, alignof(STATE_T)));
DEBUG_PRINTF("expand state: %p -> %p\n", src, dest);
@@ -114,15 +114,15 @@ void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src, u8 key) {
*dest = PARTIAL_LOAD_FN(src, limex->stateSize);
} else {
DEBUG_PRINTF("expand state, key=%hhx\n", key);
- STATE_T reachmask = REACHMASK_FN(limex, key);
+ STATE_T reachmask = REACHMASK_FN(limex, key);
if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
- STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
- reachmask);
+ STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
+ reachmask);
COMPRESSED_LOAD_FN(dest, src, &mask, limex->stateSize);
- *dest = OR_STATE(LOAD_FROM_ENG(&limex->initDS), *dest);
+ *dest = OR_STATE(LOAD_FROM_ENG(&limex->initDS), *dest);
} else {
- COMPRESSED_LOAD_FN(dest, src, &reachmask, limex->stateSize);
+ COMPRESSED_LOAD_FN(dest, src, &reachmask, limex->stateSize);
}
}
}
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellan.c b/contrib/libs/hyperscan/src/nfa/mcclellan.c
index 9f79ae1fc05..71f71e32750 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellan.c
+++ b/contrib/libs/hyperscan/src/nfa/mcclellan.c
@@ -42,13 +42,13 @@
static really_inline
char doComplexReport(NfaCallback cb, void *ctxt, const struct mcclellan *m,
- u32 s, u64a loc, char eod, u32 *cached_accept_state,
- u32 *cached_accept_id) {
- DEBUG_PRINTF("reporting state = %u, loc=%llu, eod %hhu\n",
- s & STATE_MASK, loc, eod);
+ u32 s, u64a loc, char eod, u32 *cached_accept_state,
+ u32 *cached_accept_id) {
+ DEBUG_PRINTF("reporting state = %u, loc=%llu, eod %hhu\n",
+ s & STATE_MASK, loc, eod);
if (!eod && s == *cached_accept_state) {
- if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
+ if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING; /* termination requested */
}
@@ -71,7 +71,7 @@ char doComplexReport(NfaCallback cb, void *ctxt, const struct mcclellan *m,
*cached_accept_id = rl->report[0];
DEBUG_PRINTF("reporting %u\n", rl->report[0]);
- if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
+ if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING; /* termination requested */
}
@@ -80,7 +80,7 @@ char doComplexReport(NfaCallback cb, void *ctxt, const struct mcclellan *m,
for (u32 i = 0; i < count; i++) {
DEBUG_PRINTF("reporting %u\n", rl->report[i]);
- if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
+ if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
return MO_HALT_MATCHING; /* termination requested */
}
}
@@ -89,84 +89,84 @@ char doComplexReport(NfaCallback cb, void *ctxt, const struct mcclellan *m,
}
static really_inline
-const u8 *run_mcclellan_accel(const struct mcclellan *m,
- const struct mstate_aux *aux, u32 s,
- const u8 **min_accel_offset,
- const u8 *c, const u8 *c_end) {
- DEBUG_PRINTF("skipping\n");
- u32 accel_offset = aux[s].accel_offset;
-
- assert(aux[s].accel_offset);
- assert(accel_offset >= m->aux_offset);
- assert(!m->sherman_offset || accel_offset < m->sherman_offset);
-
- const union AccelAux *aaux = (const void *)((const char *)m + accel_offset);
- const u8 *c2 = run_accel(aaux, c, c_end);
-
- if (c2 < *min_accel_offset + BAD_ACCEL_DIST) {
- *min_accel_offset = c2 + BIG_ACCEL_PENALTY;
- } else {
- *min_accel_offset = c2 + SMALL_ACCEL_PENALTY;
- }
-
- if (*min_accel_offset >= c_end - ACCEL_MIN_LEN) {
- *min_accel_offset = c_end;
- }
-
- DEBUG_PRINTF("advanced %zd, next accel chance in %zd/%zd\n",
- c2 - c, *min_accel_offset - c2, c_end - c2);
-
- return c2;
-}
-
-static really_inline
-u32 doNormal16(const struct mcclellan *m, const u8 **c_inout, const u8 *end,
- u32 s, char do_accel, enum MatchMode mode) {
- const u8 *c = *c_inout;
-
- const u16 *succ_table
- = (const u16 *)((const char *)m + sizeof(struct mcclellan));
+const u8 *run_mcclellan_accel(const struct mcclellan *m,
+ const struct mstate_aux *aux, u32 s,
+ const u8 **min_accel_offset,
+ const u8 *c, const u8 *c_end) {
+ DEBUG_PRINTF("skipping\n");
+ u32 accel_offset = aux[s].accel_offset;
+
+ assert(aux[s].accel_offset);
+ assert(accel_offset >= m->aux_offset);
+ assert(!m->sherman_offset || accel_offset < m->sherman_offset);
+
+ const union AccelAux *aaux = (const void *)((const char *)m + accel_offset);
+ const u8 *c2 = run_accel(aaux, c, c_end);
+
+ if (c2 < *min_accel_offset + BAD_ACCEL_DIST) {
+ *min_accel_offset = c2 + BIG_ACCEL_PENALTY;
+ } else {
+ *min_accel_offset = c2 + SMALL_ACCEL_PENALTY;
+ }
+
+ if (*min_accel_offset >= c_end - ACCEL_MIN_LEN) {
+ *min_accel_offset = c_end;
+ }
+
+ DEBUG_PRINTF("advanced %zd, next accel chance in %zd/%zd\n",
+ c2 - c, *min_accel_offset - c2, c_end - c2);
+
+ return c2;
+}
+
+static really_inline
+u32 doNormal16(const struct mcclellan *m, const u8 **c_inout, const u8 *end,
+ u32 s, char do_accel, enum MatchMode mode) {
+ const u8 *c = *c_inout;
+
+ const u16 *succ_table
+ = (const u16 *)((const char *)m + sizeof(struct mcclellan));
assert(ISALIGNED_N(succ_table, 2));
- u32 sherman_base = m->sherman_limit;
+ u32 sherman_base = m->sherman_limit;
const char *sherman_base_offset
= (const char *)m - sizeof(struct NFA) + m->sherman_offset;
- u32 as = m->alphaShift;
+ u32 as = m->alphaShift;
s &= STATE_MASK;
- while (c < end && s) {
- u8 cprime = m->remap[*c];
- DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx (s=%u)\n", *c,
- ourisprint(*c) ? *c : '?', cprime, s);
- if (s < sherman_base) {
- DEBUG_PRINTF("doing normal\n");
- assert(s < m->state_count);
- s = succ_table[(s << as) + cprime];
- } else {
- const char *sherman_state
- = findShermanState(m, sherman_base_offset, sherman_base, s);
- DEBUG_PRINTF("doing sherman (%u)\n", s);
- s = doSherman16(sherman_state, cprime, succ_table, as);
- }
-
- DEBUG_PRINTF("s: %u (%u)\n", s, s & STATE_MASK);
- c++;
-
- if (do_accel && (s & ACCEL_FLAG)) {
- break;
- }
- if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
- break;
- }
-
- s &= STATE_MASK;
- }
-
- *c_inout = c;
- return s;
-}
-
-static really_inline
+ while (c < end && s) {
+ u8 cprime = m->remap[*c];
+ DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx (s=%u)\n", *c,
+ ourisprint(*c) ? *c : '?', cprime, s);
+ if (s < sherman_base) {
+ DEBUG_PRINTF("doing normal\n");
+ assert(s < m->state_count);
+ s = succ_table[(s << as) + cprime];
+ } else {
+ const char *sherman_state
+ = findShermanState(m, sherman_base_offset, sherman_base, s);
+ DEBUG_PRINTF("doing sherman (%u)\n", s);
+ s = doSherman16(sherman_state, cprime, succ_table, as);
+ }
+
+ DEBUG_PRINTF("s: %u (%u)\n", s, s & STATE_MASK);
+ c++;
+
+ if (do_accel && (s & ACCEL_FLAG)) {
+ break;
+ }
+ if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
+ break;
+ }
+
+ s &= STATE_MASK;
+ }
+
+ *c_inout = c;
+ return s;
+}
+
+static really_inline
u32 doNormalWide16(const struct mcclellan *m, const u8 **c_inout,
const u8 *end, u32 s, char *qstate, u16 *offset,
char do_accel, enum MatchMode mode) {
@@ -229,28 +229,28 @@ char mcclellanExec16_i(const struct mcclellan *m, u32 *state, char *qstate,
const u8 *buf, size_t len, u64a offAdj, NfaCallback cb,
void *ctxt, char single, const u8 **c_final,
enum MatchMode mode) {
- assert(ISALIGNED_N(state, 2));
- if (!len) {
- if (mode == STOP_AT_MATCH) {
- *c_final = buf;
- }
- return MO_ALIVE;
- }
-
- u32 s = *state;
+ assert(ISALIGNED_N(state, 2));
+ if (!len) {
+ if (mode == STOP_AT_MATCH) {
+ *c_final = buf;
+ }
+ return MO_ALIVE;
+ }
+
+ u32 s = *state;
u16 offset = 0;
- const u8 *c = buf;
- const u8 *c_end = buf + len;
- const struct mstate_aux *aux
- = (const struct mstate_aux *)((const char *)m + m->aux_offset
- - sizeof(struct NFA));
-
- s &= STATE_MASK;
-
+ const u8 *c = buf;
+ const u8 *c_end = buf + len;
+ const struct mstate_aux *aux
+ = (const struct mstate_aux *)((const char *)m + m->aux_offset
+ - sizeof(struct NFA));
+
+ s &= STATE_MASK;
+
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
- DEBUG_PRINTF("s: %u, len %zu\n", s, len);
+ DEBUG_PRINTF("s: %u, len %zu\n", s, len);
const u8 *min_accel_offset = c;
if (!m->has_accel || len < ACCEL_MIN_LEN) {
@@ -261,10 +261,10 @@ char mcclellanExec16_i(const struct mcclellan *m, u32 *state, char *qstate,
goto with_accel;
without_accel:
- do {
- assert(c < min_accel_offset);
- if (!s) {
- goto exit;
+ do {
+ assert(c < min_accel_offset);
+ if (!s) {
+ goto exit;
}
if (unlikely(m->has_wide)) {
@@ -273,96 +273,96 @@ without_accel:
} else {
s = doNormal16(m, &c, min_accel_offset, s, 0, mode);
}
-
+
if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
if (mode == STOP_AT_MATCH) {
*state = s & STATE_MASK;
*c_final = c - 1;
- return MO_MATCHES_PENDING;
+ return MO_MATCHES_PENDING;
}
u64a loc = (c - 1) - buf + offAdj + 1;
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD; /* termination requested */
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD; /* termination requested */
}
} else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
}
}
- assert(c <= min_accel_offset);
- } while (c < min_accel_offset);
-
- s &= STATE_MASK;
-
- if (c == c_end) {
- goto exit;
- } else {
- goto with_accel;
+ assert(c <= min_accel_offset);
+ } while (c < min_accel_offset);
+
+ s &= STATE_MASK;
+
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto with_accel;
}
with_accel:
- do {
- assert(c < c_end);
- if (!s) {
- goto exit;
+ do {
+ assert(c < c_end);
+ if (!s) {
+ goto exit;
+ }
+
+ if (s & ACCEL_FLAG) {
+ DEBUG_PRINTF("skipping\n");
+ s &= STATE_MASK;
+ c = run_mcclellan_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
}
- if (s & ACCEL_FLAG) {
- DEBUG_PRINTF("skipping\n");
- s &= STATE_MASK;
- c = run_mcclellan_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
-
if (unlikely(m->has_wide)) {
s = doNormalWide16(m, &c, c_end, s, qstate, &offset, 1, mode);
} else {
s = doNormal16(m, &c, c_end, s, 1, mode);
}
-
+
if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
if (mode == STOP_AT_MATCH) {
*state = s & STATE_MASK;
*c_final = c - 1;
- return MO_MATCHES_PENDING;
+ return MO_MATCHES_PENDING;
}
u64a loc = (c - 1) - buf + offAdj + 1;
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD; /* termination requested */
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD; /* termination requested */
}
} else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
}
- }
+ }
- assert(c <= c_end);
- } while (c < c_end);
+ assert(c <= c_end);
+ } while (c < c_end);
-exit:
- s &= STATE_MASK;
+exit:
+ s &= STATE_MASK;
if (mode == STOP_AT_MATCH) {
*c_final = c_end;
}
*state = s;
- return MO_ALIVE;
+ return MO_ALIVE;
}
static never_inline
@@ -404,69 +404,69 @@ char mcclellanExec16_i_ni(const struct mcclellan *m, u32 *state, char *qstate,
return mcclellanExec16_i_sam(m, state, qstate, buf, len, offAdj, cb,
ctxt, single, final_point);
} else {
- assert(mode == NO_MATCHES);
+ assert(mode == NO_MATCHES);
return mcclellanExec16_i_nm(m, state, qstate, buf, len, offAdj, cb,
ctxt, single, final_point);
}
}
static really_inline
-u32 doNormal8(const struct mcclellan *m, const u8 **c_inout, const u8 *end,
- u32 s, char do_accel, enum MatchMode mode) {
- const u8 *c = *c_inout;
- u32 accel_limit = m->accel_limit_8;
- u32 accept_limit = m->accept_limit_8;
-
- const u32 as = m->alphaShift;
+u32 doNormal8(const struct mcclellan *m, const u8 **c_inout, const u8 *end,
+ u32 s, char do_accel, enum MatchMode mode) {
+ const u8 *c = *c_inout;
+ u32 accel_limit = m->accel_limit_8;
+ u32 accept_limit = m->accept_limit_8;
+
+ const u32 as = m->alphaShift;
const u8 *succ_table = (const u8 *)((const char *)m
+ sizeof(struct mcclellan));
- while (c < end && s) {
- u8 cprime = m->remap[*c];
- DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx\n", *c,
- ourisprint(*c) ? *c : '?', cprime);
- s = succ_table[(s << as) + cprime];
-
- DEBUG_PRINTF("s: %u\n", s);
- c++;
- if (do_accel) {
- if (s >= accel_limit) {
- break;
- }
- } else {
- if (mode != NO_MATCHES && s >= accept_limit) {
- break;
- }
- }
- }
- *c_inout = c;
- return s;
-}
-
-static really_inline
-char mcclellanExec8_i(const struct mcclellan *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **c_final, enum MatchMode mode) {
- if (!len) {
- if (mode == STOP_AT_MATCH) {
- *c_final = buf;
- }
- return MO_ALIVE;
- }
- u32 s = *state;
- const u8 *c = buf;
- const u8 *c_end = buf + len;
-
- const struct mstate_aux *aux
- = (const struct mstate_aux *)((const char *)m + m->aux_offset
+ while (c < end && s) {
+ u8 cprime = m->remap[*c];
+ DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx\n", *c,
+ ourisprint(*c) ? *c : '?', cprime);
+ s = succ_table[(s << as) + cprime];
+
+ DEBUG_PRINTF("s: %u\n", s);
+ c++;
+ if (do_accel) {
+ if (s >= accel_limit) {
+ break;
+ }
+ } else {
+ if (mode != NO_MATCHES && s >= accept_limit) {
+ break;
+ }
+ }
+ }
+ *c_inout = c;
+ return s;
+}
+
+static really_inline
+char mcclellanExec8_i(const struct mcclellan *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **c_final, enum MatchMode mode) {
+ if (!len) {
+ if (mode == STOP_AT_MATCH) {
+ *c_final = buf;
+ }
+ return MO_ALIVE;
+ }
+ u32 s = *state;
+ const u8 *c = buf;
+ const u8 *c_end = buf + len;
+
+ const struct mstate_aux *aux
+ = (const struct mstate_aux *)((const char *)m + m->aux_offset
- sizeof(struct NFA));
- u32 accept_limit = m->accept_limit_8;
+ u32 accept_limit = m->accept_limit_8;
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
- DEBUG_PRINTF("accel %hu, accept %u\n", m->accel_limit_8, accept_limit);
+ DEBUG_PRINTF("accel %hu, accept %u\n", m->accel_limit_8, accept_limit);
- DEBUG_PRINTF("s: %u, len %zu\n", s, len);
+ DEBUG_PRINTF("s: %u, len %zu\n", s, len);
const u8 *min_accel_offset = c;
if (!m->has_accel || len < ACCEL_MIN_LEN) {
@@ -477,119 +477,119 @@ char mcclellanExec8_i(const struct mcclellan *m, u32 *state, const u8 *buf,
goto with_accel;
without_accel:
- do {
- assert(c < min_accel_offset);
- if (!s) {
- goto exit;
- }
-
- s = doNormal8(m, &c, min_accel_offset, s, 0, mode);
-
+ do {
+ assert(c < min_accel_offset);
+ if (!s) {
+ goto exit;
+ }
+
+ s = doNormal8(m, &c, min_accel_offset, s, 0, mode);
+
if (mode != NO_MATCHES && s >= accept_limit) {
if (mode == STOP_AT_MATCH) {
DEBUG_PRINTF("match - pausing\n");
*state = s;
*c_final = c - 1;
- return MO_MATCHES_PENDING;
+ return MO_MATCHES_PENDING;
}
u64a loc = (c - 1) - buf + offAdj + 1;
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD;
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD;
}
} else if (doComplexReport(cb, ctxt, m, s, loc, 0,
- &cached_accept_state, &cached_accept_id)
+ &cached_accept_state, &cached_accept_id)
== MO_HALT_MATCHING) {
- return MO_DEAD;
+ return MO_DEAD;
}
}
-
- assert(c <= min_accel_offset);
- } while (c < min_accel_offset);
-
- if (c == c_end) {
- goto exit;
+
+ assert(c <= min_accel_offset);
+ } while (c < min_accel_offset);
+
+ if (c == c_end) {
+ goto exit;
}
with_accel:
- do {
- u32 accel_limit = m->accel_limit_8;
- assert(c < c_end);
-
- if (!s) {
- goto exit;
- }
-
- if (s >= accel_limit && aux[s].accel_offset) {
- c = run_mcclellan_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
- s = doNormal8(m, &c, c_end, s, 1, mode);
-
- if (mode != NO_MATCHES && s >= accept_limit) {
- if (mode == STOP_AT_MATCH) {
- DEBUG_PRINTF("match - pausing\n");
- *state = s;
- *c_final = c - 1;
- return MO_MATCHES_PENDING;
- }
-
- u64a loc = (c - 1) - buf + offAdj + 1;
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD;
+ do {
+ u32 accel_limit = m->accel_limit_8;
+ assert(c < c_end);
+
+ if (!s) {
+ goto exit;
+ }
+
+ if (s >= accel_limit && aux[s].accel_offset) {
+ c = run_mcclellan_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
+ }
+ s = doNormal8(m, &c, c_end, s, 1, mode);
+
+ if (mode != NO_MATCHES && s >= accept_limit) {
+ if (mode == STOP_AT_MATCH) {
+ DEBUG_PRINTF("match - pausing\n");
+ *state = s;
+ *c_final = c - 1;
+ return MO_MATCHES_PENDING;
+ }
+
+ u64a loc = (c - 1) - buf + offAdj + 1;
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD;
}
- } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
+ } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
}
}
- assert(c <= c_end);
- } while (c < c_end);
-
-exit:
+ assert(c <= c_end);
+ } while (c < c_end);
+
+exit:
*state = s;
if (mode == STOP_AT_MATCH) {
*c_final = c_end;
}
- return MO_ALIVE;
+ return MO_ALIVE;
}
static never_inline
-char mcclellanExec8_i_cb(const struct mcclellan *m, u32 *state, const u8 *buf,
+char mcclellanExec8_i_cb(const struct mcclellan *m, u32 *state, const u8 *buf,
size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
char single, const u8 **final_point) {
return mcclellanExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, CALLBACK_OUTPUT);
+ final_point, CALLBACK_OUTPUT);
}
static never_inline
-char mcclellanExec8_i_sam(const struct mcclellan *m, u32 *state, const u8 *buf,
+char mcclellanExec8_i_sam(const struct mcclellan *m, u32 *state, const u8 *buf,
size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
char single, const u8 **final_point) {
return mcclellanExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, STOP_AT_MATCH);
+ final_point, STOP_AT_MATCH);
}
static never_inline
-char mcclellanExec8_i_nm(const struct mcclellan *m, u32 *state, const u8 *buf,
+char mcclellanExec8_i_nm(const struct mcclellan *m, u32 *state, const u8 *buf,
size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
char single, const u8 **final_point) {
return mcclellanExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, NO_MATCHES);
+ final_point, NO_MATCHES);
}
static really_inline
-char mcclellanExec8_i_ni(const struct mcclellan *m, u32 *state, const u8 *buf,
+char mcclellanExec8_i_ni(const struct mcclellan *m, u32 *state, const u8 *buf,
size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
char single, const u8 **final_point,
enum MatchMode mode) {
@@ -607,7 +607,7 @@ char mcclellanExec8_i_ni(const struct mcclellan *m, u32 *state, const u8 *buf,
}
static really_inline
-char mcclellanCheckEOD(const struct NFA *nfa, u32 s, u64a offset,
+char mcclellanCheckEOD(const struct NFA *nfa, u32 s, u64a offset,
NfaCallback cb, void *ctxt) {
const struct mcclellan *m = getImplNfa(nfa);
const struct mstate_aux *aux = get_aux(m, s);
@@ -616,10 +616,10 @@ char mcclellanCheckEOD(const struct NFA *nfa, u32 s, u64a offset,
return MO_CONTINUE_MATCHING;
}
- if (!aux->accept_eod) {
- return MO_CONTINUE_MATCHING;
+ if (!aux->accept_eod) {
+ return MO_CONTINUE_MATCHING;
}
- return doComplexReport(cb, ctxt, m, s, offset, 1, NULL, NULL);
+ return doComplexReport(cb, ctxt, m, s, offset, 1, NULL, NULL);
}
static really_inline
@@ -632,7 +632,7 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
s64a sp;
assert(ISALIGNED_N(q->state, 2));
- u32 s = *(u16 *)q->state;
+ u32 s = *(u16 *)q->state;
if (q->report_current) {
assert(s);
@@ -641,10 +641,10 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
int rv;
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- rv = cb(0, q_cur_offset(q), m->arb_report, context);
+ rv = cb(0, q_cur_offset(q), m->arb_report, context);
} else {
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
&cached_accept_state, &cached_accept_id);
@@ -653,7 +653,7 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
q->report_current = 0;
if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
+ return MO_DEAD;
}
}
@@ -691,17 +691,17 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
char rv = mcclellanExec16_i_ni(m, &s, q->state, cur_buf + sp,
local_ep - sp, offset + sp, cb, context,
single, &final_look, mode);
- if (rv == MO_DEAD) {
+ if (rv == MO_DEAD) {
*(u16 *)q->state = 0;
- return MO_DEAD;
+ return MO_DEAD;
}
- if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
+ if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
DEBUG_PRINTF("this is as far as we go\n");
- DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
-
+ DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
+
assert(q->cur);
- assert(final_look != cur_buf + local_ep);
-
+ assert(final_look != cur_buf + local_ep);
+
q->cur--;
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = final_look - cur_buf + 1; /* due to
@@ -710,7 +710,7 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
return MO_MATCHES_PENDING;
}
- assert(rv == MO_ALIVE);
+ assert(rv == MO_ALIVE);
assert(q->cur);
if (mode != NO_MATCHES && q->items[q->cur].location > end) {
DEBUG_PRINTF("this is as far as we go\n");
@@ -743,7 +743,7 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
case MQE_END:
*(u16 *)q->state = s;
q->cur++;
- return s ? MO_ALIVE : MO_DEAD;
+ return s ? MO_ALIVE : MO_DEAD;
default:
assert(!"invalid queue event");
}
@@ -752,18 +752,18 @@ char nfaExecMcClellan16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
}
}
-static really_inline
-char nfaExecMcClellan16_Bi(const struct NFA *n, u64a offset, const u8 *buffer,
- size_t length, NfaCallback cb, void *context,
- char single) {
+static really_inline
+char nfaExecMcClellan16_Bi(const struct NFA *n, u64a offset, const u8 *buffer,
+ size_t length, NfaCallback cb, void *context,
+ char single) {
assert(n->type == MCCLELLAN_NFA_16);
const struct mcclellan *m = getImplNfa(n);
- u32 s = m->start_anchored;
+ u32 s = m->start_anchored;
if (mcclellanExec16_i(m, &s, NULL, buffer, length, offset, cb, context,
single, NULL, CALLBACK_OUTPUT)
- == MO_DEAD) {
- return s ? MO_ALIVE : MO_DEAD;
+ == MO_DEAD) {
+ return s ? MO_ALIVE : MO_DEAD;
}
if (m->has_wide == 1 && s >= m->wide_limit) {
@@ -776,19 +776,19 @@ char nfaExecMcClellan16_Bi(const struct NFA *n, u64a offset, const u8 *buffer,
doComplexReport(cb, context, m, s, offset + length, 1, NULL, NULL);
}
- return MO_ALIVE;
+ return MO_ALIVE;
}
static really_inline
char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
- const u8 *hend, NfaCallback cb, void *context,
- struct mq *q, char single, s64a end,
- enum MatchMode mode) {
+ const u8 *hend, NfaCallback cb, void *context,
+ struct mq *q, char single, s64a end,
+ enum MatchMode mode) {
assert(n->type == MCCLELLAN_NFA_8);
const struct mcclellan *m = getImplNfa(n);
s64a sp;
- u32 s = *(u8 *)q->state;
+ u32 s = *(u8 *)q->state;
if (q->report_current) {
assert(s);
@@ -797,10 +797,10 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
int rv;
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- rv = cb(0, q_cur_offset(q), m->arb_report, context);
+ rv = cb(0, q_cur_offset(q), m->arb_report, context);
} else {
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
&cached_accept_state, &cached_accept_id);
@@ -809,7 +809,7 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
q->report_current = 0;
if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
+ return MO_DEAD;
}
}
@@ -845,21 +845,21 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
}
const u8 *final_look;
- char rv = mcclellanExec8_i_ni(m, &s, cur_buf + sp, local_ep - sp,
- offset + sp, cb, context, single,
- &final_look, mode);
+ char rv = mcclellanExec8_i_ni(m, &s, cur_buf + sp, local_ep - sp,
+ offset + sp, cb, context, single,
+ &final_look, mode);
- if (rv == MO_HALT_MATCHING) {
+ if (rv == MO_HALT_MATCHING) {
*(u8 *)q->state = 0;
- return MO_DEAD;
+ return MO_DEAD;
}
- if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
- DEBUG_PRINTF("this is as far as we go\n");
- DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
-
+ if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
+
assert(q->cur);
- assert(final_look != cur_buf + local_ep);
-
+ assert(final_look != cur_buf + local_ep);
+
q->cur--;
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = final_look - cur_buf + 1; /* due to
@@ -868,7 +868,7 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
return MO_MATCHES_PENDING;
}
- assert(rv == MO_ALIVE);
+ assert(rv == MO_ALIVE);
assert(q->cur);
if (mode != NO_MATCHES && q->items[q->cur].location > end) {
DEBUG_PRINTF("this is as far as we go\n");
@@ -902,7 +902,7 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
case MQE_END:
*(u8 *)q->state = s;
q->cur++;
- return s ? MO_ALIVE : MO_DEAD;
+ return s ? MO_ALIVE : MO_DEAD;
default:
assert(!"invalid queue event");
}
@@ -911,18 +911,18 @@ char nfaExecMcClellan8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
}
}
-static really_inline
+static really_inline
char nfaExecMcClellan8_Bi(const struct NFA *n, u64a offset, const u8 *buffer,
size_t length, NfaCallback cb, void *context,
char single) {
assert(n->type == MCCLELLAN_NFA_8);
const struct mcclellan *m = getImplNfa(n);
- u32 s = m->start_anchored;
+ u32 s = m->start_anchored;
if (mcclellanExec8_i(m, &s, buffer, length, offset, cb, context, single,
NULL, CALLBACK_OUTPUT)
- == MO_DEAD) {
- return MO_DEAD;
+ == MO_DEAD) {
+ return MO_DEAD;
}
const struct mstate_aux *aux = get_aux(m, s);
@@ -931,7 +931,7 @@ char nfaExecMcClellan8_Bi(const struct NFA *n, u64a offset, const u8 *buffer,
doComplexReport(cb, context, m, s, offset + length, 1, NULL, NULL);
}
- return s ? MO_ALIVE : MO_DEAD;
+ return s ? MO_ALIVE : MO_DEAD;
}
char nfaExecMcClellan8_B(const struct NFA *n, u64a offset, const u8 *buffer,
@@ -990,7 +990,7 @@ char nfaExecMcClellan8_reportCurrent(const struct NFA *n, struct mq *q) {
const struct mcclellan *m = getImplNfa(n);
NfaCallback cb = q->cb;
void *ctxt = q->context;
- u32 s = *(u8 *)q->state;
+ u32 s = *(u8 *)q->state;
u8 single = m->flags & MCCLELLAN_FLAG_SINGLE;
u64a offset = q_cur_offset(q);
assert(q_cur_type(q) == MQE_START);
@@ -999,10 +999,10 @@ char nfaExecMcClellan8_reportCurrent(const struct NFA *n, struct mq *q) {
if (s >= m->accept_limit_8) {
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- cb(0, offset, m->arb_report, ctxt);
+ cb(0, offset, m->arb_report, ctxt);
} else {
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
&cached_accept_id);
@@ -1013,24 +1013,24 @@ char nfaExecMcClellan8_reportCurrent(const struct NFA *n, struct mq *q) {
}
char nfaExecMcClellan16_reportCurrent(const struct NFA *n, struct mq *q) {
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
NfaCallback cb = q->cb;
void *ctxt = q->context;
- u32 s = *(u16 *)q->state;
+ u32 s = *(u16 *)q->state;
const struct mstate_aux *aux = get_aux(m, s);
u8 single = m->flags & MCCLELLAN_FLAG_SINGLE;
u64a offset = q_cur_offset(q);
assert(q_cur_type(q) == MQE_START);
- DEBUG_PRINTF("state %u\n", s);
+ DEBUG_PRINTF("state %u\n", s);
assert(s);
if (aux->accept) {
if (single) {
DEBUG_PRINTF("reporting %u\n", m->arb_report);
- cb(0, offset, m->arb_report, ctxt);
+ cb(0, offset, m->arb_report, ctxt);
} else {
u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
+ u32 cached_accept_state = 0;
doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
&cached_accept_id);
@@ -1068,7 +1068,7 @@ char nfaExecMcClellan8_inAccept(const struct NFA *n, ReportID report,
struct mq *q) {
assert(n && q);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
u8 s = *(u8 *)q->state;
DEBUG_PRINTF("checking accepts for %hhu\n", s);
if (s < m->accept_limit_8) {
@@ -1078,22 +1078,22 @@ char nfaExecMcClellan8_inAccept(const struct NFA *n, ReportID report,
return mcclellanHasAccept(m, get_aux(m, s), report);
}
-char nfaExecMcClellan8_inAnyAccept(const struct NFA *n, struct mq *q) {
- assert(n && q);
-
- const struct mcclellan *m = getImplNfa(n);
- u8 s = *(u8 *)q->state;
- DEBUG_PRINTF("checking accepts for %hhu\n", s);
- assert(s < m->accept_limit_8 || get_aux(m, s)->accept);
-
- return s >= m->accept_limit_8;
-}
-
+char nfaExecMcClellan8_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+
+ const struct mcclellan *m = getImplNfa(n);
+ u8 s = *(u8 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hhu\n", s);
+ assert(s < m->accept_limit_8 || get_aux(m, s)->accept);
+
+ return s >= m->accept_limit_8;
+}
+
char nfaExecMcClellan16_inAccept(const struct NFA *n, ReportID report,
struct mq *q) {
assert(n && q);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
u16 s = *(u16 *)q->state;
DEBUG_PRINTF("checking accepts for %hu\n", s);
@@ -1101,24 +1101,24 @@ char nfaExecMcClellan16_inAccept(const struct NFA *n, ReportID report,
0 : mcclellanHasAccept(m, get_aux(m, s), report);
}
-char nfaExecMcClellan16_inAnyAccept(const struct NFA *n, struct mq *q) {
- assert(n && q);
-
- const struct mcclellan *m = getImplNfa(n);
- u16 s = *(u16 *)q->state;
- DEBUG_PRINTF("checking accepts for %hu\n", s);
-
+char nfaExecMcClellan16_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+
+ const struct mcclellan *m = getImplNfa(n);
+ u16 s = *(u16 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hu\n", s);
+
return (m->has_wide == 1 && s >= m->wide_limit) ?
0 : !!get_aux(m, s)->accept;
-}
-
+}
+
char nfaExecMcClellan8_Q2(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == MCCLELLAN_NFA_8);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
const u8 *hend = q->history + q->hlength;
return nfaExecMcClellan8_Q2i(n, offset, buffer, hend, cb, context, q,
@@ -1132,7 +1132,7 @@ char nfaExecMcClellan16_Q2(const struct NFA *n, struct mq *q, s64a end) {
NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == MCCLELLAN_NFA_16);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
const u8 *hend = q->history + q->hlength;
return nfaExecMcClellan16_Q2i(n, offset, buffer, hend, cb, context, q,
@@ -1146,7 +1146,7 @@ char nfaExecMcClellan8_QR(const struct NFA *n, struct mq *q, ReportID report) {
NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == MCCLELLAN_NFA_8);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
const u8 *hend = q->history + q->hlength;
char rv = nfaExecMcClellan8_Q2i(n, offset, buffer, hend, cb, context, q,
@@ -1165,7 +1165,7 @@ char nfaExecMcClellan16_QR(const struct NFA *n, struct mq *q, ReportID report) {
NfaCallback cb = q->cb;
void *context = q->context;
assert(n->type == MCCLELLAN_NFA_16);
- const struct mcclellan *m = getImplNfa(n);
+ const struct mcclellan *m = getImplNfa(n);
const u8 *hend = q->history + q->hlength;
char rv = nfaExecMcClellan16_Q2i(n, offset, buffer, hend, cb, context, q,
@@ -1181,7 +1181,7 @@ char nfaExecMcClellan16_QR(const struct NFA *n, struct mq *q, ReportID report) {
char nfaExecMcClellan8_initCompressedState(const struct NFA *nfa, u64a offset,
void *state, UNUSED u8 key) {
- const struct mcclellan *m = getImplNfa(nfa);
+ const struct mcclellan *m = getImplNfa(nfa);
u8 s = offset ? m->start_floating : m->start_anchored;
if (s) {
*(u8 *)state = s;
@@ -1192,7 +1192,7 @@ char nfaExecMcClellan8_initCompressedState(const struct NFA *nfa, u64a offset,
char nfaExecMcClellan16_initCompressedState(const struct NFA *nfa, u64a offset,
void *state, UNUSED u8 key) {
- const struct mcclellan *m = getImplNfa(nfa);
+ const struct mcclellan *m = getImplNfa(nfa);
u16 s = offset ? m->start_floating : m->start_anchored;
// new byte
@@ -1210,30 +1210,30 @@ char nfaExecMcClellan16_initCompressedState(const struct NFA *nfa, u64a offset,
void nfaExecMcClellan8_SimpStream(const struct NFA *nfa, char *state,
const u8 *buf, char top, size_t start_off,
size_t len, NfaCallback cb, void *ctxt) {
- const struct mcclellan *m = getImplNfa(nfa);
+ const struct mcclellan *m = getImplNfa(nfa);
+
+ u32 s = top ? m->start_anchored : *(u8 *)state;
- u32 s = top ? m->start_anchored : *(u8 *)state;
-
if (m->flags & MCCLELLAN_FLAG_SINGLE) {
- mcclellanExec8_i(m, &s, buf + start_off, len - start_off,
+ mcclellanExec8_i(m, &s, buf + start_off, len - start_off,
start_off, cb, ctxt, 1, NULL, CALLBACK_OUTPUT);
} else {
- mcclellanExec8_i(m, &s, buf + start_off, len - start_off,
+ mcclellanExec8_i(m, &s, buf + start_off, len - start_off,
start_off, cb, ctxt, 0, NULL, CALLBACK_OUTPUT);
}
-
- *(u8 *)state = s;
+
+ *(u8 *)state = s;
}
void nfaExecMcClellan16_SimpStream(const struct NFA *nfa, char *state,
const u8 *buf, char top, size_t start_off,
size_t len, NfaCallback cb, void *ctxt) {
- const struct mcclellan *m = getImplNfa(nfa);
+ const struct mcclellan *m = getImplNfa(nfa);
u32 s;
if (top) {
s = m->start_anchored;
-
+
// new byte
if (m->has_wide) {
unaligned_store_u16((u16 *)state + 1, 0);
@@ -1244,39 +1244,39 @@ void nfaExecMcClellan16_SimpStream(const struct NFA *nfa, char *state,
if (m->flags & MCCLELLAN_FLAG_SINGLE) {
mcclellanExec16_i(m, &s, state, buf + start_off, len - start_off,
- start_off, cb, ctxt, 1, NULL, CALLBACK_OUTPUT);
+ start_off, cb, ctxt, 1, NULL, CALLBACK_OUTPUT);
} else {
mcclellanExec16_i(m, &s, state, buf + start_off, len - start_off,
- start_off, cb, ctxt, 0, NULL, CALLBACK_OUTPUT);
+ start_off, cb, ctxt, 0, NULL, CALLBACK_OUTPUT);
}
-
- unaligned_store_u16(state, s);
+
+ unaligned_store_u16(state, s);
}
char nfaExecMcClellan8_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
- return mcclellanCheckEOD(nfa, *(const u8 *)state, offset, callback,
- context);
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
+ return mcclellanCheckEOD(nfa, *(const u8 *)state, offset, callback,
+ context);
}
char nfaExecMcClellan16_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
assert(ISALIGNED_N(state, 2));
- return mcclellanCheckEOD(nfa, *(const u16 *)state, offset, callback,
- context);
+ return mcclellanCheckEOD(nfa, *(const u16 *)state, offset, callback,
+ context);
}
-char nfaExecMcClellan8_queueInitState(UNUSED const struct NFA *nfa,
- struct mq *q) {
+char nfaExecMcClellan8_queueInitState(UNUSED const struct NFA *nfa,
+ struct mq *q) {
assert(nfa->scratchStateSize == 1);
*(u8 *)q->state = 0;
return 0;
}
-char nfaExecMcClellan16_queueInitState(UNUSED const struct NFA *nfa,
- struct mq *q) {
+char nfaExecMcClellan16_queueInitState(UNUSED const struct NFA *nfa,
+ struct mq *q) {
const struct mcclellan *m = getImplNfa(nfa);
assert(m->has_wide == 1 ? nfa->scratchStateSize == 4
: nfa->scratchStateSize == 2);
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellan.h b/contrib/libs/hyperscan/src/nfa/mcclellan.h
index c26a7944f9e..9c6b3eecb16 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellan.h
+++ b/contrib/libs/hyperscan/src/nfa/mcclellan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,14 +39,14 @@ struct NFA;
char nfaExecMcClellan8_testEOD(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
char nfaExecMcClellan8_Q(const struct NFA *n, struct mq *q, s64a end);
char nfaExecMcClellan8_Q2(const struct NFA *n, struct mq *q, s64a end);
char nfaExecMcClellan8_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecMcClellan8_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecMcClellan8_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecMcClellan8_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecMcClellan8_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecMcClellan8_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecMcClellan8_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
@@ -62,14 +62,14 @@ char nfaExecMcClellan8_expandState(const struct NFA *nfa, void *dest,
char nfaExecMcClellan16_testEOD(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
char nfaExecMcClellan16_Q(const struct NFA *n, struct mq *q, s64a end);
char nfaExecMcClellan16_Q2(const struct NFA *n, struct mq *q, s64a end);
char nfaExecMcClellan16_QR(const struct NFA *n, struct mq *q, ReportID report);
char nfaExecMcClellan16_reportCurrent(const struct NFA *n, struct mq *q);
char nfaExecMcClellan16_inAccept(const struct NFA *n, ReportID report,
struct mq *q);
-char nfaExecMcClellan16_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecMcClellan16_inAnyAccept(const struct NFA *n, struct mq *q);
char nfaExecMcClellan16_queueInitState(const struct NFA *n, struct mq *q);
char nfaExecMcClellan16_initCompressedState(const struct NFA *n, u64a offset,
void *state, u8 key);
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellan_common_impl.h b/contrib/libs/hyperscan/src/nfa/mcclellan_common_impl.h
index ad55579627a..7b0e7f48cd8 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellan_common_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/mcclellan_common_impl.h
@@ -33,7 +33,7 @@ enum MatchMode {
};
static really_inline
-const struct mstate_aux *get_aux(const struct mcclellan *m, u32 s) {
+const struct mstate_aux *get_aux(const struct mcclellan *m, u32 s) {
const char *nfa = (const char *)m - sizeof(struct NFA);
const struct mstate_aux *aux
= s + (const struct mstate_aux *)(nfa + m->aux_offset);
@@ -43,15 +43,15 @@ const struct mstate_aux *get_aux(const struct mcclellan *m, u32 s) {
}
static really_inline
-u32 mcclellanEnableStarts(const struct mcclellan *m, u32 s) {
+u32 mcclellanEnableStarts(const struct mcclellan *m, u32 s) {
const struct mstate_aux *aux = get_aux(m, s);
- DEBUG_PRINTF("enabling starts %u->%hu\n", s, aux->top);
+ DEBUG_PRINTF("enabling starts %u->%hu\n", s, aux->top);
return aux->top;
}
static really_inline
-u32 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
+u32 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
u32 as) {
assert(ISALIGNED_N(sherman_state, 16));
@@ -70,17 +70,17 @@ u32 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
if (z) {
u32 i = ctz32(z & ~0xf) - 4;
- u32 s_out = unaligned_load_u16((const u8 *)sherman_state
+ u32 s_out = unaligned_load_u16((const u8 *)sherman_state
+ SHERMAN_STATES_OFFSET(len)
+ sizeof(u16) * i);
- DEBUG_PRINTF("found sherman match at %u/%u for c'=%hhu s=%u\n", i,
- len, cprime, s_out);
+ DEBUG_PRINTF("found sherman match at %u/%u for c'=%hhu s=%u\n", i,
+ len, cprime, s_out);
return s_out;
}
}
- u32 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
- return succ_table[(daddy << as) + cprime];
+ u32 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
+ return succ_table[(daddy << as) + cprime];
}
static really_inline
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellan_internal.h b/contrib/libs/hyperscan/src/nfa/mcclellan_internal.h
index c2571a0468d..482fdb1bc9e 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellan_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/mcclellan_internal.h
@@ -81,18 +81,18 @@ struct mcclellan {
u16 start_floating; /**< floating start state */
u32 aux_offset; /**< offset of the aux structures relative to the start of
* the nfa structure */
- u32 sherman_offset; /**< offset of array of sherman state offsets the
- * state_info structures relative to the start of the
- * nfa structure */
- u32 sherman_end; /**< offset of the end of the state_info structures
- * relative to the start of the nfa structure */
+ u32 sherman_offset; /**< offset of array of sherman state offsets the
+ * state_info structures relative to the start of the
+ * nfa structure */
+ u32 sherman_end; /**< offset of the end of the state_info structures
+ * relative to the start of the nfa structure */
u16 accel_limit_8; /**< 8 bit, lowest accelerable state */
u16 accept_limit_8; /**< 8 bit, lowest accept state */
u16 sherman_limit; /**< lowest sherman state */
u16 wide_limit; /**< 8/16 bit, lowest wide head state */
u8 alphaShift;
u8 flags;
- u8 has_accel; /**< 1 iff there are any accel plans */
+ u8 has_accel; /**< 1 iff there are any accel plans */
u8 has_wide; /**< 1 iff there exists any wide state */
u8 remap[256]; /**< remaps characters to a smaller alphabet */
ReportID arb_report; /**< one of the accepts that this dfa may raise */
@@ -104,8 +104,8 @@ struct mcclellan {
static really_inline
const char *findShermanState(UNUSED const struct mcclellan *m,
- const char *sherman_base_offset, u32 sherman_base,
- u32 s) {
+ const char *sherman_base_offset, u32 sherman_base,
+ u32 s) {
const char *rv
= sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
assert(rv < (const char *)m + m->length - sizeof(struct NFA));
@@ -116,7 +116,7 @@ const char *findShermanState(UNUSED const struct mcclellan *m,
static really_inline
char *findMutableShermanState(char *sherman_base_offset, u16 sherman_base,
- u32 s) {
+ u32 s) {
return sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
}
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellancompile.cpp b/contrib/libs/hyperscan/src/nfa/mcclellancompile.cpp
index ecfd636bbd2..27ec1716e94 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellancompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/mcclellancompile.cpp
@@ -29,10 +29,10 @@
#include "mcclellancompile.h"
#include "accel.h"
-#include "accelcompile.h"
+#include "accelcompile.h"
#include "grey.h"
#include "mcclellan_internal.h"
-#include "mcclellancompile_util.h"
+#include "mcclellancompile_util.h"
#include "nfa_internal.h"
#include "shufticompile.h"
#include "trufflecompile.h"
@@ -45,8 +45,8 @@
#include "util/container.h"
#include "util/make_unique.h"
#include "util/order_check.h"
-#include "util/report_manager.h"
-#include "util/flat_containers.h"
+#include "util/report_manager.h"
+#include "util/flat_containers.h"
#include "util/unaligned.h"
#include "util/verify_types.h"
@@ -60,40 +60,40 @@
#include <set>
#include <vector>
-#include <boost/range/adaptor/map.hpp>
-
+#include <boost/range/adaptor/map.hpp>
+
#include "mcclellandump.h"
#include "util/dump_util.h"
#include "util/dump_charclass.h"
using namespace std;
-using boost::adaptors::map_keys;
+using boost::adaptors::map_keys;
using boost::dynamic_bitset;
-#define ACCEL_DFA_MAX_OFFSET_DEPTH 4
+#define ACCEL_DFA_MAX_OFFSET_DEPTH 4
+
+/** Maximum tolerated number of escape character from an accel state.
+ * This is larger than nfa, as we don't have a budget and the nfa cheats on stop
+ * characters for sets of states */
+#define ACCEL_DFA_MAX_STOP_CHAR 160
-/** Maximum tolerated number of escape character from an accel state.
- * This is larger than nfa, as we don't have a budget and the nfa cheats on stop
- * characters for sets of states */
-#define ACCEL_DFA_MAX_STOP_CHAR 160
+/** Maximum tolerated number of escape character from a sds accel state. Larger
+ * than normal states as accelerating sds is important. Matches NFA value */
+#define ACCEL_DFA_MAX_FLOATING_STOP_CHAR 192
-/** Maximum tolerated number of escape character from a sds accel state. Larger
- * than normal states as accelerating sds is important. Matches NFA value */
-#define ACCEL_DFA_MAX_FLOATING_STOP_CHAR 192
+namespace ue2 {
-namespace ue2 {
-
namespace /* anon */ {
struct dstate_extra {
- u16 daddytaken = 0;
- bool shermanState = false;
+ u16 daddytaken = 0;
+ bool shermanState = false;
bool wideState = false;
bool wideHead = false;
};
struct dfa_info {
- accel_dfa_build_strat &strat;
+ accel_dfa_build_strat &strat;
raw_dfa &raw;
vector<dstate> &states;
vector<dstate_extra> extra;
@@ -105,7 +105,7 @@ struct dfa_info {
u8 getAlphaShift() const;
- explicit dfa_info(accel_dfa_build_strat &s)
+ explicit dfa_info(accel_dfa_build_strat &s)
: strat(s),
raw(s.get_raw()),
states(raw.states),
@@ -292,16 +292,16 @@ void markEdges(NFA *n, u16 *succ_table, const dfa_info &info) {
}
}
-u32 mcclellan_build_strat::max_allowed_offset_accel() const {
- return ACCEL_DFA_MAX_OFFSET_DEPTH;
+u32 mcclellan_build_strat::max_allowed_offset_accel() const {
+ return ACCEL_DFA_MAX_OFFSET_DEPTH;
}
-u32 mcclellan_build_strat::max_stop_char() const {
- return ACCEL_DFA_MAX_STOP_CHAR;
+u32 mcclellan_build_strat::max_stop_char() const {
+ return ACCEL_DFA_MAX_STOP_CHAR;
}
-u32 mcclellan_build_strat::max_floating_stop_char() const {
- return ACCEL_DFA_MAX_FLOATING_STOP_CHAR;
+u32 mcclellan_build_strat::max_floating_stop_char() const {
+ return ACCEL_DFA_MAX_FLOATING_STOP_CHAR;
}
static
@@ -359,16 +359,16 @@ namespace {
struct raw_report_list {
flat_set<ReportID> reports;
- raw_report_list(const flat_set<ReportID> &reports_in,
- const ReportManager &rm, bool do_remap) {
- if (do_remap) {
- for (auto &id : reports_in) {
- reports.insert(rm.getProgramOffset(id));
- }
- } else {
- reports = reports_in;
- }
- }
+ raw_report_list(const flat_set<ReportID> &reports_in,
+ const ReportManager &rm, bool do_remap) {
+ if (do_remap) {
+ for (auto &id : reports_in) {
+ reports.insert(rm.getProgramOffset(id));
+ }
+ } else {
+ reports = reports_in;
+ }
+ }
bool operator<(const raw_report_list &b) const {
return reports < b.reports;
@@ -391,8 +391,8 @@ unique_ptr<raw_report_info> mcclellan_build_strat::gatherReports(
ReportID *arbReport) const {
DEBUG_PRINTF("gathering reports\n");
- const bool remap_reports = has_managed_reports(rdfa.kind);
-
+ const bool remap_reports = has_managed_reports(rdfa.kind);
+
auto ri = ue2::make_unique<raw_report_info_impl>();
map<raw_report_list, u32> rev;
@@ -402,14 +402,14 @@ unique_ptr<raw_report_info> mcclellan_build_strat::gatherReports(
continue;
}
- raw_report_list rrl(s.reports, rm, remap_reports);
+ raw_report_list rrl(s.reports, rm, remap_reports);
DEBUG_PRINTF("non empty r\n");
- auto it = rev.find(rrl);
- if (it != rev.end()) {
- reports.push_back(it->second);
+ auto it = rev.find(rrl);
+ if (it != rev.end()) {
+ reports.push_back(it->second);
} else {
DEBUG_PRINTF("adding to rl %zu\n", ri->size());
- rev.emplace(rrl, ri->size());
+ rev.emplace(rrl, ri->size());
reports.push_back(ri->size());
ri->rl.push_back(rrl);
}
@@ -422,15 +422,15 @@ unique_ptr<raw_report_info> mcclellan_build_strat::gatherReports(
}
DEBUG_PRINTF("non empty r eod\n");
- raw_report_list rrl(s.reports_eod, rm, remap_reports);
- auto it = rev.find(rrl);
- if (it != rev.end()) {
- reports_eod.push_back(it->second);
+ raw_report_list rrl(s.reports_eod, rm, remap_reports);
+ auto it = rev.find(rrl);
+ if (it != rev.end()) {
+ reports_eod.push_back(it->second);
continue;
}
DEBUG_PRINTF("adding to rl eod %zu\n", s.reports_eod.size());
- rev.emplace(rrl, ri->size());
+ rev.emplace(rrl, ri->size());
reports_eod.push_back(ri->size());
ri->rl.push_back(rrl);
}
@@ -445,7 +445,7 @@ unique_ptr<raw_report_info> mcclellan_build_strat::gatherReports(
/* if we have only a single report id generated from all accepts (not eod)
* we can take some short cuts */
- flat_set<ReportID> reps;
+ flat_set<ReportID> reps;
for (u32 rl_index : reports) {
if (rl_index == MO_INVALID_IDX) {
@@ -500,14 +500,14 @@ void raw_report_info_impl::fillReportLists(NFA *n, size_t base_offset,
}
static
-void fillAccelOut(const map<dstate_id_t, AccelScheme> &accel_escape_info,
- set<dstate_id_t> *accel_states) {
- for (dstate_id_t i : accel_escape_info | map_keys) {
- accel_states->insert(i);
- }
-}
-
-static
+void fillAccelOut(const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ set<dstate_id_t> *accel_states) {
+ for (dstate_id_t i : accel_escape_info | map_keys) {
+ accel_states->insert(i);
+ }
+}
+
+static
size_t calcShermanRegionSize(const dfa_info &info) {
size_t rv = 0;
@@ -550,7 +550,7 @@ void fillInAux(mstate_aux *aux, dstate_id_t i, const dfa_info &info,
: info.raw.start_floating);
}
-/* returns false on error */
+/* returns false on error */
static
bool allocateFSN16(dfa_info &info, dstate_id_t *sherman_base,
dstate_id_t *wide_limit) {
@@ -564,7 +564,7 @@ bool allocateFSN16(dfa_info &info, dstate_id_t *sherman_base,
if (info.size() > (1 << 16)) {
DEBUG_PRINTF("too many states\n");
*wide_limit = 0;
- return false;
+ return false;
}
for (u32 i = 1; i < info.size(); i++) {
@@ -609,8 +609,8 @@ bool allocateFSN16(dfa_info &info, dstate_id_t *sherman_base,
}
static
-bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
- set<dstate_id_t> *accel_states) {
+bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
+ set<dstate_id_t> *accel_states) {
DEBUG_PRINTF("building mcclellan 16\n");
vector<u32> reports; /* index in ri for the appropriate report list */
@@ -632,9 +632,9 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
DEBUG_PRINTF("count_real_states: %d\n", count_real_states);
DEBUG_PRINTF("non_wide_states: %d\n", wide_limit);
- auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
- map<dstate_id_t, AccelScheme> accel_escape_info
- = info.strat.getAccelInfo(cc.grey);
+ auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
+ map<dstate_id_t, AccelScheme> accel_escape_info
+ = info.strat.getAccelInfo(cc.grey);
size_t tran_size = (1 << info.getAlphaShift())
* sizeof(u16) * count_real_states;
@@ -642,7 +642,7 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
size_t aux_size = sizeof(mstate_aux) * wide_limit;
size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcclellan) + tran_size);
- size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
+ size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
+ ri->getReportListSize(), 32);
size_t sherman_offset = ROUNDUP_16(accel_offset + accel_size);
@@ -665,11 +665,11 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
DEBUG_PRINTF("wide_size %zu\n", wide_size);
DEBUG_PRINTF("total_size %zu\n", total_size);
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
char *nfa_base = (char *)nfa.get();
populateBasicInfo(sizeof(u16), info, total_size, aux_offset, accel_offset,
- accel_escape_info.size(), arb, single, nfa.get());
+ accel_escape_info.size(), arb, single, nfa.get());
vector<u32> reportOffsets;
@@ -705,12 +705,12 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
fillInAux(&aux[fs], i, info, reports, reports_eod, reportOffsets);
- if (contains(accel_escape_info, i)) {
+ if (contains(accel_escape_info, i)) {
this_aux->accel_offset = accel_offset;
accel_offset += info.strat.accelSize();
assert(accel_offset + sizeof(NFA) <= sherman_offset);
assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
- info.strat.buildAccel(i, accel_escape_info.at(i),
+ info.strat.buildAccel(i, accel_escape_info.at(i),
(void *)((char *)m + this_aux->accel_offset));
}
}
@@ -735,12 +735,12 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
fillInAux(this_aux, i, info, reports, reports_eod, reportOffsets);
- if (contains(accel_escape_info, i)) {
+ if (contains(accel_escape_info, i)) {
this_aux->accel_offset = accel_offset;
accel_offset += info.strat.accelSize();
assert(accel_offset + sizeof(NFA) <= sherman_offset);
assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
- info.strat.buildAccel(i, accel_escape_info.at(i),
+ info.strat.buildAccel(i, accel_escape_info.at(i),
(void *)((char *)m + this_aux->accel_offset));
}
@@ -838,10 +838,10 @@ bytecode_ptr<NFA> mcclellanCompile16(dfa_info &info, const CompileContext &cc,
markEdges(nfa.get(), succ_table, info);
- if (accel_states && nfa) {
- fillAccelOut(accel_escape_info, accel_states);
- }
-
+ if (accel_states && nfa) {
+ fillAccelOut(accel_escape_info, accel_states);
+ }
+
return nfa;
}
@@ -880,9 +880,9 @@ void fillInBasicState8(const dfa_info &info, mstate_aux *aux, u8 *succ_table,
}
static
-void allocateFSN8(dfa_info &info,
- const map<dstate_id_t, AccelScheme> &accel_escape_info,
- u16 *accel_limit, u16 *accept_limit) {
+void allocateFSN8(dfa_info &info,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ u16 *accel_limit, u16 *accept_limit) {
info.states[0].impl_id = 0; /* dead is always 0 */
vector<dstate_id_t> norm;
@@ -894,7 +894,7 @@ void allocateFSN8(dfa_info &info,
for (u32 i = 1; i < info.size(); i++) {
if (!info.states[i].reports.empty()) {
accept.push_back(i);
- } else if (contains(accel_escape_info, i)) {
+ } else if (contains(accel_escape_info, i)) {
accel.push_back(i);
} else {
norm.push_back(i);
@@ -922,8 +922,8 @@ void allocateFSN8(dfa_info &info,
}
static
-bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
- set<dstate_id_t> *accel_states) {
+bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
+ set<dstate_id_t> *accel_states) {
DEBUG_PRINTF("building mcclellan 8\n");
vector<u32> reports;
@@ -931,14 +931,14 @@ bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
ReportID arb;
u8 single;
- auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
- map<dstate_id_t, AccelScheme> accel_escape_info
- = info.strat.getAccelInfo(cc.grey);
+ auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
+ map<dstate_id_t, AccelScheme> accel_escape_info
+ = info.strat.getAccelInfo(cc.grey);
size_t tran_size = sizeof(u8) * (1 << info.getAlphaShift()) * info.size();
size_t aux_size = sizeof(mstate_aux) * info.size();
size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcclellan) + tran_size);
- size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
+ size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
+ ri->getReportListSize(), 32);
size_t total_size = accel_offset + accel_size;
@@ -953,15 +953,15 @@ bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
accel_offset -= sizeof(NFA); /* adj accel offset to be relative to m */
assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
char *nfa_base = (char *)nfa.get();
mcclellan *m = (mcclellan *)getMutableImplNfa(nfa.get());
- allocateFSN8(info, accel_escape_info, &m->accel_limit_8,
- &m->accept_limit_8);
+ allocateFSN8(info, accel_escape_info, &m->accel_limit_8,
+ &m->accept_limit_8);
populateBasicInfo(sizeof(u8), info, total_size, aux_offset, accel_offset,
- accel_escape_info.size(), arb, single, nfa.get());
+ accel_escape_info.size(), arb, single, nfa.get());
vector<u32> reportOffsets;
@@ -972,14 +972,14 @@ bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
mstate_aux *aux = (mstate_aux *)(nfa_base + aux_offset);
for (size_t i = 0; i < info.size(); i++) {
- if (contains(accel_escape_info, i)) {
+ if (contains(accel_escape_info, i)) {
u32 j = info.implId(i);
aux[j].accel_offset = accel_offset;
accel_offset += info.strat.accelSize();
- info.strat.buildAccel(i, accel_escape_info.at(i),
- (void *)((char *)m + aux[j].accel_offset));
+ info.strat.buildAccel(i, accel_escape_info.at(i),
+ (void *)((char *)m + aux[j].accel_offset));
}
fillInBasicState8(info, aux, succ_table, reportOffsets, reports,
@@ -990,17 +990,17 @@ bytecode_ptr<NFA> mcclellanCompile8(dfa_info &info, const CompileContext &cc,
DEBUG_PRINTF("rl size %zu\n", ri->size());
- if (accel_states && nfa) {
- fillAccelOut(accel_escape_info, accel_states);
- }
-
+ if (accel_states && nfa) {
+ fillAccelOut(accel_escape_info, accel_states);
+ }
+
return nfa;
}
#define MAX_SHERMAN_LIST_LEN 9
static
-void addIfEarlier(flat_set<dstate_id_t> &dest, dstate_id_t candidate,
+void addIfEarlier(flat_set<dstate_id_t> &dest, dstate_id_t candidate,
dstate_id_t max) {
if (candidate < max) {
dest.insert(candidate);
@@ -1008,41 +1008,41 @@ void addIfEarlier(flat_set<dstate_id_t> &dest, dstate_id_t candidate,
}
static
-void addSuccessors(flat_set<dstate_id_t> &dest, const dstate &source,
+void addSuccessors(flat_set<dstate_id_t> &dest, const dstate &source,
u16 alphasize, dstate_id_t curr_id) {
for (symbol_t s = 0; s < alphasize; s++) {
addIfEarlier(dest, source.next[s], curr_id);
}
}
-/* \brief Returns a set of states to search for a better daddy. */
-static
-flat_set<dstate_id_t> find_daddy_candidates(const dfa_info &info,
- dstate_id_t curr_id) {
- flat_set<dstate_id_t> hinted;
-
- addIfEarlier(hinted, 0, curr_id);
- addIfEarlier(hinted, info.raw.start_anchored, curr_id);
- addIfEarlier(hinted, info.raw.start_floating, curr_id);
-
- // Add existing daddy and his successors, then search back one generation.
- const u16 alphasize = info.impl_alpha_size;
- dstate_id_t daddy = info.states[curr_id].daddy;
- for (u32 level = 0; daddy && level < 2; level++) {
- addIfEarlier(hinted, daddy, curr_id);
- addSuccessors(hinted, info.states[daddy], alphasize, curr_id);
- daddy = info.states[daddy].daddy;
- }
-
- return hinted;
-}
-
+/* \brief Returns a set of states to search for a better daddy. */
+static
+flat_set<dstate_id_t> find_daddy_candidates(const dfa_info &info,
+ dstate_id_t curr_id) {
+ flat_set<dstate_id_t> hinted;
+
+ addIfEarlier(hinted, 0, curr_id);
+ addIfEarlier(hinted, info.raw.start_anchored, curr_id);
+ addIfEarlier(hinted, info.raw.start_floating, curr_id);
+
+ // Add existing daddy and his successors, then search back one generation.
+ const u16 alphasize = info.impl_alpha_size;
+ dstate_id_t daddy = info.states[curr_id].daddy;
+ for (u32 level = 0; daddy && level < 2; level++) {
+ addIfEarlier(hinted, daddy, curr_id);
+ addSuccessors(hinted, info.states[daddy], alphasize, curr_id);
+ daddy = info.states[daddy].daddy;
+ }
+
+ return hinted;
+}
+
#define MAX_SHERMAN_SELF_LOOP 20
static
-void find_better_daddy(dfa_info &info, dstate_id_t curr_id, bool using8bit,
- bool any_cyclic_near_anchored_state,
- bool trust_daddy_states, const Grey &grey) {
+void find_better_daddy(dfa_info &info, dstate_id_t curr_id, bool using8bit,
+ bool any_cyclic_near_anchored_state,
+ bool trust_daddy_states, const Grey &grey) {
if (!grey.allowShermanStates) {
return;
}
@@ -1077,25 +1077,25 @@ void find_better_daddy(dfa_info &info, dstate_id_t curr_id, bool using8bit,
dstate_id_t best_daddy = 0;
dstate &currState = info.states[curr_id];
- flat_set<dstate_id_t> hinted;
- if (trust_daddy_states) {
- // Use the daddy already set for this state so long as it isn't already
- // a Sherman state.
+ flat_set<dstate_id_t> hinted;
+ if (trust_daddy_states) {
+ // Use the daddy already set for this state so long as it isn't already
+ // a Sherman state.
dstate_id_t daddy = currState.daddy;
if (!info.is_sherman(daddy) && !info.is_widestate(daddy)) {
- hinted.insert(currState.daddy);
- } else {
- // Fall back to granddaddy, which has already been processed (due
- // to BFS ordering) and cannot be a Sherman state.
- dstate_id_t granddaddy = info.states[currState.daddy].daddy;
+ hinted.insert(currState.daddy);
+ } else {
+ // Fall back to granddaddy, which has already been processed (due
+ // to BFS ordering) and cannot be a Sherman state.
+ dstate_id_t granddaddy = info.states[currState.daddy].daddy;
if (info.is_widestate(granddaddy)) {
return;
}
- assert(!info.is_sherman(granddaddy));
- hinted.insert(granddaddy);
+ assert(!info.is_sherman(granddaddy));
+ hinted.insert(granddaddy);
}
- } else {
- hinted = find_daddy_candidates(info, curr_id);
+ } else {
+ hinted = find_daddy_candidates(info, curr_id);
}
for (const dstate_id_t &donor : hinted) {
@@ -1139,7 +1139,7 @@ void find_better_daddy(dfa_info &info, dstate_id_t curr_id, bool using8bit,
}
u32 self_loop_width = 0;
- const dstate &curr_raw = info.states[curr_id];
+ const dstate &curr_raw = info.states[curr_id];
for (unsigned i = 0; i < N_CHARS; i++) {
if (curr_raw.next[info.alpha_remap[i]] == curr_id) {
self_loop_width++;
@@ -1148,7 +1148,7 @@ void find_better_daddy(dfa_info &info, dstate_id_t curr_id, bool using8bit,
if (self_loop_width > MAX_SHERMAN_SELF_LOOP) {
DEBUG_PRINTF("%hu is banned wide self loop (%u)\n", curr_id,
- self_loop_width);
+ self_loop_width);
return;
}
@@ -1459,11 +1459,11 @@ void find_wide_state(dfa_info &info) {
generate_symbol_chain(info, chain_tail);
}
-bytecode_ptr<NFA> mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
- const CompileContext &cc,
- bool trust_daddy_states,
- set<dstate_id_t> *accel_states) {
- assert(!is_dead(raw));
+bytecode_ptr<NFA> mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
+ const CompileContext &cc,
+ bool trust_daddy_states,
+ set<dstate_id_t> *accel_states) {
+ assert(!is_dead(raw));
dfa_info info(strat);
bool using8bit = cc.grey.allowMcClellan8 && info.size() <= 256;
@@ -1475,17 +1475,17 @@ bytecode_ptr<NFA> mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
bool has_eod_reports = raw.hasEodReports();
- bytecode_ptr<NFA> nfa;
- if (!using8bit) {
+ bytecode_ptr<NFA> nfa;
+ if (!using8bit) {
// Wide state optimization
if (cc.grey.allowWideStates && strat.getType() == McClellan
&& !is_triggered(raw.kind)) {
find_wide_state(info);
}
- u16 total_daddy = 0;
- bool any_cyclic_near_anchored_state
- = is_cyclic_near(raw, raw.start_anchored);
+ u16 total_daddy = 0;
+ bool any_cyclic_near_anchored_state
+ = is_cyclic_near(raw, raw.start_anchored);
// Sherman optimization
if (info.impl_alpha_size > 16) {
@@ -1502,11 +1502,11 @@ bytecode_ptr<NFA> mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
DEBUG_PRINTF("daddy %hu/%zu states=%zu alpha=%hu\n", total_daddy,
info.size() * info.impl_alpha_size, info.size(),
info.impl_alpha_size);
- }
+ }
- nfa = mcclellanCompile16(info, cc, accel_states);
+ nfa = mcclellanCompile16(info, cc, accel_states);
} else {
- nfa = mcclellanCompile8(info, cc, accel_states);
+ nfa = mcclellanCompile8(info, cc, accel_states);
}
if (has_eod_reports) {
@@ -1517,13 +1517,13 @@ bytecode_ptr<NFA> mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
return nfa;
}
-bytecode_ptr<NFA> mcclellanCompile(raw_dfa &raw, const CompileContext &cc,
- const ReportManager &rm,
- bool only_accel_init,
- bool trust_daddy_states,
- set<dstate_id_t> *accel_states) {
- mcclellan_build_strat mbs(raw, rm, only_accel_init);
- return mcclellanCompile_i(raw, mbs, cc, trust_daddy_states, accel_states);
+bytecode_ptr<NFA> mcclellanCompile(raw_dfa &raw, const CompileContext &cc,
+ const ReportManager &rm,
+ bool only_accel_init,
+ bool trust_daddy_states,
+ set<dstate_id_t> *accel_states) {
+ mcclellan_build_strat mbs(raw, rm, only_accel_init);
+ return mcclellanCompile_i(raw, mbs, cc, trust_daddy_states, accel_states);
}
size_t mcclellan_build_strat::accelSize(void) const {
@@ -1548,7 +1548,7 @@ u32 mcclellanStartReachSize(const raw_dfa *raw) {
return out.count();
}
-bool has_accel_mcclellan(const NFA *nfa) {
+bool has_accel_mcclellan(const NFA *nfa) {
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
return m->has_accel;
}
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellancompile.h b/contrib/libs/hyperscan/src/nfa/mcclellancompile.h
index f1c5ea08884..73cb9fd775a 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellancompile.h
+++ b/contrib/libs/hyperscan/src/nfa/mcclellancompile.h
@@ -29,10 +29,10 @@
#ifndef MCCLELLANCOMPILE_H
#define MCCLELLANCOMPILE_H
-#include "accel_dfa_build_strat.h"
+#include "accel_dfa_build_strat.h"
#include "rdfa.h"
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include <memory>
#include <vector>
@@ -42,54 +42,54 @@ struct NFA;
namespace ue2 {
-class ReportManager;
+class ReportManager;
struct CompileContext;
-class mcclellan_build_strat : public accel_dfa_build_strat {
+class mcclellan_build_strat : public accel_dfa_build_strat {
public:
- mcclellan_build_strat(raw_dfa &rdfa_in, const ReportManager &rm_in,
- bool only_accel_init_in)
- : accel_dfa_build_strat(rm_in, only_accel_init_in), rdfa(rdfa_in) {}
+ mcclellan_build_strat(raw_dfa &rdfa_in, const ReportManager &rm_in,
+ bool only_accel_init_in)
+ : accel_dfa_build_strat(rm_in, only_accel_init_in), rdfa(rdfa_in) {}
raw_dfa &get_raw() const override { return rdfa; }
std::unique_ptr<raw_report_info> gatherReports(
- std::vector<u32> &reports /* out */,
- std::vector<u32> &reports_eod /* out */,
- u8 *isSingleReport /* out */,
- ReportID *arbReport /* out */) const override;
+ std::vector<u32> &reports /* out */,
+ std::vector<u32> &reports_eod /* out */,
+ u8 *isSingleReport /* out */,
+ ReportID *arbReport /* out */) const override;
size_t accelSize(void) const override;
- u32 max_allowed_offset_accel() const override;
- u32 max_stop_char() const override;
- u32 max_floating_stop_char() const override;
+ u32 max_allowed_offset_accel() const override;
+ u32 max_stop_char() const override;
+ u32 max_floating_stop_char() const override;
DfaType getType() const override { return McClellan; }
private:
raw_dfa &rdfa;
};
-/**
- * \brief Construct an implementation DFA.
- *
- * \param raw the raw dfa to construct from
- * \param cc compile context
- * \param rm report manger
- * \param only_accel_init if true, only the init states will be examined for
- * acceleration opportunities
- * \param trust_daddy_states if true, trust the daddy state set in the raw dfa
- * rather than conducting a search for a better daddy (for Sherman
- * states)
- * \param accel_states (optional) success, is filled with the set of
- * accelerable states
- */
-bytecode_ptr<NFA>
+/**
+ * \brief Construct an implementation DFA.
+ *
+ * \param raw the raw dfa to construct from
+ * \param cc compile context
+ * \param rm report manger
+ * \param only_accel_init if true, only the init states will be examined for
+ * acceleration opportunities
+ * \param trust_daddy_states if true, trust the daddy state set in the raw dfa
+ * rather than conducting a search for a better daddy (for Sherman
+ * states)
+ * \param accel_states (optional) success, is filled with the set of
+ * accelerable states
+ */
+bytecode_ptr<NFA>
mcclellanCompile(raw_dfa &raw, const CompileContext &cc,
- const ReportManager &rm, bool only_accel_init,
- bool trust_daddy_states = false,
+ const ReportManager &rm, bool only_accel_init,
+ bool trust_daddy_states = false,
std::set<dstate_id_t> *accel_states = nullptr);
/* used internally by mcclellan/haig/gough compile process */
-bytecode_ptr<NFA>
-mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
- const CompileContext &cc, bool trust_daddy_states = false,
+bytecode_ptr<NFA>
+mcclellanCompile_i(raw_dfa &raw, accel_dfa_build_strat &strat,
+ const CompileContext &cc, bool trust_daddy_states = false,
std::set<dstate_id_t> *accel_states = nullptr);
/**
@@ -99,8 +99,8 @@ u32 mcclellanStartReachSize(const raw_dfa *raw);
std::set<ReportID> all_reports(const raw_dfa &rdfa);
-bool has_accel_mcclellan(const NFA *nfa);
+bool has_accel_mcclellan(const NFA *nfa);
} // namespace ue2
-#endif // MCCLELLANCOMPILE_H
+#endif // MCCLELLANCOMPILE_H
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.cpp b/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.cpp
index 5a2ac16cf3f..3e299b81e22 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.cpp
+++ b/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,11 +30,11 @@
#include "rdfa.h"
#include "util/container.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include "ue2common.h"
#include <deque>
-#include <map>
+#include <map>
using namespace std;
@@ -43,12 +43,12 @@ namespace ue2 {
#define INIT_STATE 1
static
-bool state_has_reports(const raw_dfa &raw, dstate_id_t s) {
- const auto &ds = raw.states[s];
- return !ds.reports.empty() || !ds.reports_eod.empty();
-}
-
-static
+bool state_has_reports(const raw_dfa &raw, dstate_id_t s) {
+ const auto &ds = raw.states[s];
+ return !ds.reports.empty() || !ds.reports_eod.empty();
+}
+
+static
u32 count_dots(const raw_dfa &raw) {
assert(raw.start_anchored == INIT_STATE);
@@ -65,7 +65,7 @@ u32 count_dots(const raw_dfa &raw) {
}
}
- if (state_has_reports(raw, raw.states[i].next[0])) {
+ if (state_has_reports(raw, raw.states[i].next[0])) {
goto validate;
}
@@ -126,11 +126,11 @@ u32 remove_leading_dots(raw_dfa &raw) {
static never_inline
u32 calc_min_dist_from_bob(raw_dfa &raw, vector<u32> *dist_in) {
vector<u32> &dist = *dist_in;
- dist.assign(raw.states.size(), ~0U);
+ dist.assign(raw.states.size(), ~0U);
assert(raw.start_anchored != DEAD_STATE);
- deque<dstate_id_t> to_visit = { raw.start_anchored };
+ deque<dstate_id_t> to_visit = { raw.start_anchored };
dist[raw.start_anchored] = 0;
u32 last_d = 0;
@@ -145,7 +145,7 @@ u32 calc_min_dist_from_bob(raw_dfa &raw, vector<u32> *dist_in) {
assert(d >= last_d);
assert(d != ~0U);
- for (dstate_id_t t : raw.states[s].next) {
+ for (dstate_id_t t : raw.states[s].next) {
if (t == DEAD_STATE) {
continue;
}
@@ -163,41 +163,41 @@ u32 calc_min_dist_from_bob(raw_dfa &raw, vector<u32> *dist_in) {
return last_d;
}
-bool clear_deeper_reports(raw_dfa &raw, u32 max_offset) {
- DEBUG_PRINTF("clearing reports on states deeper than %u\n", max_offset);
+bool clear_deeper_reports(raw_dfa &raw, u32 max_offset) {
+ DEBUG_PRINTF("clearing reports on states deeper than %u\n", max_offset);
vector<u32> bob_dist;
u32 max_min_dist_bob = calc_min_dist_from_bob(raw, &bob_dist);
if (max_min_dist_bob <= max_offset) {
- return false;
+ return false;
}
- bool changed = false;
+ bool changed = false;
for (u32 s = DEAD_STATE + 1; s < raw.states.size(); s++) {
- if (bob_dist[s] > max_offset && state_has_reports(raw, s)) {
- DEBUG_PRINTF("clearing reports on %u (depth %u)\n", s, bob_dist[s]);
- auto &ds = raw.states[s];
- ds.reports.clear();
- ds.reports_eod.clear();
- changed = true;
+ if (bob_dist[s] > max_offset && state_has_reports(raw, s)) {
+ DEBUG_PRINTF("clearing reports on %u (depth %u)\n", s, bob_dist[s]);
+ auto &ds = raw.states[s];
+ ds.reports.clear();
+ ds.reports_eod.clear();
+ changed = true;
}
}
- if (!changed) {
- return false;
- }
-
- // We may have cleared all reports from the DFA, in which case it should
- // become empty.
- if (all_of_in(raw.states, [](const dstate &ds) {
- return ds.reports.empty() && ds.reports_eod.empty();
- })) {
- DEBUG_PRINTF("no reports left at all, dfa is dead\n");
- raw.start_anchored = DEAD_STATE;
- raw.start_floating = DEAD_STATE;
+ if (!changed) {
+ return false;
}
- return true;
+ // We may have cleared all reports from the DFA, in which case it should
+ // become empty.
+ if (all_of_in(raw.states, [](const dstate &ds) {
+ return ds.reports.empty() && ds.reports_eod.empty();
+ })) {
+ DEBUG_PRINTF("no reports left at all, dfa is dead\n");
+ raw.start_anchored = DEAD_STATE;
+ raw.start_floating = DEAD_STATE;
+ }
+
+ return true;
}
set<ReportID> all_reports(const raw_dfa &rdfa) {
@@ -230,10 +230,10 @@ bool has_non_eod_accepts(const raw_dfa &rdfa) {
size_t hash_dfa_no_reports(const raw_dfa &rdfa) {
size_t v = 0;
hash_combine(v, rdfa.alpha_size);
- hash_combine(v, rdfa.alpha_remap);
+ hash_combine(v, rdfa.alpha_remap);
for (const auto &ds : rdfa.states) {
- hash_combine(v, ds.next);
+ hash_combine(v, ds.next);
}
return v;
@@ -246,41 +246,41 @@ size_t hash_dfa(const raw_dfa &rdfa) {
return v;
}
-static
-bool can_die_early(const raw_dfa &raw, dstate_id_t s,
- map<dstate_id_t, u32> &visited, u32 age_limit) {
- if (contains(visited, s) && visited[s] >= age_limit) {
- /* we have already visited (or are in the process of visiting) here with
- * a looser limit. */
- return false;
- }
- visited[s] = age_limit;
-
- if (s == DEAD_STATE) {
- return true;
- }
-
- if (age_limit == 0) {
- return false;
- }
-
- for (const auto &next : raw.states[s].next) {
- if (can_die_early(raw, next, visited, age_limit - 1)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool can_die_early(const raw_dfa &raw, u32 age_limit) {
- map<dstate_id_t, u32> visited;
- return can_die_early(raw, raw.start_anchored, visited, age_limit);
-}
-
-bool is_dead(const raw_dfa &rdfa) {
- return rdfa.start_anchored == DEAD_STATE &&
- rdfa.start_floating == DEAD_STATE;
-}
-
+static
+bool can_die_early(const raw_dfa &raw, dstate_id_t s,
+ map<dstate_id_t, u32> &visited, u32 age_limit) {
+ if (contains(visited, s) && visited[s] >= age_limit) {
+ /* we have already visited (or are in the process of visiting) here with
+ * a looser limit. */
+ return false;
+ }
+ visited[s] = age_limit;
+
+ if (s == DEAD_STATE) {
+ return true;
+ }
+
+ if (age_limit == 0) {
+ return false;
+ }
+
+ for (const auto &next : raw.states[s].next) {
+ if (can_die_early(raw, next, visited, age_limit - 1)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool can_die_early(const raw_dfa &raw, u32 age_limit) {
+ map<dstate_id_t, u32> visited;
+ return can_die_early(raw, raw.start_anchored, visited, age_limit);
+}
+
+bool is_dead(const raw_dfa &rdfa) {
+ return rdfa.start_anchored == DEAD_STATE &&
+ rdfa.start_floating == DEAD_STATE;
+}
+
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.h b/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.h
index a489496133e..bc730cddeab 100644
--- a/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.h
+++ b/contrib/libs/hyperscan/src/nfa/mcclellancompile_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,23 +29,23 @@
#ifndef MCCLELLAN_COMPILE_UTIL_H
#define MCCLELLAN_COMPILE_UTIL_H
-#include "rdfa.h"
+#include "rdfa.h"
#include "ue2common.h"
#include <set>
namespace ue2 {
-u32 remove_leading_dots(raw_dfa &raw);
+u32 remove_leading_dots(raw_dfa &raw);
+
+/**
+ * \brief Clear reports on any states that are deeper than \a max_offset from
+ * start of stream.
+ *
+ * Returns false if no changes are made to the DFA.
+ */
+bool clear_deeper_reports(raw_dfa &raw, u32 max_offset);
-/**
- * \brief Clear reports on any states that are deeper than \a max_offset from
- * start of stream.
- *
- * Returns false if no changes are made to the DFA.
- */
-bool clear_deeper_reports(raw_dfa &raw, u32 max_offset);
-
std::set<ReportID> all_reports(const raw_dfa &rdfa);
bool has_eod_accepts(const raw_dfa &rdfa);
bool has_non_eod_accepts(const raw_dfa &rdfa);
@@ -57,15 +57,15 @@ size_t hash_dfa_no_reports(const raw_dfa &rdfa);
/** \brief Compute a simple hash of this raw_dfa, including its reports. */
size_t hash_dfa(const raw_dfa &rdfa);
-bool can_die_early(const raw_dfa &raw, u32 age_limit);
-
-/**
- * \brief Returns true if this DFA cannot match, i.e. its start state is
- * DEAD_STATE.
- */
-bool is_dead(const raw_dfa &rdfa);
-
-
+bool can_die_early(const raw_dfa &raw, u32 age_limit);
+
+/**
+ * \brief Returns true if this DFA cannot match, i.e. its start state is
+ * DEAD_STATE.
+ */
+bool is_dead(const raw_dfa &rdfa);
+
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng.c b/contrib/libs/hyperscan/src/nfa/mcsheng.c
index 901385573e5..22cac119fb7 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng.c
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng.c
@@ -1,1410 +1,1410 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "mcsheng.h"
-
-#include "accel.h"
-#include "mcsheng_internal.h"
-#include "nfa_api.h"
-#include "nfa_api_queue.h"
-#include "nfa_internal.h"
-#include "util/arch.h"
-#include "util/bitutils.h"
-#include "util/compare.h"
-#include "util/simd_utils.h"
-#include "ue2common.h"
-
-enum MatchMode {
- CALLBACK_OUTPUT,
- STOP_AT_MATCH,
- NO_MATCHES
-};
-
-static really_inline
-const struct mstate_aux *get_aux(const struct mcsheng *m, u32 s) {
- const char *nfa = (const char *)m - sizeof(struct NFA);
- const struct mstate_aux *aux
- = s + (const struct mstate_aux *)(nfa + m->aux_offset);
-
- assert(ISALIGNED(aux));
- return aux;
-}
-
-static really_inline
-u32 mcshengEnableStarts(const struct mcsheng *m, u32 s) {
- const struct mstate_aux *aux = get_aux(m, s);
-
- DEBUG_PRINTF("enabling starts %u->%hu\n", s, aux->top);
- return aux->top;
-}
-
-static really_inline
-u32 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
- u32 as) {
- assert(ISALIGNED_N(sherman_state, 16));
-
- u8 len = *(const u8 *)(sherman_state + SHERMAN_LEN_OFFSET);
-
- if (len) {
- m128 ss_char = load128(sherman_state);
- m128 cur_char = set16x8(cprime);
-
- u32 z = movemask128(eq128(ss_char, cur_char));
-
- /* remove header cruft: type 1, len 1, daddy 2*/
- z &= ~0xf;
- z &= (1U << (len + 4)) - 1;
-
- if (z) {
- u32 i = ctz32(z & ~0xf) - 4;
-
- u32 s_out = unaligned_load_u16((const u8 *)sherman_state
- + SHERMAN_STATES_OFFSET(len)
- + sizeof(u16) * i);
- DEBUG_PRINTF("found sherman match at %u/%u for c'=%hhu s=%u\n", i,
- len, cprime, s_out);
- return s_out;
- }
- }
-
- u32 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
- return succ_table[(daddy << as) + cprime];
-}
-
-static really_inline
-char doComplexReport(NfaCallback cb, void *ctxt, const struct mcsheng *m,
- u32 s, u64a loc, char eod, u32 *cached_accept_state,
- u32 *cached_accept_id) {
- DEBUG_PRINTF("reporting state = %u, loc=%llu, eod %hhu\n",
- s & STATE_MASK, loc, eod);
-
- if (!eod && s == *cached_accept_state) {
- if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
-
- return MO_CONTINUE_MATCHING; /* continue execution */
- }
-
- const struct mstate_aux *aux = get_aux(m, s);
- size_t offset = eod ? aux->accept_eod : aux->accept;
-
- assert(offset);
- const struct report_list *rl
- = (const void *)((const char *)m + offset - sizeof(struct NFA));
- assert(ISALIGNED(rl));
-
- DEBUG_PRINTF("report list size %u\n", rl->count);
- u32 count = rl->count;
-
- if (!eod && count == 1) {
- *cached_accept_state = s;
- *cached_accept_id = rl->report[0];
-
- DEBUG_PRINTF("reporting %u\n", rl->report[0]);
- if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
-
- return MO_CONTINUE_MATCHING; /* continue execution */
- }
-
- for (u32 i = 0; i < count; i++) {
- DEBUG_PRINTF("reporting %u\n", rl->report[i]);
- if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
- }
-
- return MO_CONTINUE_MATCHING; /* continue execution */
-}
-
-#define SHENG_CHUNK 8
-
-static really_inline
-u32 doSheng(const struct mcsheng *m, const u8 **c_inout, const u8 *soft_c_end,
- const u8 *hard_c_end, u32 s_in, char do_accel) {
- assert(s_in < m->sheng_end);
- assert(s_in); /* should not already be dead */
- assert(soft_c_end <= hard_c_end);
- DEBUG_PRINTF("s_in = %u (adjusted %u)\n", s_in, s_in - 1);
- m128 s = set16x8(s_in - 1);
- const u8 *c = *c_inout;
- const u8 *c_end = hard_c_end - SHENG_CHUNK + 1;
- if (!do_accel) {
- c_end = MIN(soft_c_end, hard_c_end - SHENG_CHUNK + 1);
- }
- const m128 *masks = m->sheng_masks;
- u8 sheng_limit = m->sheng_end - 1; /* - 1: no dead state */
- u8 sheng_stop_limit = do_accel ? m->sheng_accel_limit : sheng_limit;
-
- /* When we use movd to get a u32 containing our state, it will have 4 lanes
- * all duplicating the state. We can create versions of our limits with 4
- * copies to directly compare against, this prevents us generating code to
- * extract a single copy of the state from the u32 for checking. */
- u32 sheng_stop_limit_x4 = sheng_stop_limit * 0x01010101;
-
-#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
- u32 sheng_limit_x4 = sheng_limit * 0x01010101;
- m128 simd_stop_limit = set4x32(sheng_stop_limit_x4);
- m128 accel_delta = set16x8(sheng_limit - sheng_stop_limit);
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "mcsheng.h"
+
+#include "accel.h"
+#include "mcsheng_internal.h"
+#include "nfa_api.h"
+#include "nfa_api_queue.h"
+#include "nfa_internal.h"
+#include "util/arch.h"
+#include "util/bitutils.h"
+#include "util/compare.h"
+#include "util/simd_utils.h"
+#include "ue2common.h"
+
+enum MatchMode {
+ CALLBACK_OUTPUT,
+ STOP_AT_MATCH,
+ NO_MATCHES
+};
+
+static really_inline
+const struct mstate_aux *get_aux(const struct mcsheng *m, u32 s) {
+ const char *nfa = (const char *)m - sizeof(struct NFA);
+ const struct mstate_aux *aux
+ = s + (const struct mstate_aux *)(nfa + m->aux_offset);
+
+ assert(ISALIGNED(aux));
+ return aux;
+}
+
+static really_inline
+u32 mcshengEnableStarts(const struct mcsheng *m, u32 s) {
+ const struct mstate_aux *aux = get_aux(m, s);
+
+ DEBUG_PRINTF("enabling starts %u->%hu\n", s, aux->top);
+ return aux->top;
+}
+
+static really_inline
+u32 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
+ u32 as) {
+ assert(ISALIGNED_N(sherman_state, 16));
+
+ u8 len = *(const u8 *)(sherman_state + SHERMAN_LEN_OFFSET);
+
+ if (len) {
+ m128 ss_char = load128(sherman_state);
+ m128 cur_char = set16x8(cprime);
+
+ u32 z = movemask128(eq128(ss_char, cur_char));
+
+ /* remove header cruft: type 1, len 1, daddy 2*/
+ z &= ~0xf;
+ z &= (1U << (len + 4)) - 1;
+
+ if (z) {
+ u32 i = ctz32(z & ~0xf) - 4;
+
+ u32 s_out = unaligned_load_u16((const u8 *)sherman_state
+ + SHERMAN_STATES_OFFSET(len)
+ + sizeof(u16) * i);
+ DEBUG_PRINTF("found sherman match at %u/%u for c'=%hhu s=%u\n", i,
+ len, cprime, s_out);
+ return s_out;
+ }
+ }
+
+ u32 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
+ return succ_table[(daddy << as) + cprime];
+}
+
+static really_inline
+char doComplexReport(NfaCallback cb, void *ctxt, const struct mcsheng *m,
+ u32 s, u64a loc, char eod, u32 *cached_accept_state,
+ u32 *cached_accept_id) {
+ DEBUG_PRINTF("reporting state = %u, loc=%llu, eod %hhu\n",
+ s & STATE_MASK, loc, eod);
+
+ if (!eod && s == *cached_accept_state) {
+ if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+
+ return MO_CONTINUE_MATCHING; /* continue execution */
+ }
+
+ const struct mstate_aux *aux = get_aux(m, s);
+ size_t offset = eod ? aux->accept_eod : aux->accept;
+
+ assert(offset);
+ const struct report_list *rl
+ = (const void *)((const char *)m + offset - sizeof(struct NFA));
+ assert(ISALIGNED(rl));
+
+ DEBUG_PRINTF("report list size %u\n", rl->count);
+ u32 count = rl->count;
+
+ if (!eod && count == 1) {
+ *cached_accept_state = s;
+ *cached_accept_id = rl->report[0];
+
+ DEBUG_PRINTF("reporting %u\n", rl->report[0]);
+ if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+
+ return MO_CONTINUE_MATCHING; /* continue execution */
+ }
+
+ for (u32 i = 0; i < count; i++) {
+ DEBUG_PRINTF("reporting %u\n", rl->report[i]);
+ if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+ }
+
+ return MO_CONTINUE_MATCHING; /* continue execution */
+}
+
+#define SHENG_CHUNK 8
+
+static really_inline
+u32 doSheng(const struct mcsheng *m, const u8 **c_inout, const u8 *soft_c_end,
+ const u8 *hard_c_end, u32 s_in, char do_accel) {
+ assert(s_in < m->sheng_end);
+ assert(s_in); /* should not already be dead */
+ assert(soft_c_end <= hard_c_end);
+ DEBUG_PRINTF("s_in = %u (adjusted %u)\n", s_in, s_in - 1);
+ m128 s = set16x8(s_in - 1);
+ const u8 *c = *c_inout;
+ const u8 *c_end = hard_c_end - SHENG_CHUNK + 1;
+ if (!do_accel) {
+ c_end = MIN(soft_c_end, hard_c_end - SHENG_CHUNK + 1);
+ }
+ const m128 *masks = m->sheng_masks;
+ u8 sheng_limit = m->sheng_end - 1; /* - 1: no dead state */
+ u8 sheng_stop_limit = do_accel ? m->sheng_accel_limit : sheng_limit;
+
+ /* When we use movd to get a u32 containing our state, it will have 4 lanes
+ * all duplicating the state. We can create versions of our limits with 4
+ * copies to directly compare against, this prevents us generating code to
+ * extract a single copy of the state from the u32 for checking. */
+ u32 sheng_stop_limit_x4 = sheng_stop_limit * 0x01010101;
+
+#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
+ u32 sheng_limit_x4 = sheng_limit * 0x01010101;
+ m128 simd_stop_limit = set4x32(sheng_stop_limit_x4);
+ m128 accel_delta = set16x8(sheng_limit - sheng_stop_limit);
DEBUG_PRINTF("end %hhu, accel %hu --> limit %hhu\n", sheng_limit,
- m->sheng_accel_limit, sheng_stop_limit);
-#endif
-
-#define SHENG_SINGLE_ITER do { \
- m128 shuffle_mask = masks[*(c++)]; \
- s = pshufb_m128(shuffle_mask, s); \
- u32 s_gpr_x4 = movd(s); /* convert to u8 */ \
+ m->sheng_accel_limit, sheng_stop_limit);
+#endif
+
+#define SHENG_SINGLE_ITER do { \
+ m128 shuffle_mask = masks[*(c++)]; \
+ s = pshufb_m128(shuffle_mask, s); \
+ u32 s_gpr_x4 = movd(s); /* convert to u8 */ \
DEBUG_PRINTF("c %hhu (%c) --> s %u\n", c[-1], c[-1], s_gpr_x4); \
- if (s_gpr_x4 >= sheng_stop_limit_x4) { \
- s_gpr = s_gpr_x4; \
- goto exit; \
- } \
- } while (0)
-
- u8 s_gpr;
- while (c < c_end) {
-#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
+ if (s_gpr_x4 >= sheng_stop_limit_x4) { \
+ s_gpr = s_gpr_x4; \
+ goto exit; \
+ } \
+ } while (0)
+
+ u8 s_gpr;
+ while (c < c_end) {
+#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
/* This version uses pext for efficiently bitbashing out scaled
- * versions of the bytes to process from a u64a */
-
- u64a data_bytes = unaligned_load_u64a(c);
- u64a cc0 = pdep64(data_bytes, 0xff0); /* extract scaled low byte */
- data_bytes &= ~0xffULL; /* clear low bits for scale space */
- m128 shuffle_mask0 = load128((const char *)masks + cc0);
- s = pshufb_m128(shuffle_mask0, s);
- m128 s_max = s;
- m128 s_max0 = s_max;
+ * versions of the bytes to process from a u64a */
+
+ u64a data_bytes = unaligned_load_u64a(c);
+ u64a cc0 = pdep64(data_bytes, 0xff0); /* extract scaled low byte */
+ data_bytes &= ~0xffULL; /* clear low bits for scale space */
+ m128 shuffle_mask0 = load128((const char *)masks + cc0);
+ s = pshufb_m128(shuffle_mask0, s);
+ m128 s_max = s;
+ m128 s_max0 = s_max;
DEBUG_PRINTF("c %02llx --> s %u\n", cc0 >> 4, movd(s));
-
-#define SHENG_SINGLE_UNROLL_ITER(iter) \
- assert(iter); \
- u64a cc##iter = pext64(data_bytes, mcsheng_pext_mask[iter]); \
- assert(cc##iter == (u64a)c[iter] << 4); \
- m128 shuffle_mask##iter = load128((const char *)masks + cc##iter); \
- s = pshufb_m128(shuffle_mask##iter, s); \
- if (do_accel && iter == 7) { \
- /* in the final iteration we also have to check against accel */ \
- m128 s_temp = sadd_u8_m128(s, accel_delta); \
- s_max = max_u8_m128(s_max, s_temp); \
- } else { \
- s_max = max_u8_m128(s_max, s); \
- } \
- m128 s_max##iter = s_max; \
+
+#define SHENG_SINGLE_UNROLL_ITER(iter) \
+ assert(iter); \
+ u64a cc##iter = pext64(data_bytes, mcsheng_pext_mask[iter]); \
+ assert(cc##iter == (u64a)c[iter] << 4); \
+ m128 shuffle_mask##iter = load128((const char *)masks + cc##iter); \
+ s = pshufb_m128(shuffle_mask##iter, s); \
+ if (do_accel && iter == 7) { \
+ /* in the final iteration we also have to check against accel */ \
+ m128 s_temp = sadd_u8_m128(s, accel_delta); \
+ s_max = max_u8_m128(s_max, s_temp); \
+ } else { \
+ s_max = max_u8_m128(s_max, s); \
+ } \
+ m128 s_max##iter = s_max; \
DEBUG_PRINTF("c %02llx --> s %u max %u\n", cc##iter >> 4, \
- movd(s), movd(s_max));
-
- SHENG_SINGLE_UNROLL_ITER(1);
-
- SHENG_SINGLE_UNROLL_ITER(2);
- SHENG_SINGLE_UNROLL_ITER(3);
-
- SHENG_SINGLE_UNROLL_ITER(4);
- SHENG_SINGLE_UNROLL_ITER(5);
-
- SHENG_SINGLE_UNROLL_ITER(6);
- SHENG_SINGLE_UNROLL_ITER(7);
-
- if (movd(s_max7) >= sheng_limit_x4) {
- DEBUG_PRINTF("exit found\n");
-
- /* Explicitly check the last byte as it is more likely as it also
- * checks for acceleration. */
- if (movd(s_max6) < sheng_limit_x4) {
- c += SHENG_CHUNK;
- s_gpr = movq(s);
- assert(s_gpr >= sheng_stop_limit);
- goto exit;
- }
-
- /* use shift-xor to create a register containing all of the max
- * values */
- m128 blended = rshift64_m128(s_max0, 56);
- blended = xor128(blended, rshift64_m128(s_max1, 48));
- blended = xor128(blended, rshift64_m128(s_max2, 40));
- blended = xor128(blended, rshift64_m128(s_max3, 32));
- blended = xor128(blended, rshift64_m128(s_max4, 24));
- blended = xor128(blended, rshift64_m128(s_max5, 16));
- blended = xor128(blended, rshift64_m128(s_max6, 8));
- blended = xor128(blended, s);
- blended = xor128(blended, rshift64_m128(blended, 8));
- DEBUG_PRINTF("blended %016llx\n", movq(blended));
-
- m128 final = min_u8_m128(blended, simd_stop_limit);
- m128 cmp = sub_u8_m128(final, simd_stop_limit);
- u64a stops = ~movemask128(cmp);
- assert(stops);
- u32 earliest = ctz32(stops);
- DEBUG_PRINTF("stops %02llx, earliest %u\n", stops, earliest);
- assert(earliest < 8);
- c += earliest + 1;
- s_gpr = movq(blended) >> (earliest * 8);
- assert(s_gpr >= sheng_stop_limit);
- goto exit;
- } else {
- c += SHENG_CHUNK;
- }
-#else
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
-
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
- SHENG_SINGLE_ITER;
-#endif
- }
-
- assert(c_end - c < SHENG_CHUNK);
- if (c < soft_c_end) {
- assert(soft_c_end - c < SHENG_CHUNK);
- switch (soft_c_end - c) {
- case 7:
- SHENG_SINGLE_ITER; // fallthrough
- case 6:
- SHENG_SINGLE_ITER; // fallthrough
- case 5:
- SHENG_SINGLE_ITER; // fallthrough
- case 4:
- SHENG_SINGLE_ITER; // fallthrough
- case 3:
- SHENG_SINGLE_ITER; // fallthrough
- case 2:
- SHENG_SINGLE_ITER; // fallthrough
- case 1:
- SHENG_SINGLE_ITER; // fallthrough
- }
- }
-
- assert(c >= soft_c_end);
-
- s_gpr = movd(s);
-exit:
- assert(c <= hard_c_end);
- DEBUG_PRINTF("%zu from end; s %hhu\n", c_end - c, s_gpr);
- assert(c >= soft_c_end || s_gpr >= sheng_stop_limit);
- /* undo state adjustment to match mcclellan view */
- if (s_gpr == sheng_limit) {
- s_gpr = 0;
- } else if (s_gpr < sheng_limit) {
- s_gpr++;
- }
-
- *c_inout = c;
- return s_gpr;
-}
-
-static really_inline
-const char *findShermanState(UNUSED const struct mcsheng *m,
- const char *sherman_base_offset, u32 sherman_base,
- u32 s) {
- const char *rv
- = sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
- assert(rv < (const char *)m + m->length - sizeof(struct NFA));
- UNUSED u8 type = *(const u8 *)(rv + SHERMAN_TYPE_OFFSET);
- assert(type == SHERMAN_STATE);
- return rv;
-}
-
-static really_inline
-const u8 *run_mcsheng_accel(const struct mcsheng *m,
- const struct mstate_aux *aux, u32 s,
- const u8 **min_accel_offset,
- const u8 *c, const u8 *c_end) {
- DEBUG_PRINTF("skipping\n");
- u32 accel_offset = aux[s].accel_offset;
-
- assert(aux[s].accel_offset);
- assert(accel_offset >= m->aux_offset);
- assert(!m->sherman_offset || accel_offset < m->sherman_offset);
-
- const union AccelAux *aaux = (const void *)((const char *)m + accel_offset);
- const u8 *c2 = run_accel(aaux, c, c_end);
-
- if (c2 < *min_accel_offset + BAD_ACCEL_DIST) {
- *min_accel_offset = c2 + BIG_ACCEL_PENALTY;
- } else {
- *min_accel_offset = c2 + SMALL_ACCEL_PENALTY;
- }
-
- if (*min_accel_offset >= c_end - ACCEL_MIN_LEN) {
- *min_accel_offset = c_end;
- }
-
- DEBUG_PRINTF("advanced %zd, next accel chance in %zd/%zd\n",
- c2 - c, *min_accel_offset - c2, c_end - c2);
-
- return c2;
-}
-
-static really_inline
-u32 doNormal16(const struct mcsheng *m, const u8 **c_inout, const u8 *end,
- u32 s, char do_accel, enum MatchMode mode) {
- const u8 *c = *c_inout;
-
- const u16 *succ_table
- = (const u16 *)((const char *)m + sizeof(struct mcsheng));
- assert(ISALIGNED_N(succ_table, 2));
- u32 sheng_end = m->sheng_end;
- u32 sherman_base = m->sherman_limit;
- const char *sherman_base_offset
- = (const char *)m - sizeof(struct NFA) + m->sherman_offset;
- u32 as = m->alphaShift;
-
- /* Adjust start of succ table so we can index into using state id (rather
- * than adjust to normal id). As we will not be processing states with low
- * state ids, we will not be accessing data before the succ table. Note: due
- * to the size of the sheng tables, the succ_table pointer will still be
- * inside the engine.*/
- succ_table -= sheng_end << as;
-
- s &= STATE_MASK;
-
- while (c < end && s >= sheng_end) {
- u8 cprime = m->remap[*c];
- DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx (s=%u)\n", *c,
- ourisprint(*c) ? *c : '?', cprime, s);
- if (s < sherman_base) {
- DEBUG_PRINTF("doing normal\n");
- assert(s < m->state_count);
- s = succ_table[(s << as) + cprime];
- } else {
- const char *sherman_state
- = findShermanState(m, sherman_base_offset, sherman_base, s);
- DEBUG_PRINTF("doing sherman (%u)\n", s);
- s = doSherman16(sherman_state, cprime, succ_table, as);
- }
-
- DEBUG_PRINTF("s: %u (%u)\n", s, s & STATE_MASK);
- c++;
-
- if (do_accel && (s & ACCEL_FLAG)) {
- break;
- }
- if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
- break;
- }
-
- s &= STATE_MASK;
- }
-
- *c_inout = c;
- return s;
-}
-
-static really_inline
-char mcshengExec16_i(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **c_final, enum MatchMode mode) {
- assert(ISALIGNED_N(state, 2));
- if (!len) {
- if (mode == STOP_AT_MATCH) {
- *c_final = buf;
- }
- return MO_ALIVE;
- }
-
- u32 s = *state;
- const u8 *c = buf;
- const u8 *c_end = buf + len;
- const u8 sheng_end = m->sheng_end;
- const struct mstate_aux *aux
- = (const struct mstate_aux *)((const char *)m + m->aux_offset
- - sizeof(struct NFA));
-
- s &= STATE_MASK;
-
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- DEBUG_PRINTF("s: %u, len %zu\n", s, len);
-
- const u8 *min_accel_offset = c;
- if (!m->has_accel || len < ACCEL_MIN_LEN) {
- min_accel_offset = c_end;
- goto without_accel;
- }
-
- goto with_accel;
-
-without_accel:
- do {
- assert(c < min_accel_offset);
- int do_accept;
- if (!s) {
- goto exit;
- } else if (s < sheng_end) {
- s = doSheng(m, &c, min_accel_offset, c_end, s, 0);
- do_accept = mode != NO_MATCHES && get_aux(m, s)->accept;
- } else {
- s = doNormal16(m, &c, min_accel_offset, s, 0, mode);
-
- do_accept = mode != NO_MATCHES && (s & ACCEPT_FLAG);
- }
-
- if (do_accept) {
- if (mode == STOP_AT_MATCH) {
- *state = s & STATE_MASK;
- *c_final = c - 1;
- return MO_MATCHES_PENDING;
- }
-
- u64a loc = (c - 1) - buf + offAdj + 1;
-
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD; /* termination requested */
- }
- } else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- assert(c <= c_end); /* sheng is fuzzy for min_accel_offset */
- } while (c < min_accel_offset);
-
- if (c == c_end) {
- goto exit;
- }
-
-with_accel:
- do {
- assert(c < c_end);
- int do_accept;
-
- if (!s) {
- goto exit;
- } else if (s < sheng_end) {
- if (s > m->sheng_accel_limit) {
- c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
- s = doSheng(m, &c, c_end, c_end, s, 1);
- do_accept = mode != NO_MATCHES && get_aux(m, s)->accept;
- } else {
- if (s & ACCEL_FLAG) {
- DEBUG_PRINTF("skipping\n");
- s &= STATE_MASK;
- c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
-
- s = doNormal16(m, &c, c_end, s, 1, mode);
- do_accept = mode != NO_MATCHES && (s & ACCEPT_FLAG);
- }
-
- if (do_accept) {
- if (mode == STOP_AT_MATCH) {
- *state = s & STATE_MASK;
- *c_final = c - 1;
- return MO_MATCHES_PENDING;
- }
-
- u64a loc = (c - 1) - buf + offAdj + 1;
-
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD; /* termination requested */
- }
- } else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- assert(c <= c_end);
- } while (c < c_end);
-
-exit:
- s &= STATE_MASK;
-
- if (mode == STOP_AT_MATCH) {
- *c_final = c_end;
- }
- *state = s;
-
- return MO_ALIVE;
-}
-
-static never_inline
-char mcshengExec16_i_cb(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, CALLBACK_OUTPUT);
-}
-
-static never_inline
-char mcshengExec16_i_sam(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, STOP_AT_MATCH);
-}
-
-static never_inline
-char mcshengExec16_i_nm(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, NO_MATCHES);
-}
-
-static really_inline
-char mcshengExec16_i_ni(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point,
- enum MatchMode mode) {
- if (mode == CALLBACK_OUTPUT) {
- return mcshengExec16_i_cb(m, state, buf, len, offAdj, cb, ctxt,
- single, final_point);
- } else if (mode == STOP_AT_MATCH) {
- return mcshengExec16_i_sam(m, state, buf, len, offAdj, cb, ctxt,
- single, final_point);
- } else {
- assert (mode == NO_MATCHES);
- return mcshengExec16_i_nm(m, state, buf, len, offAdj, cb, ctxt,
- single, final_point);
- }
-}
-
-static really_inline
-u32 doNormal8(const struct mcsheng *m, const u8 **c_inout, const u8 *end, u32 s,
- char do_accel, enum MatchMode mode) {
- const u8 *c = *c_inout;
- u32 sheng_end = m->sheng_end;
- u32 accel_limit = m->accel_limit_8;
- u32 accept_limit = m->accept_limit_8;
-
- const u32 as = m->alphaShift;
- const u8 *succ_table = (const u8 *)((const char *)m
- + sizeof(struct mcsheng));
- /* Adjust start of succ table so we can index into using state id (rather
- * than adjust to normal id). As we will not be processing states with low
- * state ids, we will not be accessing data before the succ table. Note: due
- * to the size of the sheng tables, the succ_table pointer will still be
- * inside the engine.*/
- succ_table -= sheng_end << as;
-
- assert(s >= sheng_end);
-
- while (c < end && s >= sheng_end) {
- u8 cprime = m->remap[*c];
- DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx\n", *c,
- ourisprint(*c) ? *c : '?', cprime);
- s = succ_table[(s << as) + cprime];
-
- DEBUG_PRINTF("s: %u\n", s);
- c++;
- if (do_accel) {
- if (s >= accel_limit) {
- break;
- }
- } else {
- if (mode != NO_MATCHES && s >= accept_limit) {
- break;
- }
- }
- }
- *c_inout = c;
- return s;
-}
-
-static really_inline
-char mcshengExec8_i(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **c_final, enum MatchMode mode) {
- if (!len) {
- *c_final = buf;
- return MO_ALIVE;
- }
- u32 s = *state;
- const u8 *c = buf;
- const u8 *c_end = buf + len;
- const u8 sheng_end = m->sheng_end;
-
- const struct mstate_aux *aux
- = (const struct mstate_aux *)((const char *)m + m->aux_offset
- - sizeof(struct NFA));
- u32 accept_limit = m->accept_limit_8;
-
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- DEBUG_PRINTF("accel %hu, accept %u\n", m->accel_limit_8, accept_limit);
-
- DEBUG_PRINTF("s: %u, len %zu\n", s, len);
-
- const u8 *min_accel_offset = c;
- if (!m->has_accel || len < ACCEL_MIN_LEN) {
- min_accel_offset = c_end;
- goto without_accel;
- }
-
- goto with_accel;
-
-without_accel:
- do {
- assert(c < min_accel_offset);
- if (!s) {
- goto exit;
- } else if (s < sheng_end) {
- s = doSheng(m, &c, min_accel_offset, c_end, s, 0);
- } else {
- s = doNormal8(m, &c, min_accel_offset, s, 0, mode);
- assert(c <= min_accel_offset);
- }
-
- if (mode != NO_MATCHES && s >= accept_limit) {
- if (mode == STOP_AT_MATCH) {
- DEBUG_PRINTF("match - pausing\n");
- *state = s;
- *c_final = c - 1;
- return MO_MATCHES_PENDING;
- }
-
- u64a loc = (c - 1) - buf + offAdj + 1;
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- assert(c <= c_end); /* sheng is fuzzy for min_accel_offset */
- } while (c < min_accel_offset);
-
- if (c == c_end) {
- goto exit;
- }
-
-with_accel:
- do {
- u32 accel_limit = m->accel_limit_8;
-
- assert(c < c_end);
- if (!s) {
- goto exit;
- } else if (s < sheng_end) {
- if (s > m->sheng_accel_limit) {
- c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
- s = doSheng(m, &c, c_end, c_end, s, 1);
- } else {
- if (s >= accel_limit && aux[s].accel_offset) {
- c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
- if (c == c_end) {
- goto exit;
- } else {
- goto without_accel;
- }
- }
- s = doNormal8(m, &c, c_end, s, 1, mode);
- }
-
- if (mode != NO_MATCHES && s >= accept_limit) {
- if (mode == STOP_AT_MATCH) {
- DEBUG_PRINTF("match - pausing\n");
- *state = s;
- *c_final = c - 1;
- return MO_MATCHES_PENDING;
- }
-
- u64a loc = (c - 1) - buf + offAdj + 1;
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
- &cached_accept_state, &cached_accept_id)
- == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- assert(c <= c_end);
- } while (c < c_end);
-
-exit:
- *state = s;
- if (mode == STOP_AT_MATCH) {
- *c_final = c_end;
- }
- return MO_ALIVE;
-}
-
-static never_inline
-char mcshengExec8_i_cb(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, CALLBACK_OUTPUT);
-}
-
-static never_inline
-char mcshengExec8_i_sam(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, STOP_AT_MATCH);
-}
-
-static never_inline
-char mcshengExec8_i_nm(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point) {
- return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point, NO_MATCHES);
-}
-
-static really_inline
-char mcshengExec8_i_ni(const struct mcsheng *m, u32 *state, const u8 *buf,
- size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
- char single, const u8 **final_point,
- enum MatchMode mode) {
- if (mode == CALLBACK_OUTPUT) {
- return mcshengExec8_i_cb(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point);
- } else if (mode == STOP_AT_MATCH) {
- return mcshengExec8_i_sam(m, state, buf, len, offAdj, cb, ctxt,
- single, final_point);
- } else {
- assert(mode == NO_MATCHES);
- return mcshengExec8_i_nm(m, state, buf, len, offAdj, cb, ctxt, single,
- final_point);
- }
-}
-
-static really_inline
-char mcshengCheckEOD(const struct NFA *nfa, u32 s, u64a offset,
- NfaCallback cb, void *ctxt) {
- const struct mcsheng *m = getImplNfa(nfa);
- const struct mstate_aux *aux = get_aux(m, s);
-
- if (!aux->accept_eod) {
- return MO_CONTINUE_MATCHING;
- }
- return doComplexReport(cb, ctxt, m, s, offset, 1, NULL, NULL);
-}
-
-static really_inline
-char nfaExecMcSheng16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
- const u8 *hend, NfaCallback cb, void *context,
- struct mq *q, char single, s64a end,
- enum MatchMode mode) {
- assert(n->type == MCSHENG_NFA_16);
- const struct mcsheng *m = getImplNfa(n);
- s64a sp;
-
- assert(ISALIGNED_N(q->state, 2));
- u32 s = *(u16 *)q->state;
-
- if (q->report_current) {
- assert(s);
- assert(get_aux(m, s)->accept);
-
- int rv;
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- rv = cb(0, q_cur_offset(q), m->arb_report, context);
- } else {
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
- &cached_accept_state, &cached_accept_id);
- }
-
- q->report_current = 0;
-
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- sp = q_cur_loc(q);
- q->cur++;
-
- const u8 *cur_buf = sp < 0 ? hend : buffer;
-
- assert(q->cur);
- if (mode != NO_MATCHES && q->items[q->cur - 1].location > end) {
- DEBUG_PRINTF("this is as far as we go\n");
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = end;
- *(u16 *)q->state = s;
- return MO_ALIVE;
- }
-
- while (1) {
- assert(q->cur < q->end);
- s64a ep = q->items[q->cur].location;
- if (mode != NO_MATCHES) {
- ep = MIN(ep, end);
- }
-
- assert(ep >= sp);
-
- s64a local_ep = ep;
- if (sp < 0) {
- local_ep = MIN(0, ep);
- }
-
- /* do main buffer region */
- const u8 *final_look;
- char rv = mcshengExec16_i_ni(m, &s, cur_buf + sp, local_ep - sp,
- offset + sp, cb, context, single,
- &final_look, mode);
- if (rv == MO_DEAD) {
- *(u16 *)q->state = 0;
- return MO_DEAD;
- }
- if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
- DEBUG_PRINTF("this is as far as we go\n");
- DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
-
- assert(q->cur);
- assert(final_look != cur_buf + local_ep);
-
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = final_look - cur_buf + 1; /* due to
- * early -1 */
- *(u16 *)q->state = s;
- return MO_MATCHES_PENDING;
- }
-
- assert(rv == MO_ALIVE);
- assert(q->cur);
- if (mode != NO_MATCHES && q->items[q->cur].location > end) {
- DEBUG_PRINTF("this is as far as we go\n");
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = end;
- *(u16 *)q->state = s;
- return MO_ALIVE;
- }
-
- sp = local_ep;
-
- if (sp == 0) {
- cur_buf = buffer;
- }
-
- if (sp != ep) {
- continue;
- }
-
- switch (q->items[q->cur].type) {
- case MQE_TOP:
- assert(sp + offset || !s);
- if (sp + offset == 0) {
- s = m->start_anchored;
- break;
- }
- s = mcshengEnableStarts(m, s);
- break;
- case MQE_END:
- *(u16 *)q->state = s;
- q->cur++;
- return s ? MO_ALIVE : MO_DEAD;
- default:
- assert(!"invalid queue event");
- }
-
- q->cur++;
- }
-}
-
-static really_inline
-char nfaExecMcSheng8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
- const u8 *hend, NfaCallback cb, void *context,
- struct mq *q, char single, s64a end,
- enum MatchMode mode) {
- assert(n->type == MCSHENG_NFA_8);
- const struct mcsheng *m = getImplNfa(n);
- s64a sp;
-
- u32 s = *(u8 *)q->state;
-
- if (q->report_current) {
- assert(s);
- assert(s >= m->accept_limit_8);
-
- int rv;
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- rv = cb(0, q_cur_offset(q), m->arb_report, context);
- } else {
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
- &cached_accept_state, &cached_accept_id);
- }
-
- q->report_current = 0;
-
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- }
-
- sp = q_cur_loc(q);
- q->cur++;
-
- const u8 *cur_buf = sp < 0 ? hend : buffer;
-
- if (mode != NO_MATCHES && q->items[q->cur - 1].location > end) {
- DEBUG_PRINTF("this is as far as we go\n");
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = end;
- *(u8 *)q->state = s;
- return MO_ALIVE;
- }
-
- while (1) {
- DEBUG_PRINTF("%s @ %llu\n", q->items[q->cur].type == MQE_TOP ? "TOP" :
- q->items[q->cur].type == MQE_END ? "END" : "???",
- q->items[q->cur].location + offset);
- assert(q->cur < q->end);
- s64a ep = q->items[q->cur].location;
- if (mode != NO_MATCHES) {
- ep = MIN(ep, end);
- }
-
- assert(ep >= sp);
-
- s64a local_ep = ep;
- if (sp < 0) {
- local_ep = MIN(0, ep);
- }
-
- const u8 *final_look;
- char rv = mcshengExec8_i_ni(m, &s, cur_buf + sp, local_ep - sp,
- offset + sp, cb, context, single,
- &final_look, mode);
- if (rv == MO_HALT_MATCHING) {
- *(u8 *)q->state = 0;
- return MO_DEAD;
- }
- if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
- DEBUG_PRINTF("this is as far as we go\n");
- DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
-
- assert(q->cur);
- assert(final_look != cur_buf + local_ep);
-
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = final_look - cur_buf + 1; /* due to
- * early -1 */
- *(u8 *)q->state = s;
- return MO_MATCHES_PENDING;
- }
-
- assert(rv == MO_ALIVE);
- assert(q->cur);
- if (mode != NO_MATCHES && q->items[q->cur].location > end) {
- DEBUG_PRINTF("this is as far as we go\n");
- assert(q->cur);
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = end;
- *(u8 *)q->state = s;
- return MO_ALIVE;
- }
-
- sp = local_ep;
-
- if (sp == 0) {
- cur_buf = buffer;
- }
-
- if (sp != ep) {
- continue;
- }
-
- switch (q->items[q->cur].type) {
- case MQE_TOP:
- assert(sp + offset || !s);
- if (sp + offset == 0) {
- s = (u8)m->start_anchored;
- break;
- }
- s = mcshengEnableStarts(m, s);
- break;
- case MQE_END:
- *(u8 *)q->state = s;
- q->cur++;
- return s ? MO_ALIVE : MO_DEAD;
- default:
- assert(!"invalid queue event");
- }
-
- q->cur++;
- }
-}
-
-char nfaExecMcSheng8_Q(const struct NFA *n, struct mq *q, s64a end) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_8);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- return nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, end,
- CALLBACK_OUTPUT);
-}
-
-char nfaExecMcSheng16_Q(const struct NFA *n, struct mq *q, s64a end) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_16);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- return nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, end,
- CALLBACK_OUTPUT);
-}
-
-char nfaExecMcSheng8_reportCurrent(const struct NFA *n, struct mq *q) {
- const struct mcsheng *m = getImplNfa(n);
- NfaCallback cb = q->cb;
- void *ctxt = q->context;
- u32 s = *(u8 *)q->state;
- u8 single = m->flags & MCSHENG_FLAG_SINGLE;
- u64a offset = q_cur_offset(q);
- assert(q_cur_type(q) == MQE_START);
- assert(s);
-
- if (s >= m->accept_limit_8) {
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- cb(0, offset, m->arb_report, ctxt);
- } else {
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
- &cached_accept_id);
- }
- }
-
- return 0;
-}
-
-char nfaExecMcSheng16_reportCurrent(const struct NFA *n, struct mq *q) {
- const struct mcsheng *m = getImplNfa(n);
- NfaCallback cb = q->cb;
- void *ctxt = q->context;
- u32 s = *(u16 *)q->state;
- const struct mstate_aux *aux = get_aux(m, s);
- u8 single = m->flags & MCSHENG_FLAG_SINGLE;
- u64a offset = q_cur_offset(q);
- assert(q_cur_type(q) == MQE_START);
- DEBUG_PRINTF("state %u\n", s);
- assert(s);
-
- if (aux->accept) {
- if (single) {
- DEBUG_PRINTF("reporting %u\n", m->arb_report);
- cb(0, offset, m->arb_report, ctxt);
- } else {
- u32 cached_accept_id = 0;
- u32 cached_accept_state = 0;
-
- doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
- &cached_accept_id);
- }
- }
-
- return 0;
-}
-
-static
-char mcshengHasAccept(const struct mcsheng *m, const struct mstate_aux *aux,
+ movd(s), movd(s_max));
+
+ SHENG_SINGLE_UNROLL_ITER(1);
+
+ SHENG_SINGLE_UNROLL_ITER(2);
+ SHENG_SINGLE_UNROLL_ITER(3);
+
+ SHENG_SINGLE_UNROLL_ITER(4);
+ SHENG_SINGLE_UNROLL_ITER(5);
+
+ SHENG_SINGLE_UNROLL_ITER(6);
+ SHENG_SINGLE_UNROLL_ITER(7);
+
+ if (movd(s_max7) >= sheng_limit_x4) {
+ DEBUG_PRINTF("exit found\n");
+
+ /* Explicitly check the last byte as it is more likely as it also
+ * checks for acceleration. */
+ if (movd(s_max6) < sheng_limit_x4) {
+ c += SHENG_CHUNK;
+ s_gpr = movq(s);
+ assert(s_gpr >= sheng_stop_limit);
+ goto exit;
+ }
+
+ /* use shift-xor to create a register containing all of the max
+ * values */
+ m128 blended = rshift64_m128(s_max0, 56);
+ blended = xor128(blended, rshift64_m128(s_max1, 48));
+ blended = xor128(blended, rshift64_m128(s_max2, 40));
+ blended = xor128(blended, rshift64_m128(s_max3, 32));
+ blended = xor128(blended, rshift64_m128(s_max4, 24));
+ blended = xor128(blended, rshift64_m128(s_max5, 16));
+ blended = xor128(blended, rshift64_m128(s_max6, 8));
+ blended = xor128(blended, s);
+ blended = xor128(blended, rshift64_m128(blended, 8));
+ DEBUG_PRINTF("blended %016llx\n", movq(blended));
+
+ m128 final = min_u8_m128(blended, simd_stop_limit);
+ m128 cmp = sub_u8_m128(final, simd_stop_limit);
+ u64a stops = ~movemask128(cmp);
+ assert(stops);
+ u32 earliest = ctz32(stops);
+ DEBUG_PRINTF("stops %02llx, earliest %u\n", stops, earliest);
+ assert(earliest < 8);
+ c += earliest + 1;
+ s_gpr = movq(blended) >> (earliest * 8);
+ assert(s_gpr >= sheng_stop_limit);
+ goto exit;
+ } else {
+ c += SHENG_CHUNK;
+ }
+#else
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+ SHENG_SINGLE_ITER;
+#endif
+ }
+
+ assert(c_end - c < SHENG_CHUNK);
+ if (c < soft_c_end) {
+ assert(soft_c_end - c < SHENG_CHUNK);
+ switch (soft_c_end - c) {
+ case 7:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 6:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 5:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 4:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 3:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 2:
+ SHENG_SINGLE_ITER; // fallthrough
+ case 1:
+ SHENG_SINGLE_ITER; // fallthrough
+ }
+ }
+
+ assert(c >= soft_c_end);
+
+ s_gpr = movd(s);
+exit:
+ assert(c <= hard_c_end);
+ DEBUG_PRINTF("%zu from end; s %hhu\n", c_end - c, s_gpr);
+ assert(c >= soft_c_end || s_gpr >= sheng_stop_limit);
+ /* undo state adjustment to match mcclellan view */
+ if (s_gpr == sheng_limit) {
+ s_gpr = 0;
+ } else if (s_gpr < sheng_limit) {
+ s_gpr++;
+ }
+
+ *c_inout = c;
+ return s_gpr;
+}
+
+static really_inline
+const char *findShermanState(UNUSED const struct mcsheng *m,
+ const char *sherman_base_offset, u32 sherman_base,
+ u32 s) {
+ const char *rv
+ = sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
+ assert(rv < (const char *)m + m->length - sizeof(struct NFA));
+ UNUSED u8 type = *(const u8 *)(rv + SHERMAN_TYPE_OFFSET);
+ assert(type == SHERMAN_STATE);
+ return rv;
+}
+
+static really_inline
+const u8 *run_mcsheng_accel(const struct mcsheng *m,
+ const struct mstate_aux *aux, u32 s,
+ const u8 **min_accel_offset,
+ const u8 *c, const u8 *c_end) {
+ DEBUG_PRINTF("skipping\n");
+ u32 accel_offset = aux[s].accel_offset;
+
+ assert(aux[s].accel_offset);
+ assert(accel_offset >= m->aux_offset);
+ assert(!m->sherman_offset || accel_offset < m->sherman_offset);
+
+ const union AccelAux *aaux = (const void *)((const char *)m + accel_offset);
+ const u8 *c2 = run_accel(aaux, c, c_end);
+
+ if (c2 < *min_accel_offset + BAD_ACCEL_DIST) {
+ *min_accel_offset = c2 + BIG_ACCEL_PENALTY;
+ } else {
+ *min_accel_offset = c2 + SMALL_ACCEL_PENALTY;
+ }
+
+ if (*min_accel_offset >= c_end - ACCEL_MIN_LEN) {
+ *min_accel_offset = c_end;
+ }
+
+ DEBUG_PRINTF("advanced %zd, next accel chance in %zd/%zd\n",
+ c2 - c, *min_accel_offset - c2, c_end - c2);
+
+ return c2;
+}
+
+static really_inline
+u32 doNormal16(const struct mcsheng *m, const u8 **c_inout, const u8 *end,
+ u32 s, char do_accel, enum MatchMode mode) {
+ const u8 *c = *c_inout;
+
+ const u16 *succ_table
+ = (const u16 *)((const char *)m + sizeof(struct mcsheng));
+ assert(ISALIGNED_N(succ_table, 2));
+ u32 sheng_end = m->sheng_end;
+ u32 sherman_base = m->sherman_limit;
+ const char *sherman_base_offset
+ = (const char *)m - sizeof(struct NFA) + m->sherman_offset;
+ u32 as = m->alphaShift;
+
+ /* Adjust start of succ table so we can index into using state id (rather
+ * than adjust to normal id). As we will not be processing states with low
+ * state ids, we will not be accessing data before the succ table. Note: due
+ * to the size of the sheng tables, the succ_table pointer will still be
+ * inside the engine.*/
+ succ_table -= sheng_end << as;
+
+ s &= STATE_MASK;
+
+ while (c < end && s >= sheng_end) {
+ u8 cprime = m->remap[*c];
+ DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx (s=%u)\n", *c,
+ ourisprint(*c) ? *c : '?', cprime, s);
+ if (s < sherman_base) {
+ DEBUG_PRINTF("doing normal\n");
+ assert(s < m->state_count);
+ s = succ_table[(s << as) + cprime];
+ } else {
+ const char *sherman_state
+ = findShermanState(m, sherman_base_offset, sherman_base, s);
+ DEBUG_PRINTF("doing sherman (%u)\n", s);
+ s = doSherman16(sherman_state, cprime, succ_table, as);
+ }
+
+ DEBUG_PRINTF("s: %u (%u)\n", s, s & STATE_MASK);
+ c++;
+
+ if (do_accel && (s & ACCEL_FLAG)) {
+ break;
+ }
+ if (mode != NO_MATCHES && (s & ACCEPT_FLAG)) {
+ break;
+ }
+
+ s &= STATE_MASK;
+ }
+
+ *c_inout = c;
+ return s;
+}
+
+static really_inline
+char mcshengExec16_i(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **c_final, enum MatchMode mode) {
+ assert(ISALIGNED_N(state, 2));
+ if (!len) {
+ if (mode == STOP_AT_MATCH) {
+ *c_final = buf;
+ }
+ return MO_ALIVE;
+ }
+
+ u32 s = *state;
+ const u8 *c = buf;
+ const u8 *c_end = buf + len;
+ const u8 sheng_end = m->sheng_end;
+ const struct mstate_aux *aux
+ = (const struct mstate_aux *)((const char *)m + m->aux_offset
+ - sizeof(struct NFA));
+
+ s &= STATE_MASK;
+
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ DEBUG_PRINTF("s: %u, len %zu\n", s, len);
+
+ const u8 *min_accel_offset = c;
+ if (!m->has_accel || len < ACCEL_MIN_LEN) {
+ min_accel_offset = c_end;
+ goto without_accel;
+ }
+
+ goto with_accel;
+
+without_accel:
+ do {
+ assert(c < min_accel_offset);
+ int do_accept;
+ if (!s) {
+ goto exit;
+ } else if (s < sheng_end) {
+ s = doSheng(m, &c, min_accel_offset, c_end, s, 0);
+ do_accept = mode != NO_MATCHES && get_aux(m, s)->accept;
+ } else {
+ s = doNormal16(m, &c, min_accel_offset, s, 0, mode);
+
+ do_accept = mode != NO_MATCHES && (s & ACCEPT_FLAG);
+ }
+
+ if (do_accept) {
+ if (mode == STOP_AT_MATCH) {
+ *state = s & STATE_MASK;
+ *c_final = c - 1;
+ return MO_MATCHES_PENDING;
+ }
+
+ u64a loc = (c - 1) - buf + offAdj + 1;
+
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD; /* termination requested */
+ }
+ } else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ assert(c <= c_end); /* sheng is fuzzy for min_accel_offset */
+ } while (c < min_accel_offset);
+
+ if (c == c_end) {
+ goto exit;
+ }
+
+with_accel:
+ do {
+ assert(c < c_end);
+ int do_accept;
+
+ if (!s) {
+ goto exit;
+ } else if (s < sheng_end) {
+ if (s > m->sheng_accel_limit) {
+ c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
+ }
+ s = doSheng(m, &c, c_end, c_end, s, 1);
+ do_accept = mode != NO_MATCHES && get_aux(m, s)->accept;
+ } else {
+ if (s & ACCEL_FLAG) {
+ DEBUG_PRINTF("skipping\n");
+ s &= STATE_MASK;
+ c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
+ }
+
+ s = doNormal16(m, &c, c_end, s, 1, mode);
+ do_accept = mode != NO_MATCHES && (s & ACCEPT_FLAG);
+ }
+
+ if (do_accept) {
+ if (mode == STOP_AT_MATCH) {
+ *state = s & STATE_MASK;
+ *c_final = c - 1;
+ return MO_MATCHES_PENDING;
+ }
+
+ u64a loc = (c - 1) - buf + offAdj + 1;
+
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD; /* termination requested */
+ }
+ } else if (doComplexReport(cb, ctxt, m, s & STATE_MASK, loc, 0,
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ assert(c <= c_end);
+ } while (c < c_end);
+
+exit:
+ s &= STATE_MASK;
+
+ if (mode == STOP_AT_MATCH) {
+ *c_final = c_end;
+ }
+ *state = s;
+
+ return MO_ALIVE;
+}
+
+static never_inline
+char mcshengExec16_i_cb(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, CALLBACK_OUTPUT);
+}
+
+static never_inline
+char mcshengExec16_i_sam(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, STOP_AT_MATCH);
+}
+
+static never_inline
+char mcshengExec16_i_nm(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec16_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, NO_MATCHES);
+}
+
+static really_inline
+char mcshengExec16_i_ni(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point,
+ enum MatchMode mode) {
+ if (mode == CALLBACK_OUTPUT) {
+ return mcshengExec16_i_cb(m, state, buf, len, offAdj, cb, ctxt,
+ single, final_point);
+ } else if (mode == STOP_AT_MATCH) {
+ return mcshengExec16_i_sam(m, state, buf, len, offAdj, cb, ctxt,
+ single, final_point);
+ } else {
+ assert (mode == NO_MATCHES);
+ return mcshengExec16_i_nm(m, state, buf, len, offAdj, cb, ctxt,
+ single, final_point);
+ }
+}
+
+static really_inline
+u32 doNormal8(const struct mcsheng *m, const u8 **c_inout, const u8 *end, u32 s,
+ char do_accel, enum MatchMode mode) {
+ const u8 *c = *c_inout;
+ u32 sheng_end = m->sheng_end;
+ u32 accel_limit = m->accel_limit_8;
+ u32 accept_limit = m->accept_limit_8;
+
+ const u32 as = m->alphaShift;
+ const u8 *succ_table = (const u8 *)((const char *)m
+ + sizeof(struct mcsheng));
+ /* Adjust start of succ table so we can index into using state id (rather
+ * than adjust to normal id). As we will not be processing states with low
+ * state ids, we will not be accessing data before the succ table. Note: due
+ * to the size of the sheng tables, the succ_table pointer will still be
+ * inside the engine.*/
+ succ_table -= sheng_end << as;
+
+ assert(s >= sheng_end);
+
+ while (c < end && s >= sheng_end) {
+ u8 cprime = m->remap[*c];
+ DEBUG_PRINTF("c: %02hhx '%c' cp:%02hhx\n", *c,
+ ourisprint(*c) ? *c : '?', cprime);
+ s = succ_table[(s << as) + cprime];
+
+ DEBUG_PRINTF("s: %u\n", s);
+ c++;
+ if (do_accel) {
+ if (s >= accel_limit) {
+ break;
+ }
+ } else {
+ if (mode != NO_MATCHES && s >= accept_limit) {
+ break;
+ }
+ }
+ }
+ *c_inout = c;
+ return s;
+}
+
+static really_inline
+char mcshengExec8_i(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **c_final, enum MatchMode mode) {
+ if (!len) {
+ *c_final = buf;
+ return MO_ALIVE;
+ }
+ u32 s = *state;
+ const u8 *c = buf;
+ const u8 *c_end = buf + len;
+ const u8 sheng_end = m->sheng_end;
+
+ const struct mstate_aux *aux
+ = (const struct mstate_aux *)((const char *)m + m->aux_offset
+ - sizeof(struct NFA));
+ u32 accept_limit = m->accept_limit_8;
+
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ DEBUG_PRINTF("accel %hu, accept %u\n", m->accel_limit_8, accept_limit);
+
+ DEBUG_PRINTF("s: %u, len %zu\n", s, len);
+
+ const u8 *min_accel_offset = c;
+ if (!m->has_accel || len < ACCEL_MIN_LEN) {
+ min_accel_offset = c_end;
+ goto without_accel;
+ }
+
+ goto with_accel;
+
+without_accel:
+ do {
+ assert(c < min_accel_offset);
+ if (!s) {
+ goto exit;
+ } else if (s < sheng_end) {
+ s = doSheng(m, &c, min_accel_offset, c_end, s, 0);
+ } else {
+ s = doNormal8(m, &c, min_accel_offset, s, 0, mode);
+ assert(c <= min_accel_offset);
+ }
+
+ if (mode != NO_MATCHES && s >= accept_limit) {
+ if (mode == STOP_AT_MATCH) {
+ DEBUG_PRINTF("match - pausing\n");
+ *state = s;
+ *c_final = c - 1;
+ return MO_MATCHES_PENDING;
+ }
+
+ u64a loc = (c - 1) - buf + offAdj + 1;
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ assert(c <= c_end); /* sheng is fuzzy for min_accel_offset */
+ } while (c < min_accel_offset);
+
+ if (c == c_end) {
+ goto exit;
+ }
+
+with_accel:
+ do {
+ u32 accel_limit = m->accel_limit_8;
+
+ assert(c < c_end);
+ if (!s) {
+ goto exit;
+ } else if (s < sheng_end) {
+ if (s > m->sheng_accel_limit) {
+ c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
+ }
+ s = doSheng(m, &c, c_end, c_end, s, 1);
+ } else {
+ if (s >= accel_limit && aux[s].accel_offset) {
+ c = run_mcsheng_accel(m, aux, s, &min_accel_offset, c, c_end);
+ if (c == c_end) {
+ goto exit;
+ } else {
+ goto without_accel;
+ }
+ }
+ s = doNormal8(m, &c, c_end, s, 1, mode);
+ }
+
+ if (mode != NO_MATCHES && s >= accept_limit) {
+ if (mode == STOP_AT_MATCH) {
+ DEBUG_PRINTF("match - pausing\n");
+ *state = s;
+ *c_final = c - 1;
+ return MO_MATCHES_PENDING;
+ }
+
+ u64a loc = (c - 1) - buf + offAdj + 1;
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ if (cb(0, loc, m->arb_report, ctxt) == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ } else if (doComplexReport(cb, ctxt, m, s, loc, 0,
+ &cached_accept_state, &cached_accept_id)
+ == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ assert(c <= c_end);
+ } while (c < c_end);
+
+exit:
+ *state = s;
+ if (mode == STOP_AT_MATCH) {
+ *c_final = c_end;
+ }
+ return MO_ALIVE;
+}
+
+static never_inline
+char mcshengExec8_i_cb(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, CALLBACK_OUTPUT);
+}
+
+static never_inline
+char mcshengExec8_i_sam(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, STOP_AT_MATCH);
+}
+
+static never_inline
+char mcshengExec8_i_nm(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point) {
+ return mcshengExec8_i(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point, NO_MATCHES);
+}
+
+static really_inline
+char mcshengExec8_i_ni(const struct mcsheng *m, u32 *state, const u8 *buf,
+ size_t len, u64a offAdj, NfaCallback cb, void *ctxt,
+ char single, const u8 **final_point,
+ enum MatchMode mode) {
+ if (mode == CALLBACK_OUTPUT) {
+ return mcshengExec8_i_cb(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point);
+ } else if (mode == STOP_AT_MATCH) {
+ return mcshengExec8_i_sam(m, state, buf, len, offAdj, cb, ctxt,
+ single, final_point);
+ } else {
+ assert(mode == NO_MATCHES);
+ return mcshengExec8_i_nm(m, state, buf, len, offAdj, cb, ctxt, single,
+ final_point);
+ }
+}
+
+static really_inline
+char mcshengCheckEOD(const struct NFA *nfa, u32 s, u64a offset,
+ NfaCallback cb, void *ctxt) {
+ const struct mcsheng *m = getImplNfa(nfa);
+ const struct mstate_aux *aux = get_aux(m, s);
+
+ if (!aux->accept_eod) {
+ return MO_CONTINUE_MATCHING;
+ }
+ return doComplexReport(cb, ctxt, m, s, offset, 1, NULL, NULL);
+}
+
+static really_inline
+char nfaExecMcSheng16_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
+ const u8 *hend, NfaCallback cb, void *context,
+ struct mq *q, char single, s64a end,
+ enum MatchMode mode) {
+ assert(n->type == MCSHENG_NFA_16);
+ const struct mcsheng *m = getImplNfa(n);
+ s64a sp;
+
+ assert(ISALIGNED_N(q->state, 2));
+ u32 s = *(u16 *)q->state;
+
+ if (q->report_current) {
+ assert(s);
+ assert(get_aux(m, s)->accept);
+
+ int rv;
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ rv = cb(0, q_cur_offset(q), m->arb_report, context);
+ } else {
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
+ &cached_accept_state, &cached_accept_id);
+ }
+
+ q->report_current = 0;
+
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ sp = q_cur_loc(q);
+ q->cur++;
+
+ const u8 *cur_buf = sp < 0 ? hend : buffer;
+
+ assert(q->cur);
+ if (mode != NO_MATCHES && q->items[q->cur - 1].location > end) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = end;
+ *(u16 *)q->state = s;
+ return MO_ALIVE;
+ }
+
+ while (1) {
+ assert(q->cur < q->end);
+ s64a ep = q->items[q->cur].location;
+ if (mode != NO_MATCHES) {
+ ep = MIN(ep, end);
+ }
+
+ assert(ep >= sp);
+
+ s64a local_ep = ep;
+ if (sp < 0) {
+ local_ep = MIN(0, ep);
+ }
+
+ /* do main buffer region */
+ const u8 *final_look;
+ char rv = mcshengExec16_i_ni(m, &s, cur_buf + sp, local_ep - sp,
+ offset + sp, cb, context, single,
+ &final_look, mode);
+ if (rv == MO_DEAD) {
+ *(u16 *)q->state = 0;
+ return MO_DEAD;
+ }
+ if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
+
+ assert(q->cur);
+ assert(final_look != cur_buf + local_ep);
+
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = final_look - cur_buf + 1; /* due to
+ * early -1 */
+ *(u16 *)q->state = s;
+ return MO_MATCHES_PENDING;
+ }
+
+ assert(rv == MO_ALIVE);
+ assert(q->cur);
+ if (mode != NO_MATCHES && q->items[q->cur].location > end) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = end;
+ *(u16 *)q->state = s;
+ return MO_ALIVE;
+ }
+
+ sp = local_ep;
+
+ if (sp == 0) {
+ cur_buf = buffer;
+ }
+
+ if (sp != ep) {
+ continue;
+ }
+
+ switch (q->items[q->cur].type) {
+ case MQE_TOP:
+ assert(sp + offset || !s);
+ if (sp + offset == 0) {
+ s = m->start_anchored;
+ break;
+ }
+ s = mcshengEnableStarts(m, s);
+ break;
+ case MQE_END:
+ *(u16 *)q->state = s;
+ q->cur++;
+ return s ? MO_ALIVE : MO_DEAD;
+ default:
+ assert(!"invalid queue event");
+ }
+
+ q->cur++;
+ }
+}
+
+static really_inline
+char nfaExecMcSheng8_Q2i(const struct NFA *n, u64a offset, const u8 *buffer,
+ const u8 *hend, NfaCallback cb, void *context,
+ struct mq *q, char single, s64a end,
+ enum MatchMode mode) {
+ assert(n->type == MCSHENG_NFA_8);
+ const struct mcsheng *m = getImplNfa(n);
+ s64a sp;
+
+ u32 s = *(u8 *)q->state;
+
+ if (q->report_current) {
+ assert(s);
+ assert(s >= m->accept_limit_8);
+
+ int rv;
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ rv = cb(0, q_cur_offset(q), m->arb_report, context);
+ } else {
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ rv = doComplexReport(cb, context, m, s, q_cur_offset(q), 0,
+ &cached_accept_state, &cached_accept_id);
+ }
+
+ q->report_current = 0;
+
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ }
+
+ sp = q_cur_loc(q);
+ q->cur++;
+
+ const u8 *cur_buf = sp < 0 ? hend : buffer;
+
+ if (mode != NO_MATCHES && q->items[q->cur - 1].location > end) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = end;
+ *(u8 *)q->state = s;
+ return MO_ALIVE;
+ }
+
+ while (1) {
+ DEBUG_PRINTF("%s @ %llu\n", q->items[q->cur].type == MQE_TOP ? "TOP" :
+ q->items[q->cur].type == MQE_END ? "END" : "???",
+ q->items[q->cur].location + offset);
+ assert(q->cur < q->end);
+ s64a ep = q->items[q->cur].location;
+ if (mode != NO_MATCHES) {
+ ep = MIN(ep, end);
+ }
+
+ assert(ep >= sp);
+
+ s64a local_ep = ep;
+ if (sp < 0) {
+ local_ep = MIN(0, ep);
+ }
+
+ const u8 *final_look;
+ char rv = mcshengExec8_i_ni(m, &s, cur_buf + sp, local_ep - sp,
+ offset + sp, cb, context, single,
+ &final_look, mode);
+ if (rv == MO_HALT_MATCHING) {
+ *(u8 *)q->state = 0;
+ return MO_DEAD;
+ }
+ if (mode == STOP_AT_MATCH && rv == MO_MATCHES_PENDING) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ DEBUG_PRINTF("state %u final_look %zd\n", s, final_look - cur_buf);
+
+ assert(q->cur);
+ assert(final_look != cur_buf + local_ep);
+
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = final_look - cur_buf + 1; /* due to
+ * early -1 */
+ *(u8 *)q->state = s;
+ return MO_MATCHES_PENDING;
+ }
+
+ assert(rv == MO_ALIVE);
+ assert(q->cur);
+ if (mode != NO_MATCHES && q->items[q->cur].location > end) {
+ DEBUG_PRINTF("this is as far as we go\n");
+ assert(q->cur);
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = end;
+ *(u8 *)q->state = s;
+ return MO_ALIVE;
+ }
+
+ sp = local_ep;
+
+ if (sp == 0) {
+ cur_buf = buffer;
+ }
+
+ if (sp != ep) {
+ continue;
+ }
+
+ switch (q->items[q->cur].type) {
+ case MQE_TOP:
+ assert(sp + offset || !s);
+ if (sp + offset == 0) {
+ s = (u8)m->start_anchored;
+ break;
+ }
+ s = mcshengEnableStarts(m, s);
+ break;
+ case MQE_END:
+ *(u8 *)q->state = s;
+ q->cur++;
+ return s ? MO_ALIVE : MO_DEAD;
+ default:
+ assert(!"invalid queue event");
+ }
+
+ q->cur++;
+ }
+}
+
+char nfaExecMcSheng8_Q(const struct NFA *n, struct mq *q, s64a end) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_8);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ return nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, end,
+ CALLBACK_OUTPUT);
+}
+
+char nfaExecMcSheng16_Q(const struct NFA *n, struct mq *q, s64a end) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_16);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ return nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, end,
+ CALLBACK_OUTPUT);
+}
+
+char nfaExecMcSheng8_reportCurrent(const struct NFA *n, struct mq *q) {
+ const struct mcsheng *m = getImplNfa(n);
+ NfaCallback cb = q->cb;
+ void *ctxt = q->context;
+ u32 s = *(u8 *)q->state;
+ u8 single = m->flags & MCSHENG_FLAG_SINGLE;
+ u64a offset = q_cur_offset(q);
+ assert(q_cur_type(q) == MQE_START);
+ assert(s);
+
+ if (s >= m->accept_limit_8) {
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ cb(0, offset, m->arb_report, ctxt);
+ } else {
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
+ &cached_accept_id);
+ }
+ }
+
+ return 0;
+}
+
+char nfaExecMcSheng16_reportCurrent(const struct NFA *n, struct mq *q) {
+ const struct mcsheng *m = getImplNfa(n);
+ NfaCallback cb = q->cb;
+ void *ctxt = q->context;
+ u32 s = *(u16 *)q->state;
+ const struct mstate_aux *aux = get_aux(m, s);
+ u8 single = m->flags & MCSHENG_FLAG_SINGLE;
+ u64a offset = q_cur_offset(q);
+ assert(q_cur_type(q) == MQE_START);
+ DEBUG_PRINTF("state %u\n", s);
+ assert(s);
+
+ if (aux->accept) {
+ if (single) {
+ DEBUG_PRINTF("reporting %u\n", m->arb_report);
+ cb(0, offset, m->arb_report, ctxt);
+ } else {
+ u32 cached_accept_id = 0;
+ u32 cached_accept_state = 0;
+
+ doComplexReport(cb, ctxt, m, s, offset, 0, &cached_accept_state,
+ &cached_accept_id);
+ }
+ }
+
+ return 0;
+}
+
+static
+char mcshengHasAccept(const struct mcsheng *m, const struct mstate_aux *aux,
ReportID report) {
- assert(m && aux);
-
- if (!aux->accept) {
- return 0;
- }
-
- const struct report_list *rl = (const struct report_list *)
- ((const char *)m + aux->accept - sizeof(struct NFA));
- assert(ISALIGNED_N(rl, 4));
-
- DEBUG_PRINTF("report list has %u entries\n", rl->count);
-
- for (u32 i = 0; i < rl->count; i++) {
- if (rl->report[i] == report) {
- return 1;
- }
- }
-
- return 0;
-}
-
-char nfaExecMcSheng8_inAccept(const struct NFA *n, ReportID report,
- struct mq *q) {
- assert(n && q);
-
- const struct mcsheng *m = getImplNfa(n);
- u8 s = *(u8 *)q->state;
- DEBUG_PRINTF("checking accepts for %hhu\n", s);
-
- return mcshengHasAccept(m, get_aux(m, s), report);
-}
-
-char nfaExecMcSheng8_inAnyAccept(const struct NFA *n, struct mq *q) {
- assert(n && q);
-
- const struct mcsheng *m = getImplNfa(n);
- u8 s = *(u8 *)q->state;
- DEBUG_PRINTF("checking accepts for %hhu\n", s);
-
- return !!get_aux(m, s)->accept;
-}
-
-char nfaExecMcSheng16_inAccept(const struct NFA *n, ReportID report,
- struct mq *q) {
- assert(n && q);
-
- const struct mcsheng *m = getImplNfa(n);
- u16 s = *(u16 *)q->state;
- DEBUG_PRINTF("checking accepts for %hu\n", s);
-
- return mcshengHasAccept(m, get_aux(m, s), report);
-}
-
-char nfaExecMcSheng16_inAnyAccept(const struct NFA *n, struct mq *q) {
- assert(n && q);
-
- const struct mcsheng *m = getImplNfa(n);
- u16 s = *(u16 *)q->state;
- DEBUG_PRINTF("checking accepts for %hu\n", s);
-
- return !!get_aux(m, s)->accept;
-}
-
-char nfaExecMcSheng8_Q2(const struct NFA *n, struct mq *q, s64a end) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_8);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- return nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, end,
- STOP_AT_MATCH);
-}
-
-char nfaExecMcSheng16_Q2(const struct NFA *n, struct mq *q, s64a end) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_16);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- return nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, end,
- STOP_AT_MATCH);
-}
-
-char nfaExecMcSheng8_QR(const struct NFA *n, struct mq *q, ReportID report) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_8);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- char rv = nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, 0 /* end */,
- NO_MATCHES);
- if (rv && nfaExecMcSheng8_inAccept(n, report, q)) {
- return MO_MATCHES_PENDING;
- } else {
- return rv;
- }
-}
-
-char nfaExecMcSheng16_QR(const struct NFA *n, struct mq *q, ReportID report) {
- u64a offset = q->offset;
- const u8 *buffer = q->buffer;
- NfaCallback cb = q->cb;
- void *context = q->context;
- assert(n->type == MCSHENG_NFA_16);
- const struct mcsheng *m = getImplNfa(n);
- const u8 *hend = q->history + q->hlength;
-
- char rv = nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
- m->flags & MCSHENG_FLAG_SINGLE, 0 /* end */,
- NO_MATCHES);
-
- if (rv && nfaExecMcSheng16_inAccept(n, report, q)) {
- return MO_MATCHES_PENDING;
- } else {
- return rv;
- }
-}
-
-char nfaExecMcSheng8_initCompressedState(const struct NFA *nfa, u64a offset,
- void *state, UNUSED u8 key) {
- const struct mcsheng *m = getImplNfa(nfa);
- u8 s = offset ? m->start_floating : m->start_anchored;
- if (s) {
- *(u8 *)state = s;
- return 1;
- }
- return 0;
-}
-
-char nfaExecMcSheng16_initCompressedState(const struct NFA *nfa, u64a offset,
- void *state, UNUSED u8 key) {
- const struct mcsheng *m = getImplNfa(nfa);
- u16 s = offset ? m->start_floating : m->start_anchored;
- if (s) {
- unaligned_store_u16(state, s);
- return 1;
- }
- return 0;
-}
-
-char nfaExecMcSheng8_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
- return mcshengCheckEOD(nfa, *(const u8 *)state, offset, callback,
- context);
-}
-
-char nfaExecMcSheng16_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
- assert(ISALIGNED_N(state, 2));
- return mcshengCheckEOD(nfa, *(const u16 *)state, offset, callback,
- context);
-}
-
-char nfaExecMcSheng8_queueInitState(UNUSED const struct NFA *nfa, struct mq *q) {
- assert(nfa->scratchStateSize == 1);
- *(u8 *)q->state = 0;
- return 0;
-}
-
-char nfaExecMcSheng16_queueInitState(UNUSED const struct NFA *nfa, struct mq *q) {
- assert(nfa->scratchStateSize == 2);
- assert(ISALIGNED_N(q->state, 2));
- *(u16 *)q->state = 0;
- return 0;
-}
-
-char nfaExecMcSheng8_queueCompressState(UNUSED const struct NFA *nfa,
- const struct mq *q, UNUSED s64a loc) {
- void *dest = q->streamState;
- const void *src = q->state;
- assert(nfa->scratchStateSize == 1);
- assert(nfa->streamStateSize == 1);
- *(u8 *)dest = *(const u8 *)src;
- return 0;
-}
-
-char nfaExecMcSheng8_expandState(UNUSED const struct NFA *nfa, void *dest,
- const void *src, UNUSED u64a offset,
- UNUSED u8 key) {
- assert(nfa->scratchStateSize == 1);
- assert(nfa->streamStateSize == 1);
- *(u8 *)dest = *(const u8 *)src;
- return 0;
-}
-
-char nfaExecMcSheng16_queueCompressState(UNUSED const struct NFA *nfa,
- const struct mq *q,
- UNUSED s64a loc) {
- void *dest = q->streamState;
- const void *src = q->state;
- assert(nfa->scratchStateSize == 2);
- assert(nfa->streamStateSize == 2);
- assert(ISALIGNED_N(src, 2));
- unaligned_store_u16(dest, *(const u16 *)(src));
- return 0;
-}
-
-char nfaExecMcSheng16_expandState(UNUSED const struct NFA *nfa, void *dest,
- const void *src, UNUSED u64a offset,
- UNUSED u8 key) {
- assert(nfa->scratchStateSize == 2);
- assert(nfa->streamStateSize == 2);
- assert(ISALIGNED_N(dest, 2));
- *(u16 *)dest = unaligned_load_u16(src);
- return 0;
-}
+ assert(m && aux);
+
+ if (!aux->accept) {
+ return 0;
+ }
+
+ const struct report_list *rl = (const struct report_list *)
+ ((const char *)m + aux->accept - sizeof(struct NFA));
+ assert(ISALIGNED_N(rl, 4));
+
+ DEBUG_PRINTF("report list has %u entries\n", rl->count);
+
+ for (u32 i = 0; i < rl->count; i++) {
+ if (rl->report[i] == report) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+char nfaExecMcSheng8_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q) {
+ assert(n && q);
+
+ const struct mcsheng *m = getImplNfa(n);
+ u8 s = *(u8 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hhu\n", s);
+
+ return mcshengHasAccept(m, get_aux(m, s), report);
+}
+
+char nfaExecMcSheng8_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+
+ const struct mcsheng *m = getImplNfa(n);
+ u8 s = *(u8 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hhu\n", s);
+
+ return !!get_aux(m, s)->accept;
+}
+
+char nfaExecMcSheng16_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q) {
+ assert(n && q);
+
+ const struct mcsheng *m = getImplNfa(n);
+ u16 s = *(u16 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hu\n", s);
+
+ return mcshengHasAccept(m, get_aux(m, s), report);
+}
+
+char nfaExecMcSheng16_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+
+ const struct mcsheng *m = getImplNfa(n);
+ u16 s = *(u16 *)q->state;
+ DEBUG_PRINTF("checking accepts for %hu\n", s);
+
+ return !!get_aux(m, s)->accept;
+}
+
+char nfaExecMcSheng8_Q2(const struct NFA *n, struct mq *q, s64a end) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_8);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ return nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, end,
+ STOP_AT_MATCH);
+}
+
+char nfaExecMcSheng16_Q2(const struct NFA *n, struct mq *q, s64a end) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_16);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ return nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, end,
+ STOP_AT_MATCH);
+}
+
+char nfaExecMcSheng8_QR(const struct NFA *n, struct mq *q, ReportID report) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_8);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ char rv = nfaExecMcSheng8_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, 0 /* end */,
+ NO_MATCHES);
+ if (rv && nfaExecMcSheng8_inAccept(n, report, q)) {
+ return MO_MATCHES_PENDING;
+ } else {
+ return rv;
+ }
+}
+
+char nfaExecMcSheng16_QR(const struct NFA *n, struct mq *q, ReportID report) {
+ u64a offset = q->offset;
+ const u8 *buffer = q->buffer;
+ NfaCallback cb = q->cb;
+ void *context = q->context;
+ assert(n->type == MCSHENG_NFA_16);
+ const struct mcsheng *m = getImplNfa(n);
+ const u8 *hend = q->history + q->hlength;
+
+ char rv = nfaExecMcSheng16_Q2i(n, offset, buffer, hend, cb, context, q,
+ m->flags & MCSHENG_FLAG_SINGLE, 0 /* end */,
+ NO_MATCHES);
+
+ if (rv && nfaExecMcSheng16_inAccept(n, report, q)) {
+ return MO_MATCHES_PENDING;
+ } else {
+ return rv;
+ }
+}
+
+char nfaExecMcSheng8_initCompressedState(const struct NFA *nfa, u64a offset,
+ void *state, UNUSED u8 key) {
+ const struct mcsheng *m = getImplNfa(nfa);
+ u8 s = offset ? m->start_floating : m->start_anchored;
+ if (s) {
+ *(u8 *)state = s;
+ return 1;
+ }
+ return 0;
+}
+
+char nfaExecMcSheng16_initCompressedState(const struct NFA *nfa, u64a offset,
+ void *state, UNUSED u8 key) {
+ const struct mcsheng *m = getImplNfa(nfa);
+ u16 s = offset ? m->start_floating : m->start_anchored;
+ if (s) {
+ unaligned_store_u16(state, s);
+ return 1;
+ }
+ return 0;
+}
+
+char nfaExecMcSheng8_testEOD(const struct NFA *nfa, const char *state,
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
+ return mcshengCheckEOD(nfa, *(const u8 *)state, offset, callback,
+ context);
+}
+
+char nfaExecMcSheng16_testEOD(const struct NFA *nfa, const char *state,
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
+ assert(ISALIGNED_N(state, 2));
+ return mcshengCheckEOD(nfa, *(const u16 *)state, offset, callback,
+ context);
+}
+
+char nfaExecMcSheng8_queueInitState(UNUSED const struct NFA *nfa, struct mq *q) {
+ assert(nfa->scratchStateSize == 1);
+ *(u8 *)q->state = 0;
+ return 0;
+}
+
+char nfaExecMcSheng16_queueInitState(UNUSED const struct NFA *nfa, struct mq *q) {
+ assert(nfa->scratchStateSize == 2);
+ assert(ISALIGNED_N(q->state, 2));
+ *(u16 *)q->state = 0;
+ return 0;
+}
+
+char nfaExecMcSheng8_queueCompressState(UNUSED const struct NFA *nfa,
+ const struct mq *q, UNUSED s64a loc) {
+ void *dest = q->streamState;
+ const void *src = q->state;
+ assert(nfa->scratchStateSize == 1);
+ assert(nfa->streamStateSize == 1);
+ *(u8 *)dest = *(const u8 *)src;
+ return 0;
+}
+
+char nfaExecMcSheng8_expandState(UNUSED const struct NFA *nfa, void *dest,
+ const void *src, UNUSED u64a offset,
+ UNUSED u8 key) {
+ assert(nfa->scratchStateSize == 1);
+ assert(nfa->streamStateSize == 1);
+ *(u8 *)dest = *(const u8 *)src;
+ return 0;
+}
+
+char nfaExecMcSheng16_queueCompressState(UNUSED const struct NFA *nfa,
+ const struct mq *q,
+ UNUSED s64a loc) {
+ void *dest = q->streamState;
+ const void *src = q->state;
+ assert(nfa->scratchStateSize == 2);
+ assert(nfa->streamStateSize == 2);
+ assert(ISALIGNED_N(src, 2));
+ unaligned_store_u16(dest, *(const u16 *)(src));
+ return 0;
+}
+
+char nfaExecMcSheng16_expandState(UNUSED const struct NFA *nfa, void *dest,
+ const void *src, UNUSED u64a offset,
+ UNUSED u8 key) {
+ assert(nfa->scratchStateSize == 2);
+ assert(nfa->streamStateSize == 2);
+ assert(ISALIGNED_N(dest, 2));
+ *(u16 *)dest = unaligned_load_u16(src);
+ return 0;
+}
#if defined(HAVE_AVX512VBMI)
static really_inline
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng.h b/contrib/libs/hyperscan/src/nfa/mcsheng.h
index 11ab588d0c5..0329e12128b 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng.h
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng.h
@@ -1,85 +1,85 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef MCSHENG_H
-#define MCSHENG_H
-
-#include "callback.h"
-#include "ue2common.h"
-
-struct mq;
-struct NFA;
-
-/* 8-bit Sheng-McClellan hybrid */
-
-char nfaExecMcSheng8_testEOD(const struct NFA *nfa, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context);
-char nfaExecMcSheng8_Q(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecMcSheng8_Q2(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecMcSheng8_QR(const struct NFA *n, struct mq *q, ReportID report);
-char nfaExecMcSheng8_reportCurrent(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng8_inAccept(const struct NFA *n, ReportID report,
- struct mq *q);
-char nfaExecMcSheng8_inAnyAccept(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng8_queueInitState(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng8_initCompressedState(const struct NFA *n, u64a offset,
- void *state, u8 key);
-char nfaExecMcSheng8_queueCompressState(const struct NFA *nfa,
- const struct mq *q, s64a loc);
-char nfaExecMcSheng8_expandState(const struct NFA *nfa, void *dest,
- const void *src, u64a offset, u8 key);
-
-#define nfaExecMcSheng8_B_Reverse NFA_API_NO_IMPL
-#define nfaExecMcSheng8_zombie_status NFA_API_ZOMBIE_NO_IMPL
-
-/* 16-bit Sheng-McClellan hybrid */
-
-char nfaExecMcSheng16_testEOD(const struct NFA *nfa, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context);
-char nfaExecMcSheng16_Q(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecMcSheng16_Q2(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecMcSheng16_QR(const struct NFA *n, struct mq *q, ReportID report);
-char nfaExecMcSheng16_reportCurrent(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng16_inAccept(const struct NFA *n, ReportID report,
- struct mq *q);
-char nfaExecMcSheng16_inAnyAccept(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng16_queueInitState(const struct NFA *n, struct mq *q);
-char nfaExecMcSheng16_initCompressedState(const struct NFA *n, u64a offset,
- void *state, u8 key);
-char nfaExecMcSheng16_queueCompressState(const struct NFA *nfa,
- const struct mq *q, s64a loc);
-char nfaExecMcSheng16_expandState(const struct NFA *nfa, void *dest,
- const void *src, u64a offset, u8 key);
-
-#define nfaExecMcSheng16_B_Reverse NFA_API_NO_IMPL
-#define nfaExecMcSheng16_zombie_status NFA_API_ZOMBIE_NO_IMPL
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef MCSHENG_H
+#define MCSHENG_H
+
+#include "callback.h"
+#include "ue2common.h"
+
+struct mq;
+struct NFA;
+
+/* 8-bit Sheng-McClellan hybrid */
+
+char nfaExecMcSheng8_testEOD(const struct NFA *nfa, const char *state,
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context);
+char nfaExecMcSheng8_Q(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecMcSheng8_Q2(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecMcSheng8_QR(const struct NFA *n, struct mq *q, ReportID report);
+char nfaExecMcSheng8_reportCurrent(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng8_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q);
+char nfaExecMcSheng8_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng8_queueInitState(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng8_initCompressedState(const struct NFA *n, u64a offset,
+ void *state, u8 key);
+char nfaExecMcSheng8_queueCompressState(const struct NFA *nfa,
+ const struct mq *q, s64a loc);
+char nfaExecMcSheng8_expandState(const struct NFA *nfa, void *dest,
+ const void *src, u64a offset, u8 key);
+
+#define nfaExecMcSheng8_B_Reverse NFA_API_NO_IMPL
+#define nfaExecMcSheng8_zombie_status NFA_API_ZOMBIE_NO_IMPL
+
+/* 16-bit Sheng-McClellan hybrid */
+
+char nfaExecMcSheng16_testEOD(const struct NFA *nfa, const char *state,
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context);
+char nfaExecMcSheng16_Q(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecMcSheng16_Q2(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecMcSheng16_QR(const struct NFA *n, struct mq *q, ReportID report);
+char nfaExecMcSheng16_reportCurrent(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng16_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q);
+char nfaExecMcSheng16_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng16_queueInitState(const struct NFA *n, struct mq *q);
+char nfaExecMcSheng16_initCompressedState(const struct NFA *n, u64a offset,
+ void *state, u8 key);
+char nfaExecMcSheng16_queueCompressState(const struct NFA *nfa,
+ const struct mq *q, s64a loc);
+char nfaExecMcSheng16_expandState(const struct NFA *nfa, void *dest,
+ const void *src, u64a offset, u8 key);
+
+#define nfaExecMcSheng16_B_Reverse NFA_API_NO_IMPL
+#define nfaExecMcSheng16_zombie_status NFA_API_ZOMBIE_NO_IMPL
#if defined(HAVE_AVX512VBMI)
/* 64-8 bit Sheng-McClellan hybrid */
char nfaExecMcSheng64_8_testEOD(const struct NFA *nfa, const char *state,
@@ -99,7 +99,7 @@ char nfaExecMcSheng64_8_queueCompressState(const struct NFA *nfa,
const struct mq *q, s64a loc);
char nfaExecMcSheng64_8_expandState(const struct NFA *nfa, void *dest,
const void *src, u64a offset, u8 key);
-
+
#define nfaExecMcSheng64_8_B_Reverse NFA_API_NO_IMPL
#define nfaExecMcSheng64_8_zombie_status NFA_API_ZOMBIE_NO_IMPL
@@ -154,4 +154,4 @@ char nfaExecMcSheng64_16_expandState(const struct NFA *nfa, void *dest,
#endif //end of HAVE_AVX512VBMI
-#endif
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng_compile.cpp b/contrib/libs/hyperscan/src/nfa/mcsheng_compile.cpp
index 4cb40c64358..fb75e49a352 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng_compile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng_compile.cpp
@@ -1,249 +1,249 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "mcsheng_compile.h"
-
-#include "accel.h"
-#include "accelcompile.h"
-#include "grey.h"
-#include "mcclellancompile.h"
-#include "mcclellancompile_util.h"
-#include "mcsheng_internal.h"
-#include "nfa_internal.h"
-#include "rdfa_graph.h"
-#include "shufticompile.h"
-#include "trufflecompile.h"
-#include "ue2common.h"
-#include "util/alloc.h"
-#include "util/bitutils.h"
-#include "util/charreach.h"
-#include "util/compare.h"
-#include "util/compile_context.h"
-#include "util/container.h"
-#include "util/flat_containers.h"
-#include "util/graph.h"
-#include "util/graph_range.h"
-#include "util/make_unique.h"
-#include "util/order_check.h"
-#include "util/report_manager.h"
-#include "util/unaligned.h"
-#include "util/unordered.h"
-#include "util/verify_types.h"
-
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <map>
-#include <memory>
-#include <set>
-#include <deque>
-#include <vector>
-#include <boost/range/adaptor/map.hpp>
-
-using namespace std;
-using boost::adaptors::map_keys;
-
-namespace ue2 {
-
-namespace /* anon */ {
-
-#define MIN_SHENG_SIZE 6
-#define INVALID_SHENG_ID 255
-
-struct dstate_extra {
- u16 daddytaken = 0;
- bool shermanState = false;
- bool sheng_succ = false;
- u8 sheng_id = INVALID_SHENG_ID;
-};
-
-struct dfa_info {
- accel_dfa_build_strat &strat;
- raw_dfa &raw;
- vector<dstate> &states;
- vector<dstate_extra> extra;
- const u16 alpha_size; /* including special symbols */
- const array<u16, ALPHABET_SIZE> &alpha_remap;
- vector<CharReach> rev_alpha;
- const u16 impl_alpha_size;
-
- u8 getAlphaShift() const;
-
- explicit dfa_info(accel_dfa_build_strat &s)
- : strat(s),
- raw(s.get_raw()),
- states(raw.states),
- extra(raw.states.size()),
- alpha_size(raw.alpha_size),
- alpha_remap(raw.alpha_remap),
- impl_alpha_size(raw.getImplAlphaSize()) {
- rev_alpha.resize(impl_alpha_size);
- for (u32 i = 0; i < N_CHARS; i++) {
- rev_alpha[alpha_remap[i]].set(i);
- }
- }
-
- dstate_id_t implId(dstate_id_t raw_id) const {
- return states[raw_id].impl_id;
- }
-
- bool is_sherman(dstate_id_t raw_id) const {
- return extra[raw_id].shermanState;
- }
-
- bool is_sheng(dstate_id_t raw_id) const {
- return extra[raw_id].sheng_id != INVALID_SHENG_ID;
- }
-
- bool is_sheng_succ(dstate_id_t raw_id) const {
- return extra[raw_id].sheng_succ;
- }
-
- /* states which use the normal transition/successor table */
- bool is_normal(dstate_id_t raw_id) const {
- return raw_id != DEAD_STATE && !is_sheng(raw_id) && !is_sherman(raw_id);
- }
- size_t size(void) const { return states.size(); }
-};
-
-u8 dfa_info::getAlphaShift() const {
- if (impl_alpha_size < 2) {
- return 1;
- } else {
- /* log2 round up */
- return 32 - clz32(impl_alpha_size - 1);
- }
-}
-
-} // namespace
-
-static
-mstate_aux *getAux(NFA *n, dstate_id_t i) {
- mcsheng *m = (mcsheng *)getMutableImplNfa(n);
- mstate_aux *aux_base = (mstate_aux *)((char *)n + m->aux_offset);
-
- mstate_aux *aux = aux_base + i;
- assert((const char *)aux < (const char *)n + m->length);
- return aux;
-}
-
-static
-void createShuffleMasks(mcsheng *m, const dfa_info &info,
- dstate_id_t sheng_end,
- const map<dstate_id_t, AccelScheme> &accel_escape_info) {
- DEBUG_PRINTF("using first %hu states for a sheng\n", sheng_end);
- assert(sheng_end > DEAD_STATE + 1);
- assert(sheng_end <= sizeof(m128) + 1);
- vector<array<u8, sizeof(m128)>> masks;
- masks.resize(info.alpha_size);
- /* -1 to avoid wasting a slot as we do not include dead state */
- vector<dstate_id_t> raw_ids;
- raw_ids.resize(sheng_end - 1);
- for (dstate_id_t s = DEAD_STATE + 1; s < info.states.size(); s++) {
- assert(info.implId(s)); /* should not map to DEAD_STATE */
- if (info.is_sheng(s)) {
- raw_ids[info.extra[s].sheng_id] = s;
- }
- }
- for (u32 i = 0; i < info.alpha_size; i++) {
- if (i == info.alpha_remap[TOP]) {
- continue;
- }
- auto &mask = masks[i];
- assert(sizeof(mask) == sizeof(m128));
- mask.fill(0);
-
- for (dstate_id_t sheng_id = 0; sheng_id < sheng_end - 1; sheng_id++) {
- dstate_id_t raw_id = raw_ids[sheng_id];
- dstate_id_t next_id = info.implId(info.states[raw_id].next[i]);
- if (next_id == DEAD_STATE) {
- next_id = sheng_end - 1;
- } else if (next_id < sheng_end) {
- next_id--;
- }
- DEBUG_PRINTF("%hu: %u->next %hu\n", sheng_id, i, next_id);
- mask[sheng_id] = verify_u8(next_id);
- }
- }
- for (u32 i = 0; i < N_CHARS; i++) {
- assert(info.alpha_remap[i] != info.alpha_remap[TOP]);
- memcpy((u8 *)&m->sheng_masks[i],
- (u8 *)masks[info.alpha_remap[i]].data(), sizeof(m128));
- }
- m->sheng_end = sheng_end;
- m->sheng_accel_limit = sheng_end - 1;
-
- for (dstate_id_t s : raw_ids) {
- if (contains(accel_escape_info, s)) {
- LIMIT_TO_AT_MOST(&m->sheng_accel_limit, info.extra[s].sheng_id);
- }
- }
-}
-
-static
-void populateBasicInfo(size_t state_size, const dfa_info &info,
- u32 total_size, u32 aux_offset, u32 accel_offset,
- u32 accel_count, ReportID arb, bool single, NFA *nfa) {
- assert(state_size == sizeof(u16) || state_size == sizeof(u8));
-
- nfa->length = total_size;
- nfa->nPositions = info.states.size();
-
- nfa->scratchStateSize = verify_u32(state_size);
- nfa->streamStateSize = verify_u32(state_size);
-
- if (state_size == sizeof(u8)) {
- nfa->type = MCSHENG_NFA_8;
- } else {
- nfa->type = MCSHENG_NFA_16;
- }
-
- mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
- for (u32 i = 0; i < 256; i++) {
- m->remap[i] = verify_u8(info.alpha_remap[i]);
- }
- m->alphaShift = info.getAlphaShift();
- m->length = total_size;
- m->aux_offset = aux_offset;
- m->accel_offset = accel_offset;
- m->arb_report = arb;
- m->state_count = verify_u16(info.size());
- m->start_anchored = info.implId(info.raw.start_anchored);
- m->start_floating = info.implId(info.raw.start_floating);
- m->has_accel = accel_count ? 1 : 0;
-
- if (single) {
- m->flags |= MCSHENG_FLAG_SINGLE;
- }
-}
-
-static
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "mcsheng_compile.h"
+
+#include "accel.h"
+#include "accelcompile.h"
+#include "grey.h"
+#include "mcclellancompile.h"
+#include "mcclellancompile_util.h"
+#include "mcsheng_internal.h"
+#include "nfa_internal.h"
+#include "rdfa_graph.h"
+#include "shufticompile.h"
+#include "trufflecompile.h"
+#include "ue2common.h"
+#include "util/alloc.h"
+#include "util/bitutils.h"
+#include "util/charreach.h"
+#include "util/compare.h"
+#include "util/compile_context.h"
+#include "util/container.h"
+#include "util/flat_containers.h"
+#include "util/graph.h"
+#include "util/graph_range.h"
+#include "util/make_unique.h"
+#include "util/order_check.h"
+#include "util/report_manager.h"
+#include "util/unaligned.h"
+#include "util/unordered.h"
+#include "util/verify_types.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <set>
+#include <deque>
+#include <vector>
+#include <boost/range/adaptor/map.hpp>
+
+using namespace std;
+using boost::adaptors::map_keys;
+
+namespace ue2 {
+
+namespace /* anon */ {
+
+#define MIN_SHENG_SIZE 6
+#define INVALID_SHENG_ID 255
+
+struct dstate_extra {
+ u16 daddytaken = 0;
+ bool shermanState = false;
+ bool sheng_succ = false;
+ u8 sheng_id = INVALID_SHENG_ID;
+};
+
+struct dfa_info {
+ accel_dfa_build_strat &strat;
+ raw_dfa &raw;
+ vector<dstate> &states;
+ vector<dstate_extra> extra;
+ const u16 alpha_size; /* including special symbols */
+ const array<u16, ALPHABET_SIZE> &alpha_remap;
+ vector<CharReach> rev_alpha;
+ const u16 impl_alpha_size;
+
+ u8 getAlphaShift() const;
+
+ explicit dfa_info(accel_dfa_build_strat &s)
+ : strat(s),
+ raw(s.get_raw()),
+ states(raw.states),
+ extra(raw.states.size()),
+ alpha_size(raw.alpha_size),
+ alpha_remap(raw.alpha_remap),
+ impl_alpha_size(raw.getImplAlphaSize()) {
+ rev_alpha.resize(impl_alpha_size);
+ for (u32 i = 0; i < N_CHARS; i++) {
+ rev_alpha[alpha_remap[i]].set(i);
+ }
+ }
+
+ dstate_id_t implId(dstate_id_t raw_id) const {
+ return states[raw_id].impl_id;
+ }
+
+ bool is_sherman(dstate_id_t raw_id) const {
+ return extra[raw_id].shermanState;
+ }
+
+ bool is_sheng(dstate_id_t raw_id) const {
+ return extra[raw_id].sheng_id != INVALID_SHENG_ID;
+ }
+
+ bool is_sheng_succ(dstate_id_t raw_id) const {
+ return extra[raw_id].sheng_succ;
+ }
+
+ /* states which use the normal transition/successor table */
+ bool is_normal(dstate_id_t raw_id) const {
+ return raw_id != DEAD_STATE && !is_sheng(raw_id) && !is_sherman(raw_id);
+ }
+ size_t size(void) const { return states.size(); }
+};
+
+u8 dfa_info::getAlphaShift() const {
+ if (impl_alpha_size < 2) {
+ return 1;
+ } else {
+ /* log2 round up */
+ return 32 - clz32(impl_alpha_size - 1);
+ }
+}
+
+} // namespace
+
+static
+mstate_aux *getAux(NFA *n, dstate_id_t i) {
+ mcsheng *m = (mcsheng *)getMutableImplNfa(n);
+ mstate_aux *aux_base = (mstate_aux *)((char *)n + m->aux_offset);
+
+ mstate_aux *aux = aux_base + i;
+ assert((const char *)aux < (const char *)n + m->length);
+ return aux;
+}
+
+static
+void createShuffleMasks(mcsheng *m, const dfa_info &info,
+ dstate_id_t sheng_end,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info) {
+ DEBUG_PRINTF("using first %hu states for a sheng\n", sheng_end);
+ assert(sheng_end > DEAD_STATE + 1);
+ assert(sheng_end <= sizeof(m128) + 1);
+ vector<array<u8, sizeof(m128)>> masks;
+ masks.resize(info.alpha_size);
+ /* -1 to avoid wasting a slot as we do not include dead state */
+ vector<dstate_id_t> raw_ids;
+ raw_ids.resize(sheng_end - 1);
+ for (dstate_id_t s = DEAD_STATE + 1; s < info.states.size(); s++) {
+ assert(info.implId(s)); /* should not map to DEAD_STATE */
+ if (info.is_sheng(s)) {
+ raw_ids[info.extra[s].sheng_id] = s;
+ }
+ }
+ for (u32 i = 0; i < info.alpha_size; i++) {
+ if (i == info.alpha_remap[TOP]) {
+ continue;
+ }
+ auto &mask = masks[i];
+ assert(sizeof(mask) == sizeof(m128));
+ mask.fill(0);
+
+ for (dstate_id_t sheng_id = 0; sheng_id < sheng_end - 1; sheng_id++) {
+ dstate_id_t raw_id = raw_ids[sheng_id];
+ dstate_id_t next_id = info.implId(info.states[raw_id].next[i]);
+ if (next_id == DEAD_STATE) {
+ next_id = sheng_end - 1;
+ } else if (next_id < sheng_end) {
+ next_id--;
+ }
+ DEBUG_PRINTF("%hu: %u->next %hu\n", sheng_id, i, next_id);
+ mask[sheng_id] = verify_u8(next_id);
+ }
+ }
+ for (u32 i = 0; i < N_CHARS; i++) {
+ assert(info.alpha_remap[i] != info.alpha_remap[TOP]);
+ memcpy((u8 *)&m->sheng_masks[i],
+ (u8 *)masks[info.alpha_remap[i]].data(), sizeof(m128));
+ }
+ m->sheng_end = sheng_end;
+ m->sheng_accel_limit = sheng_end - 1;
+
+ for (dstate_id_t s : raw_ids) {
+ if (contains(accel_escape_info, s)) {
+ LIMIT_TO_AT_MOST(&m->sheng_accel_limit, info.extra[s].sheng_id);
+ }
+ }
+}
+
+static
+void populateBasicInfo(size_t state_size, const dfa_info &info,
+ u32 total_size, u32 aux_offset, u32 accel_offset,
+ u32 accel_count, ReportID arb, bool single, NFA *nfa) {
+ assert(state_size == sizeof(u16) || state_size == sizeof(u8));
+
+ nfa->length = total_size;
+ nfa->nPositions = info.states.size();
+
+ nfa->scratchStateSize = verify_u32(state_size);
+ nfa->streamStateSize = verify_u32(state_size);
+
+ if (state_size == sizeof(u8)) {
+ nfa->type = MCSHENG_NFA_8;
+ } else {
+ nfa->type = MCSHENG_NFA_16;
+ }
+
+ mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
+ for (u32 i = 0; i < 256; i++) {
+ m->remap[i] = verify_u8(info.alpha_remap[i]);
+ }
+ m->alphaShift = info.getAlphaShift();
+ m->length = total_size;
+ m->aux_offset = aux_offset;
+ m->accel_offset = accel_offset;
+ m->arb_report = arb;
+ m->state_count = verify_u16(info.size());
+ m->start_anchored = info.implId(info.raw.start_anchored);
+ m->start_floating = info.implId(info.raw.start_floating);
+ m->has_accel = accel_count ? 1 : 0;
+
+ if (single) {
+ m->flags |= MCSHENG_FLAG_SINGLE;
+ }
+}
+
+static
mstate_aux *getAux64(NFA *n, dstate_id_t i) {
mcsheng64 *m = (mcsheng64 *)getMutableImplNfa(n);
mstate_aux *aux_base = (mstate_aux *)((char *)n + m->aux_offset);
@@ -344,379 +344,379 @@ void populateBasicInfo64(size_t state_size, const dfa_info &info,
}
static
-size_t calcShermanRegionSize(const dfa_info &info) {
- size_t rv = 0;
-
- for (size_t i = 0; i < info.size(); i++) {
- if (info.is_sherman(i)) {
- rv += SHERMAN_FIXED_SIZE;
- }
- }
-
- return ROUNDUP_16(rv);
-}
-
-static
-void fillInAux(mstate_aux *aux, dstate_id_t i, const dfa_info &info,
- const vector<u32> &reports, const vector<u32> &reports_eod,
- const vector<u32> &reportOffsets) {
- const dstate &raw_state = info.states[i];
- aux->accept = raw_state.reports.empty() ? 0 : reportOffsets[reports[i]];
- aux->accept_eod = raw_state.reports_eod.empty() ? 0
- : reportOffsets[reports_eod[i]];
- aux->top = info.implId(i ? raw_state.next[info.alpha_remap[TOP]]
- : info.raw.start_floating);
-}
-
-/* returns false on error */
-static
-bool allocateImplId16(dfa_info &info, dstate_id_t sheng_end,
+size_t calcShermanRegionSize(const dfa_info &info) {
+ size_t rv = 0;
+
+ for (size_t i = 0; i < info.size(); i++) {
+ if (info.is_sherman(i)) {
+ rv += SHERMAN_FIXED_SIZE;
+ }
+ }
+
+ return ROUNDUP_16(rv);
+}
+
+static
+void fillInAux(mstate_aux *aux, dstate_id_t i, const dfa_info &info,
+ const vector<u32> &reports, const vector<u32> &reports_eod,
+ const vector<u32> &reportOffsets) {
+ const dstate &raw_state = info.states[i];
+ aux->accept = raw_state.reports.empty() ? 0 : reportOffsets[reports[i]];
+ aux->accept_eod = raw_state.reports_eod.empty() ? 0
+ : reportOffsets[reports_eod[i]];
+ aux->top = info.implId(i ? raw_state.next[info.alpha_remap[TOP]]
+ : info.raw.start_floating);
+}
+
+/* returns false on error */
+static
+bool allocateImplId16(dfa_info &info, dstate_id_t sheng_end,
dstate_id_t *sherman_base) {
- info.states[0].impl_id = 0; /* dead is always 0 */
-
- vector<dstate_id_t> norm;
- vector<dstate_id_t> sherm;
- vector<dstate_id_t> norm_sheng_succ;
- vector<dstate_id_t> sherm_sheng_succ;
-
- if (info.size() > (1 << 16)) {
- DEBUG_PRINTF("too many states\n");
- *sherman_base = 0;
- return false;
- }
-
- for (u32 i = 1; i < info.size(); i++) {
- if (info.is_sheng(i)) {
- continue; /* sheng impl ids have already been allocated */
- } if (info.is_sherman(i)) {
- if (info.is_sheng_succ(i)) {
- sherm_sheng_succ.push_back(i);
- } else {
- sherm.push_back(i);
- }
- } else {
- if (info.is_sheng_succ(i)) {
- norm_sheng_succ.push_back(i);
- } else {
- norm.push_back(i);
- }
- }
- }
-
- dstate_id_t next_norm = sheng_end;
- for (dstate_id_t s : norm_sheng_succ) {
- info.states[s].impl_id = next_norm++;
- }
- if (next_norm + norm.size() + sherm_sheng_succ.size() > UINT8_MAX) {
- /* we need to give sheng_succs ids which fit into a u8 -- demote these
- * to normal states */
- for (dstate_id_t s : sherm_sheng_succ) {
- info.states[s].impl_id = next_norm++;
- info.extra[s].shermanState = false;
- }
- sherm_sheng_succ.clear();
- }
- for (dstate_id_t s : norm) {
- info.states[s].impl_id = next_norm++;
- }
-
- *sherman_base = next_norm;
- dstate_id_t next_sherman = next_norm;
-
- for (dstate_id_t s : sherm_sheng_succ) {
- info.states[s].impl_id = next_sherman++;
- }
-
- for (dstate_id_t s : sherm) {
- info.states[s].impl_id = next_sherman++;
- }
-
- /* Check to see if we haven't over allocated our states */
- DEBUG_PRINTF("next sherman %u masked %u\n", next_sherman,
- (dstate_id_t)(next_sherman & STATE_MASK));
- return (next_sherman - 1) == ((next_sherman - 1) & STATE_MASK);
-}
-
-typedef RdfaGraph::vertex_descriptor RdfaVertex;
-
-static
-bool mark_sheng_succs(const RdfaGraph &g, dfa_info &info,
- const flat_set<RdfaVertex> &sheng_states) {
- u32 exit_count = 0;
-
- for (auto v : sheng_states) {
- dstate_id_t s = g[v].index;
- for (u32 i = 0; i != info.alpha_size; i++) {
- if (i == info.alpha_remap[TOP]) {
- continue;
- }
- dstate_id_t next = info.states[s].next[i];
- if (!next || info.is_sheng(next) || info.is_sheng_succ(next)) {
- continue;
- }
- exit_count++;
- info.extra[next].sheng_succ = true;
- }
- }
-
- if (exit_count + sheng_states.size() < UINT8_MAX) {
- return true;
- } else {
- DEBUG_PRINTF("fail: unable to fit %u exits in byte", exit_count);
- return false;
- }
-}
-
-static
-CharReach get_edge_reach(dstate_id_t u, dstate_id_t v, const dfa_info &info) {
- CharReach rv;
- for (u32 i = 0; i < info.impl_alpha_size; i++) {
- if (info.raw.states[u].next[i] == v) {
- assert(info.rev_alpha[i].any());
- rv |= info.rev_alpha[i];
- }
- }
- assert(rv.any());
- return rv;
-}
-
-#define MAX_SHENG_STATES 16
+ info.states[0].impl_id = 0; /* dead is always 0 */
+
+ vector<dstate_id_t> norm;
+ vector<dstate_id_t> sherm;
+ vector<dstate_id_t> norm_sheng_succ;
+ vector<dstate_id_t> sherm_sheng_succ;
+
+ if (info.size() > (1 << 16)) {
+ DEBUG_PRINTF("too many states\n");
+ *sherman_base = 0;
+ return false;
+ }
+
+ for (u32 i = 1; i < info.size(); i++) {
+ if (info.is_sheng(i)) {
+ continue; /* sheng impl ids have already been allocated */
+ } if (info.is_sherman(i)) {
+ if (info.is_sheng_succ(i)) {
+ sherm_sheng_succ.push_back(i);
+ } else {
+ sherm.push_back(i);
+ }
+ } else {
+ if (info.is_sheng_succ(i)) {
+ norm_sheng_succ.push_back(i);
+ } else {
+ norm.push_back(i);
+ }
+ }
+ }
+
+ dstate_id_t next_norm = sheng_end;
+ for (dstate_id_t s : norm_sheng_succ) {
+ info.states[s].impl_id = next_norm++;
+ }
+ if (next_norm + norm.size() + sherm_sheng_succ.size() > UINT8_MAX) {
+ /* we need to give sheng_succs ids which fit into a u8 -- demote these
+ * to normal states */
+ for (dstate_id_t s : sherm_sheng_succ) {
+ info.states[s].impl_id = next_norm++;
+ info.extra[s].shermanState = false;
+ }
+ sherm_sheng_succ.clear();
+ }
+ for (dstate_id_t s : norm) {
+ info.states[s].impl_id = next_norm++;
+ }
+
+ *sherman_base = next_norm;
+ dstate_id_t next_sherman = next_norm;
+
+ for (dstate_id_t s : sherm_sheng_succ) {
+ info.states[s].impl_id = next_sherman++;
+ }
+
+ for (dstate_id_t s : sherm) {
+ info.states[s].impl_id = next_sherman++;
+ }
+
+ /* Check to see if we haven't over allocated our states */
+ DEBUG_PRINTF("next sherman %u masked %u\n", next_sherman,
+ (dstate_id_t)(next_sherman & STATE_MASK));
+ return (next_sherman - 1) == ((next_sherman - 1) & STATE_MASK);
+}
+
+typedef RdfaGraph::vertex_descriptor RdfaVertex;
+
+static
+bool mark_sheng_succs(const RdfaGraph &g, dfa_info &info,
+ const flat_set<RdfaVertex> &sheng_states) {
+ u32 exit_count = 0;
+
+ for (auto v : sheng_states) {
+ dstate_id_t s = g[v].index;
+ for (u32 i = 0; i != info.alpha_size; i++) {
+ if (i == info.alpha_remap[TOP]) {
+ continue;
+ }
+ dstate_id_t next = info.states[s].next[i];
+ if (!next || info.is_sheng(next) || info.is_sheng_succ(next)) {
+ continue;
+ }
+ exit_count++;
+ info.extra[next].sheng_succ = true;
+ }
+ }
+
+ if (exit_count + sheng_states.size() < UINT8_MAX) {
+ return true;
+ } else {
+ DEBUG_PRINTF("fail: unable to fit %u exits in byte", exit_count);
+ return false;
+ }
+}
+
+static
+CharReach get_edge_reach(dstate_id_t u, dstate_id_t v, const dfa_info &info) {
+ CharReach rv;
+ for (u32 i = 0; i < info.impl_alpha_size; i++) {
+ if (info.raw.states[u].next[i] == v) {
+ assert(info.rev_alpha[i].any());
+ rv |= info.rev_alpha[i];
+ }
+ }
+ assert(rv.any());
+ return rv;
+}
+
+#define MAX_SHENG_STATES 16
#define MAX_SHENG64_STATES 64
-#define MAX_SHENG_LEAKINESS 0.05
-
-using LeakinessCache = ue2_unordered_map<pair<RdfaVertex, u32>, double>;
-
-/**
- * Returns the proportion of strings of length 'depth' which will leave the
- * sheng region when starting at state 'u'.
- */
-static
-double leakiness(const RdfaGraph &g, dfa_info &info,
- const flat_set<RdfaVertex> &sheng_states, RdfaVertex u,
- u32 depth, LeakinessCache &cache) {
- double rv = 0;
- if (contains(cache, make_pair(u, depth))) {
- return cache[make_pair(u, depth)];
- }
- for (RdfaVertex v : adjacent_vertices_range(u, g)) {
- if (g[v].index == DEAD_STATE) {
- continue;
- }
- double width = get_edge_reach(g[u].index, g[v].index, info).count();
- width /= N_CHARS;
-
- double weight;
- if (!contains(sheng_states, v)) {
- weight = 1;
- } else if (depth > 1) {
- weight = leakiness(g, info, sheng_states, v, depth - 1, cache);
- } else {
- continue; /* weight = 0 */
- }
- rv += width * weight;
- }
-
- cache[make_pair(u, depth)] = rv;
- DEBUG_PRINTF("%zu [%u] q = %g\n", g[u].index, depth, rv);
- return rv;
-}
-
-/**
- * Returns the proportion of 8 byte strings which will leave the sheng region
- * when starting at state 'u'.
- */
-static
-double leakiness(const RdfaGraph &g, dfa_info &info,
- const flat_set<RdfaVertex> &sheng_states, RdfaVertex u) {
- LeakinessCache cache;
- double rv = leakiness(g, info, sheng_states, u, 8, cache);
- return rv;
-}
-
-static
-dstate_id_t find_sheng_states(dfa_info &info,
+#define MAX_SHENG_LEAKINESS 0.05
+
+using LeakinessCache = ue2_unordered_map<pair<RdfaVertex, u32>, double>;
+
+/**
+ * Returns the proportion of strings of length 'depth' which will leave the
+ * sheng region when starting at state 'u'.
+ */
+static
+double leakiness(const RdfaGraph &g, dfa_info &info,
+ const flat_set<RdfaVertex> &sheng_states, RdfaVertex u,
+ u32 depth, LeakinessCache &cache) {
+ double rv = 0;
+ if (contains(cache, make_pair(u, depth))) {
+ return cache[make_pair(u, depth)];
+ }
+ for (RdfaVertex v : adjacent_vertices_range(u, g)) {
+ if (g[v].index == DEAD_STATE) {
+ continue;
+ }
+ double width = get_edge_reach(g[u].index, g[v].index, info).count();
+ width /= N_CHARS;
+
+ double weight;
+ if (!contains(sheng_states, v)) {
+ weight = 1;
+ } else if (depth > 1) {
+ weight = leakiness(g, info, sheng_states, v, depth - 1, cache);
+ } else {
+ continue; /* weight = 0 */
+ }
+ rv += width * weight;
+ }
+
+ cache[make_pair(u, depth)] = rv;
+ DEBUG_PRINTF("%zu [%u] q = %g\n", g[u].index, depth, rv);
+ return rv;
+}
+
+/**
+ * Returns the proportion of 8 byte strings which will leave the sheng region
+ * when starting at state 'u'.
+ */
+static
+double leakiness(const RdfaGraph &g, dfa_info &info,
+ const flat_set<RdfaVertex> &sheng_states, RdfaVertex u) {
+ LeakinessCache cache;
+ double rv = leakiness(g, info, sheng_states, u, 8, cache);
+ return rv;
+}
+
+static
+dstate_id_t find_sheng_states(dfa_info &info,
map<dstate_id_t, AccelScheme> &accel_escape_info,
size_t max_sheng_states) {
- RdfaGraph g(info.raw);
- auto cyclics = find_vertices_in_cycles(g);
-
- auto base_cyclic = RdfaGraph::null_vertex();
- for (const auto &v : cyclics) {
- if (g[v].index == DEAD_STATE) {
- continue;
- }
- DEBUG_PRINTF("considering cyclic %zu\n", g[v].index);
- /* get an estimate of stickness of the cyclic: assume any edges from
- * states with larger state ids are back edges */
- CharReach est_back_reach;
- for (const auto &u : inv_adjacent_vertices_range(v, g)) {
- if (g[u].index < g[v].index) {
- continue;
- }
- est_back_reach |= get_edge_reach(g[u].index, g[v].index, info);
- }
-
- if (est_back_reach.count() < 30) {
- continue;
- }
- base_cyclic = v;
- break;
- }
- if (!base_cyclic) {
- return DEAD_STATE;
- }
-
- flat_set<RdfaVertex> sheng_states;
- deque<RdfaVertex> to_consider = { base_cyclic };
- flat_set<dstate_id_t> considered = { DEAD_STATE };
- bool seen_back_edge = false;
- while (!to_consider.empty()
+ RdfaGraph g(info.raw);
+ auto cyclics = find_vertices_in_cycles(g);
+
+ auto base_cyclic = RdfaGraph::null_vertex();
+ for (const auto &v : cyclics) {
+ if (g[v].index == DEAD_STATE) {
+ continue;
+ }
+ DEBUG_PRINTF("considering cyclic %zu\n", g[v].index);
+ /* get an estimate of stickness of the cyclic: assume any edges from
+ * states with larger state ids are back edges */
+ CharReach est_back_reach;
+ for (const auto &u : inv_adjacent_vertices_range(v, g)) {
+ if (g[u].index < g[v].index) {
+ continue;
+ }
+ est_back_reach |= get_edge_reach(g[u].index, g[v].index, info);
+ }
+
+ if (est_back_reach.count() < 30) {
+ continue;
+ }
+ base_cyclic = v;
+ break;
+ }
+ if (!base_cyclic) {
+ return DEAD_STATE;
+ }
+
+ flat_set<RdfaVertex> sheng_states;
+ deque<RdfaVertex> to_consider = { base_cyclic };
+ flat_set<dstate_id_t> considered = { DEAD_STATE };
+ bool seen_back_edge = false;
+ while (!to_consider.empty()
&& sheng_states.size() < max_sheng_states) {
- auto v = to_consider.front();
- to_consider.pop_front();
- if (!considered.insert(g[v].index).second) {
- continue;
- }
-
- assert(!contains(sheng_states, v));
-
- if (generates_callbacks(info.raw.kind)
- && !info.states[g[v].index].reports.empty()) {
- /* cannot raise callbacks from sheng region */
- continue;
- }
-
- sheng_states.insert(v);
- for (const auto &t : adjacent_vertices_range(v, g)) {
- if (!contains(considered, g[t].index)) {
- to_consider.push_back(t);
- }
- if (t == base_cyclic) {
- seen_back_edge = true;
- }
- }
- }
-
- /* allocate normal ids */
- dstate_id_t sheng_end = DEAD_STATE + 1;
- for (auto v : sheng_states) {
- dstate_id_t s = g[v].index;
- if (!contains(accel_escape_info, s)) {
- info.states[s].impl_id = sheng_end++;
- info.extra[s].sheng_id = info.states[s].impl_id - 1;
- }
- }
-
- /* allocate accel ids */
- for (auto v : sheng_states) {
- dstate_id_t s = g[v].index;
- if (contains(accel_escape_info, s)) {
- assert(!info.states[s].impl_id);
- info.states[s].impl_id = sheng_end++;
- info.extra[s].sheng_id = info.states[s].impl_id - 1;
- }
- }
-
- if (sheng_states.size() < MIN_SHENG_SIZE) {
- DEBUG_PRINTF("sheng region too small\n");
- return DEAD_STATE;
- }
-
- if (!seen_back_edge) {
- DEBUG_PRINTF("did not include cyclic\n");
- return DEAD_STATE;
- }
-
- double leak = leakiness(g, info, sheng_states, base_cyclic);
- if (leak > MAX_SHENG_LEAKINESS) {
- DEBUG_PRINTF("too leaky (%g)\n", leak);
- return DEAD_STATE;
- }
-
- if (!mark_sheng_succs(g, info, sheng_states)) {
- return DEAD_STATE;
- }
-
- /* TODO: ensure sufficiently 'sticky' */
- /* TODO: check not all states accel */
- DEBUG_PRINTF("sheng_end = %hu\n", sheng_end);
- return sheng_end;
-}
-
-static
-void fill_in_aux_info(NFA *nfa, const dfa_info &info,
- const map<dstate_id_t, AccelScheme> &accel_escape_info,
- u32 accel_offset, UNUSED u32 accel_end_offset,
- const vector<u32> &reports,
- const vector<u32> &reports_eod,
- u32 report_base_offset,
- const raw_report_info &ri) {
- mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
-
- vector<u32> reportOffsets;
-
- ri.fillReportLists(nfa, report_base_offset, reportOffsets);
-
- for (u32 i = 0; i < info.size(); i++) {
- u16 impl_id = info.implId(i);
- mstate_aux *this_aux = getAux(nfa, impl_id);
-
- fillInAux(this_aux, i, info, reports, reports_eod, reportOffsets);
- if (contains(accel_escape_info, i)) {
- this_aux->accel_offset = accel_offset;
- accel_offset += info.strat.accelSize();
- assert(accel_offset <= accel_end_offset);
- assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
- info.strat.buildAccel(i, accel_escape_info.at(i),
- (void *)((char *)m + this_aux->accel_offset));
- }
- }
-}
-
-static
-u16 get_edge_flags(NFA *nfa, dstate_id_t target_impl_id) {
- mstate_aux *aux = getAux(nfa, target_impl_id);
- u16 flags = 0;
-
- if (aux->accept) {
- flags |= ACCEPT_FLAG;
- }
-
- if (aux->accel_offset) {
- flags |= ACCEL_FLAG;
- }
-
- return flags;
-}
-
-static
-void fill_in_succ_table_16(NFA *nfa, const dfa_info &info,
- dstate_id_t sheng_end,
- UNUSED dstate_id_t sherman_base) {
- u16 *succ_table = (u16 *)((char *)nfa + sizeof(NFA) + sizeof(mcsheng));
-
- u8 alphaShift = info.getAlphaShift();
- assert(alphaShift <= 8);
-
- for (size_t i = 0; i < info.size(); i++) {
- if (!info.is_normal(i)) {
- assert(info.implId(i) < sheng_end || info.is_sherman(i));
- continue;
- }
-
- assert(info.implId(i) < sherman_base);
- u16 normal_id = verify_u16(info.implId(i) - sheng_end);
-
- for (size_t s = 0; s < info.impl_alpha_size; s++) {
- dstate_id_t raw_succ = info.states[i].next[s];
- u16 &entry = succ_table[((size_t)normal_id << alphaShift) + s];
-
- entry = info.implId(raw_succ);
- entry |= get_edge_flags(nfa, entry);
- }
- }
-}
-
+ auto v = to_consider.front();
+ to_consider.pop_front();
+ if (!considered.insert(g[v].index).second) {
+ continue;
+ }
+
+ assert(!contains(sheng_states, v));
+
+ if (generates_callbacks(info.raw.kind)
+ && !info.states[g[v].index].reports.empty()) {
+ /* cannot raise callbacks from sheng region */
+ continue;
+ }
+
+ sheng_states.insert(v);
+ for (const auto &t : adjacent_vertices_range(v, g)) {
+ if (!contains(considered, g[t].index)) {
+ to_consider.push_back(t);
+ }
+ if (t == base_cyclic) {
+ seen_back_edge = true;
+ }
+ }
+ }
+
+ /* allocate normal ids */
+ dstate_id_t sheng_end = DEAD_STATE + 1;
+ for (auto v : sheng_states) {
+ dstate_id_t s = g[v].index;
+ if (!contains(accel_escape_info, s)) {
+ info.states[s].impl_id = sheng_end++;
+ info.extra[s].sheng_id = info.states[s].impl_id - 1;
+ }
+ }
+
+ /* allocate accel ids */
+ for (auto v : sheng_states) {
+ dstate_id_t s = g[v].index;
+ if (contains(accel_escape_info, s)) {
+ assert(!info.states[s].impl_id);
+ info.states[s].impl_id = sheng_end++;
+ info.extra[s].sheng_id = info.states[s].impl_id - 1;
+ }
+ }
+
+ if (sheng_states.size() < MIN_SHENG_SIZE) {
+ DEBUG_PRINTF("sheng region too small\n");
+ return DEAD_STATE;
+ }
+
+ if (!seen_back_edge) {
+ DEBUG_PRINTF("did not include cyclic\n");
+ return DEAD_STATE;
+ }
+
+ double leak = leakiness(g, info, sheng_states, base_cyclic);
+ if (leak > MAX_SHENG_LEAKINESS) {
+ DEBUG_PRINTF("too leaky (%g)\n", leak);
+ return DEAD_STATE;
+ }
+
+ if (!mark_sheng_succs(g, info, sheng_states)) {
+ return DEAD_STATE;
+ }
+
+ /* TODO: ensure sufficiently 'sticky' */
+ /* TODO: check not all states accel */
+ DEBUG_PRINTF("sheng_end = %hu\n", sheng_end);
+ return sheng_end;
+}
+
+static
+void fill_in_aux_info(NFA *nfa, const dfa_info &info,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ u32 accel_offset, UNUSED u32 accel_end_offset,
+ const vector<u32> &reports,
+ const vector<u32> &reports_eod,
+ u32 report_base_offset,
+ const raw_report_info &ri) {
+ mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
+
+ vector<u32> reportOffsets;
+
+ ri.fillReportLists(nfa, report_base_offset, reportOffsets);
+
+ for (u32 i = 0; i < info.size(); i++) {
+ u16 impl_id = info.implId(i);
+ mstate_aux *this_aux = getAux(nfa, impl_id);
+
+ fillInAux(this_aux, i, info, reports, reports_eod, reportOffsets);
+ if (contains(accel_escape_info, i)) {
+ this_aux->accel_offset = accel_offset;
+ accel_offset += info.strat.accelSize();
+ assert(accel_offset <= accel_end_offset);
+ assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
+ info.strat.buildAccel(i, accel_escape_info.at(i),
+ (void *)((char *)m + this_aux->accel_offset));
+ }
+ }
+}
+
+static
+u16 get_edge_flags(NFA *nfa, dstate_id_t target_impl_id) {
+ mstate_aux *aux = getAux(nfa, target_impl_id);
+ u16 flags = 0;
+
+ if (aux->accept) {
+ flags |= ACCEPT_FLAG;
+ }
+
+ if (aux->accel_offset) {
+ flags |= ACCEL_FLAG;
+ }
+
+ return flags;
+}
+
+static
+void fill_in_succ_table_16(NFA *nfa, const dfa_info &info,
+ dstate_id_t sheng_end,
+ UNUSED dstate_id_t sherman_base) {
+ u16 *succ_table = (u16 *)((char *)nfa + sizeof(NFA) + sizeof(mcsheng));
+
+ u8 alphaShift = info.getAlphaShift();
+ assert(alphaShift <= 8);
+
+ for (size_t i = 0; i < info.size(); i++) {
+ if (!info.is_normal(i)) {
+ assert(info.implId(i) < sheng_end || info.is_sherman(i));
+ continue;
+ }
+
+ assert(info.implId(i) < sherman_base);
+ u16 normal_id = verify_u16(info.implId(i) - sheng_end);
+
+ for (size_t s = 0; s < info.impl_alpha_size; s++) {
+ dstate_id_t raw_succ = info.states[i].next[s];
+ u16 &entry = succ_table[((size_t)normal_id << alphaShift) + s];
+
+ entry = info.implId(raw_succ);
+ entry |= get_edge_flags(nfa, entry);
+ }
+ }
+}
+
static
void fill_in_aux_info64(NFA *nfa, const dfa_info &info,
const map<dstate_id_t, AccelScheme> &accel_escape_info,
@@ -791,232 +791,232 @@ void fill_in_succ_table_64_16(NFA *nfa, const dfa_info &info,
}
}
-#define MAX_SHERMAN_LIST_LEN 8
-
-static
-void addIfEarlier(flat_set<dstate_id_t> &dest, dstate_id_t candidate,
- dstate_id_t max) {
- if (candidate < max) {
- dest.insert(candidate);
- }
-}
-
-static
-void addSuccessors(flat_set<dstate_id_t> &dest, const dstate &source,
- u16 alphasize, dstate_id_t curr_id) {
- for (symbol_t s = 0; s < alphasize; s++) {
- addIfEarlier(dest, source.next[s], curr_id);
- }
-}
-
-/* \brief Returns a set of states to search for a better daddy. */
-static
-flat_set<dstate_id_t> find_daddy_candidates(const dfa_info &info,
- dstate_id_t curr_id) {
- flat_set<dstate_id_t> hinted;
-
- addIfEarlier(hinted, 0, curr_id);
- addIfEarlier(hinted, info.raw.start_anchored, curr_id);
- addIfEarlier(hinted, info.raw.start_floating, curr_id);
-
- // Add existing daddy and his successors, then search back one generation.
- const u16 alphasize = info.impl_alpha_size;
- dstate_id_t daddy = info.states[curr_id].daddy;
- for (u32 level = 0; daddy && level < 2; level++) {
- addIfEarlier(hinted, daddy, curr_id);
- addSuccessors(hinted, info.states[daddy], alphasize, curr_id);
- daddy = info.states[daddy].daddy;
- }
-
- return hinted;
-}
-
-#define MAX_SHERMAN_SELF_LOOP 20
-
-static
-void find_better_daddy(dfa_info &info, dstate_id_t curr_id,
- bool any_cyclic_near_anchored_state, const Grey &grey) {
- if (!grey.allowShermanStates) {
- return;
- }
-
- const u16 width = sizeof(u16);
- const u16 alphasize = info.impl_alpha_size;
-
- if (info.raw.start_anchored != DEAD_STATE
- && any_cyclic_near_anchored_state
- && curr_id < alphasize * 3) {
- /* crude attempt to prevent frequent states from being sherman'ed
- * depends on the fact that states are numbers are currently in bfs
- * order */
- DEBUG_PRINTF("%hu is banned\n", curr_id);
- return;
- }
-
- if (info.raw.start_floating != DEAD_STATE
- && curr_id >= info.raw.start_floating
- && curr_id < info.raw.start_floating + alphasize * 3) {
- /* crude attempt to prevent frequent states from being sherman'ed
- * depends on the fact that states are numbers are currently in bfs
- * order */
- DEBUG_PRINTF("%hu is banned (%hu)\n", curr_id, info.raw.start_floating);
- return;
- }
-
- const u16 full_state_size = width * alphasize;
- const u16 max_list_len = MIN(MAX_SHERMAN_LIST_LEN,
- (full_state_size - 2)/(width + 1));
- u16 best_score = 0;
- dstate_id_t best_daddy = 0;
- dstate &currState = info.states[curr_id];
-
- flat_set<dstate_id_t> hinted = find_daddy_candidates(info, curr_id);
-
- for (const dstate_id_t &donor : hinted) {
- assert(donor < curr_id);
- u32 score = 0;
-
- if (!info.is_normal(donor)) {
- continue;
- }
-
- const dstate &donorState = info.states[donor];
- for (symbol_t s = 0; s < alphasize; s++) {
- if (currState.next[s] == donorState.next[s]) {
- score++;
- }
- }
-
- /* prefer lower ids to provide some stability amongst potential
- * siblings */
- if (score > best_score || (score == best_score && donor < best_daddy)) {
- best_daddy = donor;
- best_score = score;
-
- if (score == alphasize) {
- break;
- }
- }
- }
-
- currState.daddy = best_daddy;
- info.extra[curr_id].daddytaken = best_score;
- DEBUG_PRINTF("%hu -> daddy %hu: %u/%u BF\n", curr_id, best_daddy,
- best_score, alphasize);
-
- if (best_daddy == DEAD_STATE) {
- return; /* No good daddy */
- }
-
- if (best_score + max_list_len < alphasize) {
- return; /* ??? */
- }
-
- assert(info.is_normal(currState.daddy));
-
- u32 self_loop_width = 0;
- const dstate &curr_raw = info.states[curr_id];
- for (unsigned i = 0; i < N_CHARS; i++) {
- if (curr_raw.next[info.alpha_remap[i]] == curr_id) {
- self_loop_width++;
- }
- }
-
- if (self_loop_width > MAX_SHERMAN_SELF_LOOP) {
- DEBUG_PRINTF("%hu is banned wide self loop (%u)\n", curr_id,
- self_loop_width);
- return;
- }
-
- if (info.is_sheng(curr_id)) {
- return;
- }
-
- DEBUG_PRINTF("%hu is sherman\n", curr_id);
- info.extra[curr_id].shermanState = true;
-}
-
-static
-bool is_cyclic_near(const raw_dfa &raw, dstate_id_t root) {
- symbol_t alphasize = raw.getImplAlphaSize();
- for (symbol_t s = 0; s < alphasize; s++) {
- dstate_id_t succ_id = raw.states[root].next[s];
- if (succ_id == DEAD_STATE) {
- continue;
- }
-
- const dstate &succ = raw.states[succ_id];
- for (symbol_t t = 0; t < alphasize; t++) {
- if (succ.next[t] == root || succ.next[t] == succ_id) {
- return true;
- }
- }
- }
- return false;
-}
-
-static
-void fill_in_sherman(NFA *nfa, dfa_info &info, UNUSED u16 sherman_limit) {
- char *nfa_base = (char *)nfa;
- mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
- char *sherman_table = nfa_base + m->sherman_offset;
-
- assert(ISALIGNED_16(sherman_table));
- for (size_t i = 0; i < info.size(); i++) {
- if (!info.is_sherman(i)) {
- continue;
- }
- u16 fs = verify_u16(info.implId(i));
- DEBUG_PRINTF("building sherman %zu impl %hu\n", i, fs);
-
- assert(fs >= sherman_limit);
-
- char *curr_sherman_entry
- = sherman_table + (fs - m->sherman_limit) * SHERMAN_FIXED_SIZE;
- assert(curr_sherman_entry <= nfa_base + m->length);
-
- u8 len = verify_u8(info.impl_alpha_size - info.extra[i].daddytaken);
- assert(len <= 9);
- dstate_id_t d = info.states[i].daddy;
-
- *(u8 *)(curr_sherman_entry + SHERMAN_TYPE_OFFSET) = SHERMAN_STATE;
- *(u8 *)(curr_sherman_entry + SHERMAN_LEN_OFFSET) = len;
- *(u16 *)(curr_sherman_entry + SHERMAN_DADDY_OFFSET) = info.implId(d);
- u8 *chars = (u8 *)(curr_sherman_entry + SHERMAN_CHARS_OFFSET);
-
- for (u16 s = 0; s < info.impl_alpha_size; s++) {
- if (info.states[i].next[s] != info.states[d].next[s]) {
- *(chars++) = (u8)s;
- }
- }
-
- u16 *states = (u16 *)(curr_sherman_entry + SHERMAN_STATES_OFFSET(len));
- for (u16 s = 0; s < info.impl_alpha_size; s++) {
- if (info.states[i].next[s] != info.states[d].next[s]) {
- DEBUG_PRINTF("s overrider %hu dad %hu char next %hu\n", fs,
- info.implId(d),
- info.implId(info.states[i].next[s]));
- u16 entry_val = info.implId(info.states[i].next[s]);
- entry_val |= get_edge_flags(nfa, entry_val);
- unaligned_store_u16((u8 *)states++, entry_val);
- }
- }
- }
-}
-
-static
-bytecode_ptr<NFA> mcshengCompile16(dfa_info &info, dstate_id_t sheng_end,
- const map<dstate_id_t, AccelScheme> &accel_escape_info,
- const Grey &grey) {
- DEBUG_PRINTF("building mcsheng 16\n");
-
- vector<u32> reports; /* index in ri for the appropriate report list */
- vector<u32> reports_eod; /* as above */
- ReportID arb;
- u8 single;
-
- assert(info.getAlphaShift() <= 8);
-
+#define MAX_SHERMAN_LIST_LEN 8
+
+static
+void addIfEarlier(flat_set<dstate_id_t> &dest, dstate_id_t candidate,
+ dstate_id_t max) {
+ if (candidate < max) {
+ dest.insert(candidate);
+ }
+}
+
+static
+void addSuccessors(flat_set<dstate_id_t> &dest, const dstate &source,
+ u16 alphasize, dstate_id_t curr_id) {
+ for (symbol_t s = 0; s < alphasize; s++) {
+ addIfEarlier(dest, source.next[s], curr_id);
+ }
+}
+
+/* \brief Returns a set of states to search for a better daddy. */
+static
+flat_set<dstate_id_t> find_daddy_candidates(const dfa_info &info,
+ dstate_id_t curr_id) {
+ flat_set<dstate_id_t> hinted;
+
+ addIfEarlier(hinted, 0, curr_id);
+ addIfEarlier(hinted, info.raw.start_anchored, curr_id);
+ addIfEarlier(hinted, info.raw.start_floating, curr_id);
+
+ // Add existing daddy and his successors, then search back one generation.
+ const u16 alphasize = info.impl_alpha_size;
+ dstate_id_t daddy = info.states[curr_id].daddy;
+ for (u32 level = 0; daddy && level < 2; level++) {
+ addIfEarlier(hinted, daddy, curr_id);
+ addSuccessors(hinted, info.states[daddy], alphasize, curr_id);
+ daddy = info.states[daddy].daddy;
+ }
+
+ return hinted;
+}
+
+#define MAX_SHERMAN_SELF_LOOP 20
+
+static
+void find_better_daddy(dfa_info &info, dstate_id_t curr_id,
+ bool any_cyclic_near_anchored_state, const Grey &grey) {
+ if (!grey.allowShermanStates) {
+ return;
+ }
+
+ const u16 width = sizeof(u16);
+ const u16 alphasize = info.impl_alpha_size;
+
+ if (info.raw.start_anchored != DEAD_STATE
+ && any_cyclic_near_anchored_state
+ && curr_id < alphasize * 3) {
+ /* crude attempt to prevent frequent states from being sherman'ed
+ * depends on the fact that states are numbers are currently in bfs
+ * order */
+ DEBUG_PRINTF("%hu is banned\n", curr_id);
+ return;
+ }
+
+ if (info.raw.start_floating != DEAD_STATE
+ && curr_id >= info.raw.start_floating
+ && curr_id < info.raw.start_floating + alphasize * 3) {
+ /* crude attempt to prevent frequent states from being sherman'ed
+ * depends on the fact that states are numbers are currently in bfs
+ * order */
+ DEBUG_PRINTF("%hu is banned (%hu)\n", curr_id, info.raw.start_floating);
+ return;
+ }
+
+ const u16 full_state_size = width * alphasize;
+ const u16 max_list_len = MIN(MAX_SHERMAN_LIST_LEN,
+ (full_state_size - 2)/(width + 1));
+ u16 best_score = 0;
+ dstate_id_t best_daddy = 0;
+ dstate &currState = info.states[curr_id];
+
+ flat_set<dstate_id_t> hinted = find_daddy_candidates(info, curr_id);
+
+ for (const dstate_id_t &donor : hinted) {
+ assert(donor < curr_id);
+ u32 score = 0;
+
+ if (!info.is_normal(donor)) {
+ continue;
+ }
+
+ const dstate &donorState = info.states[donor];
+ for (symbol_t s = 0; s < alphasize; s++) {
+ if (currState.next[s] == donorState.next[s]) {
+ score++;
+ }
+ }
+
+ /* prefer lower ids to provide some stability amongst potential
+ * siblings */
+ if (score > best_score || (score == best_score && donor < best_daddy)) {
+ best_daddy = donor;
+ best_score = score;
+
+ if (score == alphasize) {
+ break;
+ }
+ }
+ }
+
+ currState.daddy = best_daddy;
+ info.extra[curr_id].daddytaken = best_score;
+ DEBUG_PRINTF("%hu -> daddy %hu: %u/%u BF\n", curr_id, best_daddy,
+ best_score, alphasize);
+
+ if (best_daddy == DEAD_STATE) {
+ return; /* No good daddy */
+ }
+
+ if (best_score + max_list_len < alphasize) {
+ return; /* ??? */
+ }
+
+ assert(info.is_normal(currState.daddy));
+
+ u32 self_loop_width = 0;
+ const dstate &curr_raw = info.states[curr_id];
+ for (unsigned i = 0; i < N_CHARS; i++) {
+ if (curr_raw.next[info.alpha_remap[i]] == curr_id) {
+ self_loop_width++;
+ }
+ }
+
+ if (self_loop_width > MAX_SHERMAN_SELF_LOOP) {
+ DEBUG_PRINTF("%hu is banned wide self loop (%u)\n", curr_id,
+ self_loop_width);
+ return;
+ }
+
+ if (info.is_sheng(curr_id)) {
+ return;
+ }
+
+ DEBUG_PRINTF("%hu is sherman\n", curr_id);
+ info.extra[curr_id].shermanState = true;
+}
+
+static
+bool is_cyclic_near(const raw_dfa &raw, dstate_id_t root) {
+ symbol_t alphasize = raw.getImplAlphaSize();
+ for (symbol_t s = 0; s < alphasize; s++) {
+ dstate_id_t succ_id = raw.states[root].next[s];
+ if (succ_id == DEAD_STATE) {
+ continue;
+ }
+
+ const dstate &succ = raw.states[succ_id];
+ for (symbol_t t = 0; t < alphasize; t++) {
+ if (succ.next[t] == root || succ.next[t] == succ_id) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static
+void fill_in_sherman(NFA *nfa, dfa_info &info, UNUSED u16 sherman_limit) {
+ char *nfa_base = (char *)nfa;
+ mcsheng *m = (mcsheng *)getMutableImplNfa(nfa);
+ char *sherman_table = nfa_base + m->sherman_offset;
+
+ assert(ISALIGNED_16(sherman_table));
+ for (size_t i = 0; i < info.size(); i++) {
+ if (!info.is_sherman(i)) {
+ continue;
+ }
+ u16 fs = verify_u16(info.implId(i));
+ DEBUG_PRINTF("building sherman %zu impl %hu\n", i, fs);
+
+ assert(fs >= sherman_limit);
+
+ char *curr_sherman_entry
+ = sherman_table + (fs - m->sherman_limit) * SHERMAN_FIXED_SIZE;
+ assert(curr_sherman_entry <= nfa_base + m->length);
+
+ u8 len = verify_u8(info.impl_alpha_size - info.extra[i].daddytaken);
+ assert(len <= 9);
+ dstate_id_t d = info.states[i].daddy;
+
+ *(u8 *)(curr_sherman_entry + SHERMAN_TYPE_OFFSET) = SHERMAN_STATE;
+ *(u8 *)(curr_sherman_entry + SHERMAN_LEN_OFFSET) = len;
+ *(u16 *)(curr_sherman_entry + SHERMAN_DADDY_OFFSET) = info.implId(d);
+ u8 *chars = (u8 *)(curr_sherman_entry + SHERMAN_CHARS_OFFSET);
+
+ for (u16 s = 0; s < info.impl_alpha_size; s++) {
+ if (info.states[i].next[s] != info.states[d].next[s]) {
+ *(chars++) = (u8)s;
+ }
+ }
+
+ u16 *states = (u16 *)(curr_sherman_entry + SHERMAN_STATES_OFFSET(len));
+ for (u16 s = 0; s < info.impl_alpha_size; s++) {
+ if (info.states[i].next[s] != info.states[d].next[s]) {
+ DEBUG_PRINTF("s overrider %hu dad %hu char next %hu\n", fs,
+ info.implId(d),
+ info.implId(info.states[i].next[s]));
+ u16 entry_val = info.implId(info.states[i].next[s]);
+ entry_val |= get_edge_flags(nfa, entry_val);
+ unaligned_store_u16((u8 *)states++, entry_val);
+ }
+ }
+ }
+}
+
+static
+bytecode_ptr<NFA> mcshengCompile16(dfa_info &info, dstate_id_t sheng_end,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ const Grey &grey) {
+ DEBUG_PRINTF("building mcsheng 16\n");
+
+ vector<u32> reports; /* index in ri for the appropriate report list */
+ vector<u32> reports_eod; /* as above */
+ ReportID arb;
+ u8 single;
+
+ assert(info.getAlphaShift() <= 8);
+
// Sherman optimization
if (info.impl_alpha_size > 16) {
u16 total_daddy = 0;
@@ -1030,86 +1030,86 @@ bytecode_ptr<NFA> mcshengCompile16(dfa_info &info, dstate_id_t sheng_end,
DEBUG_PRINTF("daddy %hu/%zu states=%zu alpha=%hu\n", total_daddy,
info.size() * info.impl_alpha_size, info.size(),
info.impl_alpha_size);
- }
-
- u16 sherman_limit;
- if (!allocateImplId16(info, sheng_end, &sherman_limit)) {
- DEBUG_PRINTF("failed to allocate state numbers, %zu states total\n",
- info.size());
- return nullptr;
- }
- u16 count_real_states = sherman_limit - sheng_end;
-
- auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
-
- size_t tran_size = (1 << info.getAlphaShift()) * sizeof(u16)
- * count_real_states;
-
- size_t aux_size = sizeof(mstate_aux) * info.size();
-
- size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcsheng) + tran_size);
- size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
- size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
- + ri->getReportListSize(), 32);
- size_t sherman_offset = ROUNDUP_16(accel_offset + accel_size);
- size_t sherman_size = calcShermanRegionSize(info);
-
- size_t total_size = sherman_offset + sherman_size;
-
- accel_offset -= sizeof(NFA); /* adj accel offset to be relative to m */
- assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
-
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
- mcsheng *m = (mcsheng *)getMutableImplNfa(nfa.get());
-
- populateBasicInfo(sizeof(u16), info, total_size, aux_offset, accel_offset,
- accel_escape_info.size(), arb, single, nfa.get());
- createShuffleMasks(m, info, sheng_end, accel_escape_info);
-
- /* copy in the mc header information */
- m->sherman_offset = sherman_offset;
- m->sherman_end = total_size;
- m->sherman_limit = sherman_limit;
-
- DEBUG_PRINTF("%hu sheng, %hu norm, %zu total\n", sheng_end,
- count_real_states, info.size());
-
- fill_in_aux_info(nfa.get(), info, accel_escape_info, accel_offset,
- sherman_offset - sizeof(NFA), reports, reports_eod,
- aux_offset + aux_size, *ri);
-
- fill_in_succ_table_16(nfa.get(), info, sheng_end, sherman_limit);
-
- fill_in_sherman(nfa.get(), info, sherman_limit);
-
- return nfa;
-}
-
-static
-void fill_in_succ_table_8(NFA *nfa, const dfa_info &info,
- dstate_id_t sheng_end) {
- u8 *succ_table = (u8 *)nfa + sizeof(NFA) + sizeof(mcsheng);
-
- u8 alphaShift = info.getAlphaShift();
- assert(alphaShift <= 8);
-
- for (size_t i = 0; i < info.size(); i++) {
- assert(!info.is_sherman(i));
- if (!info.is_normal(i)) {
- assert(info.implId(i) < sheng_end);
- continue;
- }
- u8 normal_id = verify_u8(info.implId(i) - sheng_end);
-
- for (size_t s = 0; s < info.impl_alpha_size; s++) {
- dstate_id_t raw_succ = info.states[i].next[s];
- succ_table[((size_t)normal_id << alphaShift) + s]
- = info.implId(raw_succ);
- }
- }
-}
-
-static
+ }
+
+ u16 sherman_limit;
+ if (!allocateImplId16(info, sheng_end, &sherman_limit)) {
+ DEBUG_PRINTF("failed to allocate state numbers, %zu states total\n",
+ info.size());
+ return nullptr;
+ }
+ u16 count_real_states = sherman_limit - sheng_end;
+
+ auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
+
+ size_t tran_size = (1 << info.getAlphaShift()) * sizeof(u16)
+ * count_real_states;
+
+ size_t aux_size = sizeof(mstate_aux) * info.size();
+
+ size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcsheng) + tran_size);
+ size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
+ size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
+ + ri->getReportListSize(), 32);
+ size_t sherman_offset = ROUNDUP_16(accel_offset + accel_size);
+ size_t sherman_size = calcShermanRegionSize(info);
+
+ size_t total_size = sherman_offset + sherman_size;
+
+ accel_offset -= sizeof(NFA); /* adj accel offset to be relative to m */
+ assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
+
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ mcsheng *m = (mcsheng *)getMutableImplNfa(nfa.get());
+
+ populateBasicInfo(sizeof(u16), info, total_size, aux_offset, accel_offset,
+ accel_escape_info.size(), arb, single, nfa.get());
+ createShuffleMasks(m, info, sheng_end, accel_escape_info);
+
+ /* copy in the mc header information */
+ m->sherman_offset = sherman_offset;
+ m->sherman_end = total_size;
+ m->sherman_limit = sherman_limit;
+
+ DEBUG_PRINTF("%hu sheng, %hu norm, %zu total\n", sheng_end,
+ count_real_states, info.size());
+
+ fill_in_aux_info(nfa.get(), info, accel_escape_info, accel_offset,
+ sherman_offset - sizeof(NFA), reports, reports_eod,
+ aux_offset + aux_size, *ri);
+
+ fill_in_succ_table_16(nfa.get(), info, sheng_end, sherman_limit);
+
+ fill_in_sherman(nfa.get(), info, sherman_limit);
+
+ return nfa;
+}
+
+static
+void fill_in_succ_table_8(NFA *nfa, const dfa_info &info,
+ dstate_id_t sheng_end) {
+ u8 *succ_table = (u8 *)nfa + sizeof(NFA) + sizeof(mcsheng);
+
+ u8 alphaShift = info.getAlphaShift();
+ assert(alphaShift <= 8);
+
+ for (size_t i = 0; i < info.size(); i++) {
+ assert(!info.is_sherman(i));
+ if (!info.is_normal(i)) {
+ assert(info.implId(i) < sheng_end);
+ continue;
+ }
+ u8 normal_id = verify_u8(info.implId(i) - sheng_end);
+
+ for (size_t s = 0; s < info.impl_alpha_size; s++) {
+ dstate_id_t raw_succ = info.states[i].next[s];
+ succ_table[((size_t)normal_id << alphaShift) + s]
+ = info.implId(raw_succ);
+ }
+ }
+}
+
+static
void fill_in_sherman64(NFA *nfa, dfa_info &info, UNUSED u16 sherman_limit) {
char *nfa_base = (char *)nfa;
mcsheng64 *m = (mcsheng64 *)getMutableImplNfa(nfa);
@@ -1264,102 +1264,102 @@ void fill_in_succ_table_64_8(NFA *nfa, const dfa_info &info,
}
static
-void allocateImplId8(dfa_info &info, dstate_id_t sheng_end,
- const map<dstate_id_t, AccelScheme> &accel_escape_info,
- u16 *accel_limit, u16 *accept_limit) {
- info.states[0].impl_id = 0; /* dead is always 0 */
-
- vector<dstate_id_t> norm;
- vector<dstate_id_t> accel;
- vector<dstate_id_t> accept;
-
- assert(info.size() <= (1 << 8));
-
- for (u32 i = 1; i < info.size(); i++) {
- if (info.is_sheng(i)) {
- continue; /* already allocated */
- } else if (!info.states[i].reports.empty()) {
- accept.push_back(i);
- } else if (contains(accel_escape_info, i)) {
- accel.push_back(i);
- } else {
- norm.push_back(i);
- }
- }
-
- u32 j = sheng_end;
- for (const dstate_id_t &s : norm) {
- assert(j <= 256);
- DEBUG_PRINTF("mapping state %u to %u\n", s, j);
- info.states[s].impl_id = j++;
- }
- *accel_limit = j;
- for (const dstate_id_t &s : accel) {
- assert(j <= 256);
- DEBUG_PRINTF("mapping state %u to %u\n", s, j);
- info.states[s].impl_id = j++;
- }
- *accept_limit = j;
- for (const dstate_id_t &s : accept) {
- assert(j <= 256);
- DEBUG_PRINTF("mapping state %u to %u\n", s, j);
- info.states[s].impl_id = j++;
- }
-}
-
-static
-bytecode_ptr<NFA> mcshengCompile8(dfa_info &info, dstate_id_t sheng_end,
- const map<dstate_id_t, AccelScheme> &accel_escape_info) {
- DEBUG_PRINTF("building mcsheng 8\n");
-
- vector<u32> reports;
- vector<u32> reports_eod;
- ReportID arb;
- u8 single;
-
- auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
-
- size_t normal_count = info.size() - sheng_end;
-
- size_t tran_size = sizeof(u8) * (1 << info.getAlphaShift()) * normal_count;
- size_t aux_size = sizeof(mstate_aux) * info.size();
- size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcsheng) + tran_size);
- size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
- size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
- + ri->getReportListSize(), 32);
- size_t total_size = accel_offset + accel_size;
-
- DEBUG_PRINTF("aux_size %zu\n", aux_size);
- DEBUG_PRINTF("aux_offset %zu\n", aux_offset);
- DEBUG_PRINTF("rl size %u\n", ri->getReportListSize());
- DEBUG_PRINTF("accel_size %zu\n", accel_size);
- DEBUG_PRINTF("accel_offset %zu\n", accel_offset);
- DEBUG_PRINTF("total_size %zu\n", total_size);
-
- accel_offset -= sizeof(NFA); /* adj accel offset to be relative to m */
- assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
-
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
- mcsheng *m = (mcsheng *)getMutableImplNfa(nfa.get());
-
- allocateImplId8(info, sheng_end, accel_escape_info, &m->accel_limit_8,
- &m->accept_limit_8);
-
- populateBasicInfo(sizeof(u8), info, total_size, aux_offset, accel_offset,
- accel_escape_info.size(), arb, single, nfa.get());
- createShuffleMasks(m, info, sheng_end, accel_escape_info);
-
- fill_in_aux_info(nfa.get(), info, accel_escape_info, accel_offset,
- total_size - sizeof(NFA), reports, reports_eod,
- aux_offset + aux_size, *ri);
-
- fill_in_succ_table_8(nfa.get(), info, sheng_end);
-
- DEBUG_PRINTF("rl size %zu\n", ri->size());
-
- return nfa;
-}
-
+void allocateImplId8(dfa_info &info, dstate_id_t sheng_end,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ u16 *accel_limit, u16 *accept_limit) {
+ info.states[0].impl_id = 0; /* dead is always 0 */
+
+ vector<dstate_id_t> norm;
+ vector<dstate_id_t> accel;
+ vector<dstate_id_t> accept;
+
+ assert(info.size() <= (1 << 8));
+
+ for (u32 i = 1; i < info.size(); i++) {
+ if (info.is_sheng(i)) {
+ continue; /* already allocated */
+ } else if (!info.states[i].reports.empty()) {
+ accept.push_back(i);
+ } else if (contains(accel_escape_info, i)) {
+ accel.push_back(i);
+ } else {
+ norm.push_back(i);
+ }
+ }
+
+ u32 j = sheng_end;
+ for (const dstate_id_t &s : norm) {
+ assert(j <= 256);
+ DEBUG_PRINTF("mapping state %u to %u\n", s, j);
+ info.states[s].impl_id = j++;
+ }
+ *accel_limit = j;
+ for (const dstate_id_t &s : accel) {
+ assert(j <= 256);
+ DEBUG_PRINTF("mapping state %u to %u\n", s, j);
+ info.states[s].impl_id = j++;
+ }
+ *accept_limit = j;
+ for (const dstate_id_t &s : accept) {
+ assert(j <= 256);
+ DEBUG_PRINTF("mapping state %u to %u\n", s, j);
+ info.states[s].impl_id = j++;
+ }
+}
+
+static
+bytecode_ptr<NFA> mcshengCompile8(dfa_info &info, dstate_id_t sheng_end,
+ const map<dstate_id_t, AccelScheme> &accel_escape_info) {
+ DEBUG_PRINTF("building mcsheng 8\n");
+
+ vector<u32> reports;
+ vector<u32> reports_eod;
+ ReportID arb;
+ u8 single;
+
+ auto ri = info.strat.gatherReports(reports, reports_eod, &single, &arb);
+
+ size_t normal_count = info.size() - sheng_end;
+
+ size_t tran_size = sizeof(u8) * (1 << info.getAlphaShift()) * normal_count;
+ size_t aux_size = sizeof(mstate_aux) * info.size();
+ size_t aux_offset = ROUNDUP_16(sizeof(NFA) + sizeof(mcsheng) + tran_size);
+ size_t accel_size = info.strat.accelSize() * accel_escape_info.size();
+ size_t accel_offset = ROUNDUP_N(aux_offset + aux_size
+ + ri->getReportListSize(), 32);
+ size_t total_size = accel_offset + accel_size;
+
+ DEBUG_PRINTF("aux_size %zu\n", aux_size);
+ DEBUG_PRINTF("aux_offset %zu\n", aux_offset);
+ DEBUG_PRINTF("rl size %u\n", ri->getReportListSize());
+ DEBUG_PRINTF("accel_size %zu\n", accel_size);
+ DEBUG_PRINTF("accel_offset %zu\n", accel_offset);
+ DEBUG_PRINTF("total_size %zu\n", total_size);
+
+ accel_offset -= sizeof(NFA); /* adj accel offset to be relative to m */
+ assert(ISALIGNED_N(accel_offset, alignof(union AccelAux)));
+
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ mcsheng *m = (mcsheng *)getMutableImplNfa(nfa.get());
+
+ allocateImplId8(info, sheng_end, accel_escape_info, &m->accel_limit_8,
+ &m->accept_limit_8);
+
+ populateBasicInfo(sizeof(u8), info, total_size, aux_offset, accel_offset,
+ accel_escape_info.size(), arb, single, nfa.get());
+ createShuffleMasks(m, info, sheng_end, accel_escape_info);
+
+ fill_in_aux_info(nfa.get(), info, accel_escape_info, accel_offset,
+ total_size - sizeof(NFA), reports, reports_eod,
+ aux_offset + aux_size, *ri);
+
+ fill_in_succ_table_8(nfa.get(), info, sheng_end);
+
+ DEBUG_PRINTF("rl size %zu\n", ri->size());
+
+ return nfa;
+}
+
static
bytecode_ptr<NFA> mcsheng64Compile8(dfa_info &info, dstate_id_t sheng_end,
const map<dstate_id_t, AccelScheme> &accel_escape_info) {
@@ -1412,54 +1412,54 @@ bytecode_ptr<NFA> mcsheng64Compile8(dfa_info &info, dstate_id_t sheng_end,
return nfa;
}
-bytecode_ptr<NFA> mcshengCompile(raw_dfa &raw, const CompileContext &cc,
- const ReportManager &rm) {
- if (!cc.grey.allowMcSheng) {
- return nullptr;
- }
-
- mcclellan_build_strat mbs(raw, rm, false);
- dfa_info info(mbs);
- bool using8bit = cc.grey.allowMcClellan8 && info.size() <= 256;
-
- if (!cc.streaming) { /* TODO: work out if we can do the strip in streaming
- * mode with our semantics */
- raw.stripExtraEodReports();
- }
-
- bool has_eod_reports = raw.hasEodReports();
-
- map<dstate_id_t, AccelScheme> accel_escape_info
- = info.strat.getAccelInfo(cc.grey);
+bytecode_ptr<NFA> mcshengCompile(raw_dfa &raw, const CompileContext &cc,
+ const ReportManager &rm) {
+ if (!cc.grey.allowMcSheng) {
+ return nullptr;
+ }
+
+ mcclellan_build_strat mbs(raw, rm, false);
+ dfa_info info(mbs);
+ bool using8bit = cc.grey.allowMcClellan8 && info.size() <= 256;
+
+ if (!cc.streaming) { /* TODO: work out if we can do the strip in streaming
+ * mode with our semantics */
+ raw.stripExtraEodReports();
+ }
+
+ bool has_eod_reports = raw.hasEodReports();
+
+ map<dstate_id_t, AccelScheme> accel_escape_info
+ = info.strat.getAccelInfo(cc.grey);
auto old_states = info.states;
dstate_id_t sheng_end = find_sheng_states(info, accel_escape_info, MAX_SHENG_STATES);
-
- if (sheng_end <= DEAD_STATE + 1) {
+
+ if (sheng_end <= DEAD_STATE + 1) {
info.states = old_states;
- return nullptr;
- }
-
- bytecode_ptr<NFA> nfa;
-
- if (!using8bit) {
- nfa = mcshengCompile16(info, sheng_end, accel_escape_info, cc.grey);
- } else {
- nfa = mcshengCompile8(info, sheng_end, accel_escape_info);
- }
-
- if (!nfa) {
+ return nullptr;
+ }
+
+ bytecode_ptr<NFA> nfa;
+
+ if (!using8bit) {
+ nfa = mcshengCompile16(info, sheng_end, accel_escape_info, cc.grey);
+ } else {
+ nfa = mcshengCompile8(info, sheng_end, accel_escape_info);
+ }
+
+ if (!nfa) {
info.states = old_states;
- return nfa;
- }
-
- if (has_eod_reports) {
- nfa->flags |= NFA_ACCEPTS_EOD;
- }
-
- DEBUG_PRINTF("compile done\n");
- return nfa;
-}
-
+ return nfa;
+ }
+
+ if (has_eod_reports) {
+ nfa->flags |= NFA_ACCEPTS_EOD;
+ }
+
+ DEBUG_PRINTF("compile done\n");
+ return nfa;
+}
+
bytecode_ptr<NFA> mcshengCompile64(raw_dfa &raw, const CompileContext &cc,
const ReportManager &rm) {
if (!cc.grey.allowMcSheng) {
@@ -1520,8 +1520,8 @@ bytecode_ptr<NFA> mcshengCompile64(raw_dfa &raw, const CompileContext &cc,
return nfa;
}
-bool has_accel_mcsheng(const NFA *) {
- return true; /* consider the sheng region as accelerated */
-}
-
-} // namespace ue2
+bool has_accel_mcsheng(const NFA *) {
+ return true; /* consider the sheng region as accelerated */
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng_compile.h b/contrib/libs/hyperscan/src/nfa/mcsheng_compile.h
index faa289807fc..3a79b46a23b 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng_compile.h
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng_compile.h
@@ -1,51 +1,51 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef MCSHENGCOMPILE_H
-#define MCSHENGCOMPILE_H
-
-#include "ue2common.h"
-#include "util/bytecode_ptr.h"
-
-struct NFA;
-
-namespace ue2 {
-
-class ReportManager;
-struct CompileContext;
-struct raw_dfa;
-
-bytecode_ptr<NFA> mcshengCompile(raw_dfa &raw, const CompileContext &cc,
- const ReportManager &rm);
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef MCSHENGCOMPILE_H
+#define MCSHENGCOMPILE_H
+
+#include "ue2common.h"
+#include "util/bytecode_ptr.h"
+
+struct NFA;
+
+namespace ue2 {
+
+class ReportManager;
+struct CompileContext;
+struct raw_dfa;
+
+bytecode_ptr<NFA> mcshengCompile(raw_dfa &raw, const CompileContext &cc,
+ const ReportManager &rm);
bytecode_ptr<NFA> mcshengCompile64(raw_dfa &raw, const CompileContext &cc,
const ReportManager &rm);
-bool has_accel_mcsheng(const NFA *nfa);
-
-} // namespace ue2
-
-#endif
+bool has_accel_mcsheng(const NFA *nfa);
+
+} // namespace ue2
+
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng_data.c b/contrib/libs/hyperscan/src/nfa/mcsheng_data.c
index afd108c7904..0701b4b3130 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng_data.c
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng_data.c
@@ -1,46 +1,46 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "mcsheng_internal.h"
-
-/* This table is in a separate translation unit from mcsheng.c as we want to
- * prevent the compiler from seeing these constants. We have the load resources
- * free at runtime to load the masks with no problems. */
-const u64a mcsheng_pext_mask[8] = {
- 0, /* dummy */
- 0x000000000000ff0f,
- 0x0000000000ff000f,
- 0x00000000ff00000f,
- 0x000000ff0000000f,
- 0x0000ff000000000f,
- 0x00ff00000000000f,
- 0xff0000000000000f,
-};
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "mcsheng_internal.h"
+
+/* This table is in a separate translation unit from mcsheng.c as we want to
+ * prevent the compiler from seeing these constants. We have the load resources
+ * free at runtime to load the masks with no problems. */
+const u64a mcsheng_pext_mask[8] = {
+ 0, /* dummy */
+ 0x000000000000ff0f,
+ 0x0000000000ff000f,
+ 0x00000000ff00000f,
+ 0x000000ff0000000f,
+ 0x0000ff000000000f,
+ 0x00ff00000000000f,
+ 0xff0000000000000f,
+};
#if defined(HAVE_AVX512VBMI)
const u64a mcsheng64_pext_mask[8] = {
0, /* dummy */
diff --git a/contrib/libs/hyperscan/src/nfa/mcsheng_internal.h b/contrib/libs/hyperscan/src/nfa/mcsheng_internal.h
index a10bafec551..d9855746241 100644
--- a/contrib/libs/hyperscan/src/nfa/mcsheng_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/mcsheng_internal.h
@@ -1,97 +1,97 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef MCSHENG_INTERNAL_H
-#define MCSHENG_INTERNAL_H
-
-#include "nfa_internal.h"
-#include "ue2common.h"
-#include "util/simd_types.h"
-
-#define ACCEPT_FLAG 0x8000
-#define ACCEL_FLAG 0x4000
-#define STATE_MASK 0x3fff
-
-#define SHERMAN_STATE 1
-
-#define SHERMAN_TYPE_OFFSET 0
-#define SHERMAN_FIXED_SIZE 32
-
-#define SHERMAN_LEN_OFFSET 1
-#define SHERMAN_DADDY_OFFSET 2
-#define SHERMAN_CHARS_OFFSET 4
-#define SHERMAN_STATES_OFFSET(sso_len) (4 + (sso_len))
-
-struct report_list {
- u32 count;
- ReportID report[];
-};
-
-struct mstate_aux {
- u32 accept;
- u32 accept_eod;
- u16 top;
- u32 accel_offset; /* relative to start of struct mcsheng; 0 if no accel */
-};
-
-#define MCSHENG_FLAG_SINGLE 1 /**< we raise only single accept id */
-
-struct mcsheng {
- u16 state_count; /**< total number of states */
- u32 length; /**< length of dfa in bytes */
- u16 start_anchored; /**< anchored start state */
- u16 start_floating; /**< floating start state */
- u32 aux_offset; /**< offset of the aux structures relative to the start of
- * the nfa structure */
- u32 sherman_offset; /**< offset of array of sherman state offsets the
- * state_info structures relative to the start of the
- * nfa structure */
- u32 sherman_end; /**< offset of the end of the state_info structures
- * relative to the start of the nfa structure */
- u16 sheng_end; /**< first non-sheng state */
- u16 sheng_accel_limit; /**< first sheng accel state. state given in terms of
- * internal sheng ids */
- u16 accel_limit_8; /**< 8 bit, lowest accelerable state */
- u16 accept_limit_8; /**< 8 bit, lowest accept state */
- u16 sherman_limit; /**< lowest sherman state */
- u8 alphaShift;
- u8 flags;
- u8 has_accel; /**< 1 iff there are any accel plans */
- u8 remap[256]; /**< remaps characters to a smaller alphabet */
- ReportID arb_report; /**< one of the accepts that this dfa may raise */
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef MCSHENG_INTERNAL_H
+#define MCSHENG_INTERNAL_H
+
+#include "nfa_internal.h"
+#include "ue2common.h"
+#include "util/simd_types.h"
+
+#define ACCEPT_FLAG 0x8000
+#define ACCEL_FLAG 0x4000
+#define STATE_MASK 0x3fff
+
+#define SHERMAN_STATE 1
+
+#define SHERMAN_TYPE_OFFSET 0
+#define SHERMAN_FIXED_SIZE 32
+
+#define SHERMAN_LEN_OFFSET 1
+#define SHERMAN_DADDY_OFFSET 2
+#define SHERMAN_CHARS_OFFSET 4
+#define SHERMAN_STATES_OFFSET(sso_len) (4 + (sso_len))
+
+struct report_list {
+ u32 count;
+ ReportID report[];
+};
+
+struct mstate_aux {
+ u32 accept;
+ u32 accept_eod;
+ u16 top;
+ u32 accel_offset; /* relative to start of struct mcsheng; 0 if no accel */
+};
+
+#define MCSHENG_FLAG_SINGLE 1 /**< we raise only single accept id */
+
+struct mcsheng {
+ u16 state_count; /**< total number of states */
+ u32 length; /**< length of dfa in bytes */
+ u16 start_anchored; /**< anchored start state */
+ u16 start_floating; /**< floating start state */
+ u32 aux_offset; /**< offset of the aux structures relative to the start of
+ * the nfa structure */
+ u32 sherman_offset; /**< offset of array of sherman state offsets the
+ * state_info structures relative to the start of the
+ * nfa structure */
+ u32 sherman_end; /**< offset of the end of the state_info structures
+ * relative to the start of the nfa structure */
+ u16 sheng_end; /**< first non-sheng state */
+ u16 sheng_accel_limit; /**< first sheng accel state. state given in terms of
+ * internal sheng ids */
+ u16 accel_limit_8; /**< 8 bit, lowest accelerable state */
+ u16 accept_limit_8; /**< 8 bit, lowest accept state */
+ u16 sherman_limit; /**< lowest sherman state */
+ u8 alphaShift;
+ u8 flags;
+ u8 has_accel; /**< 1 iff there are any accel plans */
+ u8 remap[256]; /**< remaps characters to a smaller alphabet */
+ ReportID arb_report; /**< one of the accepts that this dfa may raise */
u32 accel_offset; /**< offset of accel structures from start of McClellan */
- m128 sheng_masks[N_CHARS];
-};
-
-/* pext masks for the runtime to access appropriately copies of bytes 1..7
- * representing the data from a u64a. */
-extern const u64a mcsheng_pext_mask[8];
-
+ m128 sheng_masks[N_CHARS];
+};
+
+/* pext masks for the runtime to access appropriately copies of bytes 1..7
+ * representing the data from a u64a. */
+extern const u64a mcsheng_pext_mask[8];
+
struct mcsheng64 {
u16 state_count; /**< total number of states */
u32 length; /**< length of dfa in bytes */
@@ -121,4 +121,4 @@ struct mcsheng64 {
extern const u64a mcsheng64_pext_mask[8];
-#endif
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/mpv.c b/contrib/libs/hyperscan/src/nfa/mpv.c
index 0bc5f3d8cb6..552754d6080 100644
--- a/contrib/libs/hyperscan/src/nfa/mpv.c
+++ b/contrib/libs/hyperscan/src/nfa/mpv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -124,15 +124,15 @@ char processReports(const struct mpv *m, u8 *reporters,
DEBUG_PRINTF("report %u at %llu\n", curr->report,
report_offset);
- if (curr->unbounded && !curr->simple_exhaust) {
+ if (curr->unbounded && !curr->simple_exhaust) {
assert(rl_count < m->puffette_count);
*rl = curr->report;
++rl;
rl_count++;
}
- if (cb(0, report_offset, curr->report, ctxt) ==
- MO_HALT_MATCHING) {
+ if (cb(0, report_offset, curr->report, ctxt) ==
+ MO_HALT_MATCHING) {
DEBUG_PRINTF("bailing\n");
return MO_HALT_MATCHING;
}
@@ -177,11 +177,11 @@ char processReportsForRange(const struct mpv *m, u8 *reporters,
return MO_CONTINUE_MATCHING;
}
- DEBUG_PRINTF("length=%zu, rl_count=%u\n", length, rl_count);
-
- for (size_t i = 2; i <= length; i++) {
+ DEBUG_PRINTF("length=%zu, rl_count=%u\n", length, rl_count);
+
+ for (size_t i = 2; i <= length; i++) {
for (u32 j = 0; j < rl_count; j++) {
- if (cb(0, first_offset + i, rl[j], ctxt) == MO_HALT_MATCHING) {
+ if (cb(0, first_offset + i, rl[j], ctxt) == MO_HALT_MATCHING) {
DEBUG_PRINTF("bailing\n");
return MO_HALT_MATCHING;
}
@@ -825,21 +825,21 @@ void mpvStoreState(const struct NFA *n, char *state,
}
}
-char nfaExecMpv_queueCompressState(const struct NFA *nfa, const struct mq *q,
- UNUSED s64a loc) {
+char nfaExecMpv_queueCompressState(const struct NFA *nfa, const struct mq *q,
+ UNUSED s64a loc) {
void *dest = q->streamState;
const void *src = q->state;
mpvStoreState(nfa, dest, src);
return 0;
}
-char nfaExecMpv_expandState(const struct NFA *nfa, void *dest, const void *src,
- UNUSED u64a offset, UNUSED u8 key) {
+char nfaExecMpv_expandState(const struct NFA *nfa, void *dest, const void *src,
+ UNUSED u64a offset, UNUSED u8 key) {
mpvLoadState(dest, nfa, src);
return 0;
}
-char nfaExecMpv_reportCurrent(const struct NFA *n, struct mq *q) {
+char nfaExecMpv_reportCurrent(const struct NFA *n, struct mq *q) {
const struct mpv *m = getImplNfa(n);
u64a offset = q_cur_offset(q);
struct mpv_decomp_state *s = (struct mpv_decomp_state *)q->state;
@@ -855,7 +855,7 @@ char nfaExecMpv_reportCurrent(const struct NFA *n, struct mq *q) {
return 0;
}
-char nfaExecMpv_queueInitState(const struct NFA *n, struct mq *q) {
+char nfaExecMpv_queueInitState(const struct NFA *n, struct mq *q) {
struct mpv_decomp_state *out = (void *)q->state;
const struct mpv *m = getImplNfa(n);
assert(sizeof(*out) <= n->scratchStateSize);
@@ -880,8 +880,8 @@ char nfaExecMpv_queueInitState(const struct NFA *n, struct mq *q) {
return 0;
}
-char nfaExecMpv_initCompressedState(const struct NFA *n, u64a offset,
- void *state, UNUSED u8 key) {
+char nfaExecMpv_initCompressedState(const struct NFA *n, u64a offset,
+ void *state, UNUSED u8 key) {
const struct mpv *m = getImplNfa(n);
memset(state, 0, m->active_offset); /* active_offset marks end of comp
* counters */
@@ -896,7 +896,7 @@ char nfaExecMpv_initCompressedState(const struct NFA *n, u64a offset,
}
static really_inline
-char nfaExecMpv_Q_i(const struct NFA *n, struct mq *q, s64a end) {
+char nfaExecMpv_Q_i(const struct NFA *n, struct mq *q, s64a end) {
u64a offset = q->offset;
const u8 *buffer = q->buffer;
size_t length = q->length;
@@ -1021,18 +1021,18 @@ char nfaExecMpv_Q_i(const struct NFA *n, struct mq *q, s64a end) {
return alive;
}
-char nfaExecMpv_Q(const struct NFA *n, struct mq *q, s64a end) {
+char nfaExecMpv_Q(const struct NFA *n, struct mq *q, s64a end) {
DEBUG_PRINTF("_Q %lld\n", end);
- return nfaExecMpv_Q_i(n, q, end);
+ return nfaExecMpv_Q_i(n, q, end);
}
-s64a nfaExecMpv_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end) {
+s64a nfaExecMpv_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end) {
DEBUG_PRINTF("nfa=%p end=%lld\n", nfa, end);
#ifdef DEBUG
debugQueue(q);
#endif
- assert(nfa->type == MPV_NFA);
+ assert(nfa->type == MPV_NFA);
assert(q && q->context && q->state);
assert(end >= 0);
assert(q->cur < q->end);
@@ -1058,7 +1058,7 @@ s64a nfaExecMpv_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end) {
/* TODO: restore max offset stuff, if/when _interesting_ max offset stuff
* is filled in */
- char rv = nfaExecMpv_Q_i(nfa, q, end);
+ char rv = nfaExecMpv_Q_i(nfa, q, end);
assert(!q->report_current);
DEBUG_PRINTF("returned rv=%d, q_trimmed=%d\n", rv, q_trimmed);
diff --git a/contrib/libs/hyperscan/src/nfa/mpv.h b/contrib/libs/hyperscan/src/nfa/mpv.h
index bc514d13e0c..3780728d7fd 100644
--- a/contrib/libs/hyperscan/src/nfa/mpv.h
+++ b/contrib/libs/hyperscan/src/nfa/mpv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,27 +34,27 @@
struct mq;
struct NFA;
-char nfaExecMpv_Q(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecMpv_reportCurrent(const struct NFA *n, struct mq *q);
-char nfaExecMpv_queueInitState(const struct NFA *n, struct mq *q);
-char nfaExecMpv_initCompressedState(const struct NFA *n, u64a offset,
- void *state, u8 key);
-char nfaExecMpv_queueCompressState(const struct NFA *nfa, const struct mq *q,
- s64a loc);
-char nfaExecMpv_expandState(const struct NFA *nfa, void *dest, const void *src,
- u64a offset, u8 key);
+char nfaExecMpv_Q(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecMpv_reportCurrent(const struct NFA *n, struct mq *q);
+char nfaExecMpv_queueInitState(const struct NFA *n, struct mq *q);
+char nfaExecMpv_initCompressedState(const struct NFA *n, u64a offset,
+ void *state, u8 key);
+char nfaExecMpv_queueCompressState(const struct NFA *nfa, const struct mq *q,
+ s64a loc);
+char nfaExecMpv_expandState(const struct NFA *nfa, void *dest, const void *src,
+ u64a offset, u8 key);
-#define nfaExecMpv_testEOD NFA_API_NO_IMPL
-#define nfaExecMpv_inAccept NFA_API_NO_IMPL
-#define nfaExecMpv_inAnyAccept NFA_API_NO_IMPL
-#define nfaExecMpv_QR NFA_API_NO_IMPL
-#define nfaExecMpv_Q2 NFA_API_NO_IMPL /* for non-chained suffixes. */
-#define nfaExecMpv_B_Reverse NFA_API_NO_IMPL
-#define nfaExecMpv_zombie_status NFA_API_ZOMBIE_NO_IMPL
+#define nfaExecMpv_testEOD NFA_API_NO_IMPL
+#define nfaExecMpv_inAccept NFA_API_NO_IMPL
+#define nfaExecMpv_inAnyAccept NFA_API_NO_IMPL
+#define nfaExecMpv_QR NFA_API_NO_IMPL
+#define nfaExecMpv_Q2 NFA_API_NO_IMPL /* for non-chained suffixes. */
+#define nfaExecMpv_B_Reverse NFA_API_NO_IMPL
+#define nfaExecMpv_zombie_status NFA_API_ZOMBIE_NO_IMPL
/**
* return 0 if the mpv dies, otherwise returns the location of the next possible
* match (given the currently known events). */
-s64a nfaExecMpv_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end);
+s64a nfaExecMpv_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end);
#endif
diff --git a/contrib/libs/hyperscan/src/nfa/mpv_internal.h b/contrib/libs/hyperscan/src/nfa/mpv_internal.h
index ae562de11e3..a52853dce28 100644
--- a/contrib/libs/hyperscan/src/nfa/mpv_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/mpv_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,15 +40,15 @@
struct mpv_puffette {
u32 repeats;
char unbounded;
-
- /**
- * \brief Report is simple-exhaustible.
- *
- * If this is true, we do best-effort suppression of runs of reports, only
- * delivering the first one.
- */
- char simple_exhaust;
-
+
+ /**
+ * \brief Report is simple-exhaustible.
+ *
+ * If this is true, we do best-effort suppression of runs of reports, only
+ * delivering the first one.
+ */
+ char simple_exhaust;
+
ReportID report;
};
diff --git a/contrib/libs/hyperscan/src/nfa/mpvcompile.cpp b/contrib/libs/hyperscan/src/nfa/mpvcompile.cpp
index abb36dd606d..8497c648706 100644
--- a/contrib/libs/hyperscan/src/nfa/mpvcompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/mpvcompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,9 +34,9 @@
#include "shufticompile.h"
#include "trufflecompile.h"
#include "util/alloc.h"
-#include "util/multibit_build.h"
+#include "util/multibit_build.h"
#include "util/order_check.h"
-#include "util/report_manager.h"
+#include "util/report_manager.h"
#include "util/verify_types.h"
#include <algorithm>
@@ -54,8 +54,8 @@ namespace ue2 {
namespace {
struct pcomp {
bool operator()(const raw_puff &a, const raw_puff &b) const {
- return tie(a.repeats, a.unbounded, a.simple_exhaust, a.report) <
- tie(b.repeats, b.unbounded, b.simple_exhaust, b.report);
+ return tie(a.repeats, a.unbounded, a.simple_exhaust, a.report) <
+ tie(b.repeats, b.unbounded, b.simple_exhaust, b.report);
}
};
@@ -83,24 +83,24 @@ struct ClusterKey {
} // namespace
static
-void writePuffette(mpv_puffette *out, const raw_puff &rp,
- const ReportManager &rm) {
+void writePuffette(mpv_puffette *out, const raw_puff &rp,
+ const ReportManager &rm) {
DEBUG_PRINTF("outputting %u %d %u to %p\n", rp.repeats, (int)rp.unbounded,
rp.report, out);
out->repeats = rp.repeats;
out->unbounded = rp.unbounded;
- out->simple_exhaust = rp.simple_exhaust;
- out->report = rm.getProgramOffset(rp.report);
+ out->simple_exhaust = rp.simple_exhaust;
+ out->report = rm.getProgramOffset(rp.report);
+}
+
+static
+void writeSentinel(mpv_puffette *out) {
+ DEBUG_PRINTF("outputting sentinel to %p\n", out);
+ memset(out, 0, sizeof(*out));
+ out->report = INVALID_REPORT;
}
static
-void writeSentinel(mpv_puffette *out) {
- DEBUG_PRINTF("outputting sentinel to %p\n", out);
- memset(out, 0, sizeof(*out));
- out->report = INVALID_REPORT;
-}
-
-static
void writeDeadPoint(mpv_kilopuff *out, const vector<raw_puff> &puffs) {
for (const auto &puff : puffs) {
if (puff.unbounded) { /* mpv can never die */
@@ -156,8 +156,8 @@ void populateClusters(const vector<raw_puff> &puffs_in,
static
void writeKiloPuff(const map<ClusterKey, vector<raw_puff>>::const_iterator &it,
- const ReportManager &rm, u32 counter_offset, mpv *m,
- mpv_kilopuff *kp, mpv_puffette **pa) {
+ const ReportManager &rm, u32 counter_offset, mpv *m,
+ mpv_kilopuff *kp, mpv_puffette **pa) {
const CharReach &reach = it->first.reach;
const vector<raw_puff> &puffs = it->second;
@@ -175,13 +175,13 @@ void writeKiloPuff(const map<ClusterKey, vector<raw_puff>>::const_iterator &it,
size_t set = reach.find_first();
assert(set != CharReach::npos);
kp->u.verm.c = (char)set;
- } else if (shuftiBuildMasks(~reach, (u8 *)&kp->u.shuf.mask_lo,
- (u8 *)&kp->u.shuf.mask_hi) != -1) {
+ } else if (shuftiBuildMasks(~reach, (u8 *)&kp->u.shuf.mask_lo,
+ (u8 *)&kp->u.shuf.mask_hi) != -1) {
kp->type = MPV_SHUFTI;
} else {
kp->type = MPV_TRUFFLE;
- truffleBuildMasks(~reach, (u8 *)&kp->u.truffle.mask1,
- (u8 *)&kp->u.truffle.mask2);
+ truffleBuildMasks(~reach, (u8 *)&kp->u.truffle.mask1,
+ (u8 *)&kp->u.truffle.mask2);
}
kp->count = verify_u32(puffs.size());
@@ -191,11 +191,11 @@ void writeKiloPuff(const map<ClusterKey, vector<raw_puff>>::const_iterator &it,
kp->puffette_offset = verify_u32((char *)*pa - (char *)m);
for (size_t i = 0; i < puffs.size(); i++) {
assert(!it->first.auto_restart || puffs[i].unbounded);
- writePuffette(*pa + i, puffs[i], rm);
+ writePuffette(*pa + i, puffs[i], rm);
}
*pa += puffs.size();
- writeSentinel(*pa);
+ writeSentinel(*pa);
++*pa;
writeDeadPoint(kp, puffs);
@@ -208,7 +208,7 @@ void writeCoreNfa(NFA *nfa, u32 len, u32 min_width, u32 max_counter,
nfa->length = len;
nfa->nPositions = max_counter - 1;
- nfa->type = MPV_NFA;
+ nfa->type = MPV_NFA;
nfa->streamStateSize = streamStateSize;
assert(16 >= sizeof(mpv_decomp_kilo));
nfa->scratchStateSize = scratchStateSize;
@@ -309,9 +309,9 @@ const mpv_counter_info &findCounter(const vector<mpv_counter_info> &counters,
return counters.front();
}
-bytecode_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
- const vector<raw_puff> &triggered_puffs,
- const ReportManager &rm) {
+bytecode_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
+ const vector<raw_puff> &triggered_puffs,
+ const ReportManager &rm) {
assert(!puffs_in.empty() || !triggered_puffs.empty());
u32 puffette_count = puffs_in.size() + triggered_puffs.size();
@@ -343,7 +343,7 @@ bytecode_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
DEBUG_PRINTF("%u puffs, len = %u\n", puffette_count, len);
- auto nfa = make_zeroed_bytecode_ptr<NFA>(len);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(len);
mpv_puffette *pa_base = (mpv_puffette *)
((char *)nfa.get() + sizeof(NFA) + sizeof(mpv)
@@ -351,7 +351,7 @@ bytecode_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
+ sizeof(mpv_counter_info) * counters.size());
mpv_puffette *pa = pa_base;
- writeSentinel(pa);
+ writeSentinel(pa);
++pa; /* skip init sentinel */
@@ -377,9 +377,9 @@ bytecode_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
mpv_kilopuff *kp_begin = (mpv_kilopuff *)(m + 1);
mpv_kilopuff *kp = kp_begin;
for (auto it = puff_clusters.begin(); it != puff_clusters.end(); ++it) {
- writeKiloPuff(it, rm,
- findCounter(counters, kp - kp_begin).counter_offset, m,
- kp, &pa);
+ writeKiloPuff(it, rm,
+ findCounter(counters, kp - kp_begin).counter_offset, m,
+ kp, &pa);
++kp;
}
assert((char *)pa == (char *)nfa.get() + len);
diff --git a/contrib/libs/hyperscan/src/nfa/mpvcompile.h b/contrib/libs/hyperscan/src/nfa/mpvcompile.h
index d9bfdb4a2ff..4f820e43658 100644
--- a/contrib/libs/hyperscan/src/nfa/mpvcompile.h
+++ b/contrib/libs/hyperscan/src/nfa/mpvcompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,7 +30,7 @@
#define MPV_COMPILE_H
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/charreach.h"
#include <memory>
@@ -40,19 +40,19 @@ struct NFA;
namespace ue2 {
-class ReportManager;
-
+class ReportManager;
+
struct raw_puff {
raw_puff(u32 repeats_in, bool unbounded_in, ReportID report_in,
- const CharReach &reach_in, bool auto_restart_in = false,
- bool simple_exhaust_in = false)
+ const CharReach &reach_in, bool auto_restart_in = false,
+ bool simple_exhaust_in = false)
: repeats(repeats_in), unbounded(unbounded_in),
- auto_restart(auto_restart_in), simple_exhaust(simple_exhaust_in),
- report(report_in), reach(reach_in) {}
+ auto_restart(auto_restart_in), simple_exhaust(simple_exhaust_in),
+ report(report_in), reach(reach_in) {}
u32 repeats; /**< report match after this many matching bytes */
bool unbounded; /**< keep producing matches after repeats are reached */
bool auto_restart; /**< for /[^X]{n}/ type patterns */
- bool simple_exhaust; /* first report will exhaust us */
+ bool simple_exhaust; /* first report will exhaust us */
ReportID report;
CharReach reach; /**< = ~escapes */
};
@@ -61,9 +61,9 @@ struct raw_puff {
* puffs in the triggered_puffs vector are enabled when an TOP_N event is
* delivered corresponding to their index in the vector
*/
-bytecode_ptr<NFA> mpvCompile(const std::vector<raw_puff> &puffs,
- const std::vector<raw_puff> &triggered_puffs,
- const ReportManager &rm);
+bytecode_ptr<NFA> mpvCompile(const std::vector<raw_puff> &puffs,
+ const std::vector<raw_puff> &triggered_puffs,
+ const ReportManager &rm);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_api.h b/contrib/libs/hyperscan/src/nfa/nfa_api.h
index c97e2cadf22..e3f7f74311a 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_api.h
+++ b/contrib/libs/hyperscan/src/nfa/nfa_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -120,16 +120,16 @@ char nfaInitCompressedState(const struct NFA *nfa, u64a offset, void *state,
*/
char nfaQueueExec(const struct NFA *nfa, struct mq *q, s64a end);
-/**
- * Main execution function that doesn't perform the checks and optimisations of
- * nfaQueueExec() and just dispatches directly to the nfa implementations. It is
- * intended to be used by the Tamarama engine.
- */
-char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end);
-
-/** Return value indicating that the engine is dead. */
-#define MO_DEAD 0
-
+/**
+ * Main execution function that doesn't perform the checks and optimisations of
+ * nfaQueueExec() and just dispatches directly to the nfa implementations. It is
+ * intended to be used by the Tamarama engine.
+ */
+char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end);
+
+/** Return value indicating that the engine is dead. */
+#define MO_DEAD 0
+
/** Return value indicating that the engine is alive. */
#define MO_ALIVE 1
@@ -166,13 +166,13 @@ char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end);
char nfaQueueExecToMatch(const struct NFA *nfa, struct mq *q, s64a end);
/**
- * Main execution function that doesn't perform the checks and optimisations of
- * nfaQueueExecToMatch() and just dispatches directly to the nfa
- * implementations. It is intended to be used by the Tamarama engine.
- */
-char nfaQueueExec2_raw(const struct NFA *nfa, struct mq *q, s64a end);
-
-/**
+ * Main execution function that doesn't perform the checks and optimisations of
+ * nfaQueueExecToMatch() and just dispatches directly to the nfa
+ * implementations. It is intended to be used by the Tamarama engine.
+ */
+char nfaQueueExec2_raw(const struct NFA *nfa, struct mq *q, s64a end);
+
+/**
* Report matches at the current queue location.
*
* @param nfa the NFA to execute
@@ -193,15 +193,15 @@ char nfaReportCurrentMatches(const struct NFA *nfa, struct mq *q);
char nfaInAcceptState(const struct NFA *nfa, ReportID report, struct mq *q);
/**
- * Returns non-zero if the NFA is in any accept state regardless of report
- * ID.
- */
-char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q);
-
-/**
+ * Returns non-zero if the NFA is in any accept state regardless of report
+ * ID.
+ */
+char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q);
+
+/**
* Process the queued commands on the given NFA up to end or the first match.
*
- * Note: This version is meant for rose prefix/infix NFAs:
+ * Note: This version is meant for rose prefix/infix NFAs:
* - never uses a callback
* - loading of state at a point in history is not special cased
*
@@ -210,9 +210,9 @@ char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q);
* end with some variant of end. The location field of the events must
* be monotonically increasing. If not all the data was processed during
* the call, the queue is updated to reflect the remaining work.
- * @param report we are interested in. If the given report will be raised at
- * the end location, the function returns @ref MO_MATCHES_PENDING. If no
- * match information is desired, MO_INVALID_IDX should be passed in.
+ * @param report we are interested in. If the given report will be raised at
+ * the end location, the function returns @ref MO_MATCHES_PENDING. If no
+ * match information is desired, MO_INVALID_IDX should be passed in.
* @return @ref MO_ALIVE if the nfa is still active with no matches pending,
* and @ref MO_MATCHES_PENDING if there are matches pending, 0 if not
* alive
@@ -228,9 +228,9 @@ char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID report);
* Runs an NFA in reverse from (buf + buflen) to buf and then from (hbuf + hlen)
* to hbuf (main buffer and history buffer).
*
- * Note: provides the match location as the "end" offset when the callback is
- * called.
- *
+ * Note: provides the match location as the "end" offset when the callback is
+ * called.
+ *
* @param nfa engine to run
* @param offset base offset of buf
* @param buf main buffer
@@ -242,7 +242,7 @@ char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID report);
*/
char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
size_t buflen, const u8 *hbuf, size_t hlen,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
/**
* Check whether the given NFA's state indicates that it is in one or more
@@ -256,13 +256,13 @@ char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
* @param offset the offset to return (via the callback) with each match
* @param callback the callback to call for each match raised
* @param context context pointer passed to each callback
- *
- * @return @ref MO_HALT_MATCHING if the user instructed us to halt, otherwise
- * @ref MO_CONTINUE_MATCHING.
+ *
+ * @return @ref MO_HALT_MATCHING if the user instructed us to halt, otherwise
+ * @ref MO_CONTINUE_MATCHING.
*/
char nfaCheckFinalState(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context);
+ NfaCallback callback, void *context);
/**
* Indicates if an engine is a zombie.
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_api_dispatch.c b/contrib/libs/hyperscan/src/nfa/nfa_api_dispatch.c
index 6a52b7ca7d5..75cac4b4815 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_api_dispatch.c
+++ b/contrib/libs/hyperscan/src/nfa/nfa_api_dispatch.c
@@ -41,59 +41,59 @@
#include "lbr.h"
#include "limex.h"
#include "mcclellan.h"
-#include "mcsheng.h"
+#include "mcsheng.h"
#include "mpv.h"
-#include "sheng.h"
-#include "tamarama.h"
+#include "sheng.h"
+#include "tamarama.h"
-#define DISPATCH_CASE(dc_ltype, dc_ftype, dc_func_call) \
- case dc_ltype: \
- return nfaExec##dc_ftype##dc_func_call; \
+#define DISPATCH_CASE(dc_ltype, dc_ftype, dc_func_call) \
+ case dc_ltype: \
+ return nfaExec##dc_ftype##dc_func_call; \
break
// general framework calls
-#define DISPATCH_BY_NFA_TYPE(dbnt_func) \
- switch (nfa->type) { \
- DISPATCH_CASE(LIMEX_NFA_32, LimEx32, dbnt_func); \
- DISPATCH_CASE(LIMEX_NFA_64, LimEx64, dbnt_func); \
- DISPATCH_CASE(LIMEX_NFA_128, LimEx128, dbnt_func); \
- DISPATCH_CASE(LIMEX_NFA_256, LimEx256, dbnt_func); \
- DISPATCH_CASE(LIMEX_NFA_384, LimEx384, dbnt_func); \
- DISPATCH_CASE(LIMEX_NFA_512, LimEx512, dbnt_func); \
- DISPATCH_CASE(MCCLELLAN_NFA_8, McClellan8, dbnt_func); \
- DISPATCH_CASE(MCCLELLAN_NFA_16, McClellan16, dbnt_func); \
- DISPATCH_CASE(GOUGH_NFA_8, Gough8, dbnt_func); \
- DISPATCH_CASE(GOUGH_NFA_16, Gough16, dbnt_func); \
- DISPATCH_CASE(MPV_NFA, Mpv, dbnt_func); \
- DISPATCH_CASE(LBR_NFA_DOT, LbrDot, dbnt_func); \
- DISPATCH_CASE(LBR_NFA_VERM, LbrVerm, dbnt_func); \
- DISPATCH_CASE(LBR_NFA_NVERM, LbrNVerm, dbnt_func); \
- DISPATCH_CASE(LBR_NFA_SHUF, LbrShuf, dbnt_func); \
- DISPATCH_CASE(LBR_NFA_TRUF, LbrTruf, dbnt_func); \
- DISPATCH_CASE(CASTLE_NFA, Castle, dbnt_func); \
- DISPATCH_CASE(SHENG_NFA, Sheng, dbnt_func); \
- DISPATCH_CASE(TAMARAMA_NFA, Tamarama, dbnt_func); \
- DISPATCH_CASE(MCSHENG_NFA_8, McSheng8, dbnt_func); \
- DISPATCH_CASE(MCSHENG_NFA_16, McSheng16, dbnt_func); \
+#define DISPATCH_BY_NFA_TYPE(dbnt_func) \
+ switch (nfa->type) { \
+ DISPATCH_CASE(LIMEX_NFA_32, LimEx32, dbnt_func); \
+ DISPATCH_CASE(LIMEX_NFA_64, LimEx64, dbnt_func); \
+ DISPATCH_CASE(LIMEX_NFA_128, LimEx128, dbnt_func); \
+ DISPATCH_CASE(LIMEX_NFA_256, LimEx256, dbnt_func); \
+ DISPATCH_CASE(LIMEX_NFA_384, LimEx384, dbnt_func); \
+ DISPATCH_CASE(LIMEX_NFA_512, LimEx512, dbnt_func); \
+ DISPATCH_CASE(MCCLELLAN_NFA_8, McClellan8, dbnt_func); \
+ DISPATCH_CASE(MCCLELLAN_NFA_16, McClellan16, dbnt_func); \
+ DISPATCH_CASE(GOUGH_NFA_8, Gough8, dbnt_func); \
+ DISPATCH_CASE(GOUGH_NFA_16, Gough16, dbnt_func); \
+ DISPATCH_CASE(MPV_NFA, Mpv, dbnt_func); \
+ DISPATCH_CASE(LBR_NFA_DOT, LbrDot, dbnt_func); \
+ DISPATCH_CASE(LBR_NFA_VERM, LbrVerm, dbnt_func); \
+ DISPATCH_CASE(LBR_NFA_NVERM, LbrNVerm, dbnt_func); \
+ DISPATCH_CASE(LBR_NFA_SHUF, LbrShuf, dbnt_func); \
+ DISPATCH_CASE(LBR_NFA_TRUF, LbrTruf, dbnt_func); \
+ DISPATCH_CASE(CASTLE_NFA, Castle, dbnt_func); \
+ DISPATCH_CASE(SHENG_NFA, Sheng, dbnt_func); \
+ DISPATCH_CASE(TAMARAMA_NFA, Tamarama, dbnt_func); \
+ DISPATCH_CASE(MCSHENG_NFA_8, McSheng8, dbnt_func); \
+ DISPATCH_CASE(MCSHENG_NFA_16, McSheng16, dbnt_func); \
DISPATCH_CASE(SHENG_NFA_32, Sheng32, dbnt_func); \
DISPATCH_CASE(SHENG_NFA_64, Sheng64, dbnt_func); \
DISPATCH_CASE(MCSHENG_64_NFA_8, McSheng64_8, dbnt_func); \
DISPATCH_CASE(MCSHENG_64_NFA_16, McSheng64_16, dbnt_func); \
- default: \
- assert(0); \
+ default: \
+ assert(0); \
}
char nfaCheckFinalState(const struct NFA *nfa, const char *state,
const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
+ NfaCallback callback, void *context) {
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
// Caller should avoid calling us if we can never produce matches.
assert(nfaAcceptsEod(nfa));
DISPATCH_BY_NFA_TYPE(_testEOD(nfa, state, streamState, offset, callback,
- context));
+ context));
return 0;
}
@@ -116,14 +116,14 @@ char nfaQueueExec2_i(const struct NFA *nfa, struct mq *q, s64a end) {
return 0;
}
-char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end) {
- return nfaQueueExec_i(nfa, q, end);
-}
-
-char nfaQueueExec2_raw(const struct NFA *nfa, struct mq *q, s64a end) {
- return nfaQueueExec2_i(nfa, q, end);
-}
-
+char nfaQueueExec_raw(const struct NFA *nfa, struct mq *q, s64a end) {
+ return nfaQueueExec_i(nfa, q, end);
+}
+
+char nfaQueueExec2_raw(const struct NFA *nfa, struct mq *q, s64a end) {
+ return nfaQueueExec2_i(nfa, q, end);
+}
+
static really_inline
char nfaQueueExecRose_i(const struct NFA *nfa, struct mq *q, ReportID report) {
DISPATCH_BY_NFA_TYPE(_QR(nfa, q, report));
@@ -303,11 +303,11 @@ char nfaInAcceptState(const struct NFA *nfa, ReportID report, struct mq *q) {
return 0;
}
-char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q) {
- DISPATCH_BY_NFA_TYPE(_inAnyAccept(nfa, q));
- return 0;
-}
-
+char nfaInAnyAcceptState(const struct NFA *nfa, struct mq *q) {
+ DISPATCH_BY_NFA_TYPE(_inAnyAccept(nfa, q));
+ return 0;
+}
+
char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID r) {
DEBUG_PRINTF("nfa=%p\n", nfa);
#ifdef DEBUG
@@ -325,12 +325,12 @@ char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID r) {
char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
size_t buflen, const u8 *hbuf, size_t hlen,
- NfaCallback callback, void *context) {
+ NfaCallback callback, void *context) {
assert(nfa);
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
DISPATCH_BY_NFA_TYPE(_B_Reverse(nfa, offset, buf, buflen, hbuf, hlen,
- callback, context));
+ callback, context));
return 0;
}
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_api_queue.h b/contrib/libs/hyperscan/src/nfa/nfa_api_queue.h
index 52ce214c5f2..e3579a7ee2a 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_api_queue.h
+++ b/contrib/libs/hyperscan/src/nfa/nfa_api_queue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_build_util.cpp b/contrib/libs/hyperscan/src/nfa/nfa_build_util.cpp
index 293a84f8ac0..47153163e9f 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_build_util.cpp
+++ b/contrib/libs/hyperscan/src/nfa/nfa_build_util.cpp
@@ -30,8 +30,8 @@
#include "limex_internal.h"
#include "mcclellancompile.h"
-#include "mcsheng_compile.h"
-#include "shengcompile.h"
+#include "mcsheng_compile.h"
+#include "shengcompile.h"
#include "nfa_internal.h"
#include "repeat_internal.h"
#include "ue2common.h"
@@ -80,7 +80,7 @@ struct DISPATCH_BY_NFA_TYPE_INT<sfunc, rv_t, arg_t, INVALID_NFA> {
decltype(arg), (NFAEngineType)0>::doOp(i, arg)
}
-typedef bool (*nfa_dispatch_fn)(const NFA *nfa);
+typedef bool (*nfa_dispatch_fn)(const NFA *nfa);
template<typename T>
static
@@ -89,40 +89,40 @@ bool has_accel_limex(const NFA *nfa) {
return limex->accelCount;
}
-template<typename T>
+template<typename T>
+static
+bool has_repeats_limex(const NFA *nfa) {
+ const T *limex = (const T *)getImplNfa(nfa);
+ return limex->repeatCount;
+}
+
+
+template<typename T>
static
-bool has_repeats_limex(const NFA *nfa) {
- const T *limex = (const T *)getImplNfa(nfa);
- return limex->repeatCount;
-}
-
-
-template<typename T>
-static
-bool has_repeats_other_than_firsts_limex(const NFA *nfa) {
- const T *limex = (const T *)getImplNfa(nfa);
- const char *ptr = (const char *)limex;
-
- const u32 *repeatOffset = (const u32 *)(ptr + limex->repeatOffset);
-
- for (u32 i = 0; i < limex->repeatCount; i++) {
- u32 offset = repeatOffset[i];
- const NFARepeatInfo *info = (const NFARepeatInfo *)(ptr + offset);
- const RepeatInfo *repeat =
- (const RepeatInfo *)((const char *)info + sizeof(*info));
- if (repeat->type != REPEAT_FIRST) {
- return true;
- }
- }
-
+bool has_repeats_other_than_firsts_limex(const NFA *nfa) {
+ const T *limex = (const T *)getImplNfa(nfa);
+ const char *ptr = (const char *)limex;
+
+ const u32 *repeatOffset = (const u32 *)(ptr + limex->repeatOffset);
+
+ for (u32 i = 0; i < limex->repeatCount; i++) {
+ u32 offset = repeatOffset[i];
+ const NFARepeatInfo *info = (const NFARepeatInfo *)(ptr + offset);
+ const RepeatInfo *repeat =
+ (const RepeatInfo *)((const char *)info + sizeof(*info));
+ if (repeat->type != REPEAT_FIRST) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static
+bool dispatch_false(const NFA *) {
return false;
}
-static
-bool dispatch_false(const NFA *) {
- return false;
-}
-
#ifdef DUMP_SUPPORT
namespace {
template<NFAEngineType t>
@@ -171,51 +171,51 @@ enum NFACategory {NFA_LIMEX, NFA_OTHER};
#define DO_IF_DUMP_SUPPORT(a)
#endif
-#define MAKE_LIMEX_TRAITS(mlt_size, mlt_align) \
- template<> struct NFATraits<LIMEX_NFA_##mlt_size> { \
+#define MAKE_LIMEX_TRAITS(mlt_size, mlt_align) \
+ template<> struct NFATraits<LIMEX_NFA_##mlt_size> { \
static UNUSED const char *name; \
static const NFACategory category = NFA_LIMEX; \
typedef LimExNFA##mlt_size implNFA_t; \
- static const nfa_dispatch_fn has_accel; \
- static const nfa_dispatch_fn has_repeats; \
- static const nfa_dispatch_fn has_repeats_other_than_firsts; \
+ static const nfa_dispatch_fn has_accel; \
+ static const nfa_dispatch_fn has_repeats; \
+ static const nfa_dispatch_fn has_repeats_other_than_firsts; \
static const u32 stateAlign = \
- MAX(mlt_align, alignof(RepeatControl)); \
+ MAX(mlt_align, alignof(RepeatControl)); \
}; \
- const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_accel \
+ const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_accel \
= has_accel_limex<LimExNFA##mlt_size>; \
- const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_repeats \
- = has_repeats_limex<LimExNFA##mlt_size>; \
- const nfa_dispatch_fn \
- NFATraits<LIMEX_NFA_##mlt_size>::has_repeats_other_than_firsts \
- = has_repeats_other_than_firsts_limex<LimExNFA##mlt_size>; \
+ const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_repeats \
+ = has_repeats_limex<LimExNFA##mlt_size>; \
+ const nfa_dispatch_fn \
+ NFATraits<LIMEX_NFA_##mlt_size>::has_repeats_other_than_firsts \
+ = has_repeats_other_than_firsts_limex<LimExNFA##mlt_size>; \
DO_IF_DUMP_SUPPORT( \
- const char *NFATraits<LIMEX_NFA_##mlt_size>::name \
- = "LimEx "#mlt_size; \
- template<> struct getDescription<LIMEX_NFA_##mlt_size> { \
- static string call(const void *p) { \
- return getDescriptionLimEx<LIMEX_NFA_##mlt_size>((const NFA *)p); \
- } \
+ const char *NFATraits<LIMEX_NFA_##mlt_size>::name \
+ = "LimEx "#mlt_size; \
+ template<> struct getDescription<LIMEX_NFA_##mlt_size> { \
+ static string call(const void *p) { \
+ return getDescriptionLimEx<LIMEX_NFA_##mlt_size>((const NFA *)p); \
+ } \
};)
-MAKE_LIMEX_TRAITS(32, alignof(u32))
-MAKE_LIMEX_TRAITS(64, alignof(m128)) /* special, 32bit arch uses m128 */
-MAKE_LIMEX_TRAITS(128, alignof(m128))
-MAKE_LIMEX_TRAITS(256, alignof(m256))
-MAKE_LIMEX_TRAITS(384, alignof(m384))
-MAKE_LIMEX_TRAITS(512, alignof(m512))
+MAKE_LIMEX_TRAITS(32, alignof(u32))
+MAKE_LIMEX_TRAITS(64, alignof(m128)) /* special, 32bit arch uses m128 */
+MAKE_LIMEX_TRAITS(128, alignof(m128))
+MAKE_LIMEX_TRAITS(256, alignof(m256))
+MAKE_LIMEX_TRAITS(384, alignof(m384))
+MAKE_LIMEX_TRAITS(512, alignof(m512))
template<> struct NFATraits<MCCLELLAN_NFA_8> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_accel = has_accel_mcclellan;
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_accel = has_accel_mcclellan;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
const char *NFATraits<MCCLELLAN_NFA_8>::name = "McClellan 8";
#endif
@@ -224,13 +224,13 @@ template<> struct NFATraits<MCCLELLAN_NFA_16> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 2;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_accel = has_accel_mcclellan;
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_accel = has_accel_mcclellan;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCCLELLAN_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
const char *NFATraits<MCCLELLAN_NFA_16>::name = "McClellan 16";
#endif
@@ -239,13 +239,13 @@ template<> struct NFATraits<GOUGH_NFA_8> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_accel = has_accel_mcclellan;
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_accel = has_accel_mcclellan;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
const char *NFATraits<GOUGH_NFA_8>::name = "Goughfish 8";
#endif
@@ -254,182 +254,182 @@ template<> struct NFATraits<GOUGH_NFA_16> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_accel = has_accel_mcclellan;
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_accel = has_accel_mcclellan;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<GOUGH_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
const char *NFATraits<GOUGH_NFA_16>::name = "Goughfish 16";
#endif
-template<> struct NFATraits<MPV_NFA> {
+template<> struct NFATraits<MPV_NFA> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<MPV_NFA>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<MPV_NFA>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<MPV_NFA>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<MPV_NFA>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<MPV_NFA>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<MPV_NFA>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<MPV_NFA>::name = "Mega-Puff-Vac";
+const char *NFATraits<MPV_NFA>::name = "Mega-Puff-Vac";
#endif
-template<> struct NFATraits<CASTLE_NFA> {
+template<> struct NFATraits<CASTLE_NFA> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<CASTLE_NFA>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<CASTLE_NFA>::name = "Castle";
+const char *NFATraits<CASTLE_NFA>::name = "Castle";
#endif
-template<> struct NFATraits<LBR_NFA_DOT> {
+template<> struct NFATraits<LBR_NFA_DOT> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_DOT>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<LBR_NFA_DOT>::name = "Lim Bounded Repeat (D)";
+const char *NFATraits<LBR_NFA_DOT>::name = "Lim Bounded Repeat (D)";
#endif
-template<> struct NFATraits<LBR_NFA_VERM> {
+template<> struct NFATraits<LBR_NFA_VERM> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_VERM>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<LBR_NFA_VERM>::name = "Lim Bounded Repeat (V)";
+const char *NFATraits<LBR_NFA_VERM>::name = "Lim Bounded Repeat (V)";
#endif
-template<> struct NFATraits<LBR_NFA_NVERM> {
+template<> struct NFATraits<LBR_NFA_NVERM> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_NVERM>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<LBR_NFA_NVERM>::name = "Lim Bounded Repeat (NV)";
+const char *NFATraits<LBR_NFA_NVERM>::name = "Lim Bounded Repeat (NV)";
#endif
-template<> struct NFATraits<LBR_NFA_SHUF> {
+template<> struct NFATraits<LBR_NFA_SHUF> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_SHUF>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<LBR_NFA_SHUF>::name = "Lim Bounded Repeat (S)";
+const char *NFATraits<LBR_NFA_SHUF>::name = "Lim Bounded Repeat (S)";
#endif
-template<> struct NFATraits<LBR_NFA_TRUF> {
+template<> struct NFATraits<LBR_NFA_TRUF> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
};
-const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_repeats_other_than_firsts = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<LBR_NFA_TRUF>::has_repeats_other_than_firsts = dispatch_false;
#if defined(DUMP_SUPPORT)
-const char *NFATraits<LBR_NFA_TRUF>::name = "Lim Bounded Repeat (M)";
+const char *NFATraits<LBR_NFA_TRUF>::name = "Lim Bounded Repeat (M)";
+#endif
+
+template<> struct NFATraits<SHENG_NFA> {
+ UNUSED static const char *name;
+ static const NFACategory category = NFA_OTHER;
+ static const u32 stateAlign = 1;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
+};
+const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_accel = has_accel_sheng;
+const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_repeats_other_than_firsts = dispatch_false;
+#if defined(DUMP_SUPPORT)
+const char *NFATraits<SHENG_NFA>::name = "Sheng";
+#endif
+
+template<> struct NFATraits<TAMARAMA_NFA> {
+ UNUSED static const char *name;
+ static const NFACategory category = NFA_OTHER;
+ static const u32 stateAlign = 64;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
+};
+const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_accel = dispatch_false;
+const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_repeats_other_than_firsts = dispatch_false;
+#if defined(DUMP_SUPPORT)
+const char *NFATraits<TAMARAMA_NFA>::name = "Tamarama";
+#endif
+
+template<> struct NFATraits<MCSHENG_NFA_8> {
+ UNUSED static const char *name;
+ static const NFACategory category = NFA_OTHER;
+ static const u32 stateAlign = 1;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
+};
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_accel = has_accel_mcsheng;
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
+#if defined(DUMP_SUPPORT)
+const char *NFATraits<MCSHENG_NFA_8>::name = "Shengy McShengFace 8";
+#endif
+
+template<> struct NFATraits<MCSHENG_NFA_16> {
+ UNUSED static const char *name;
+ static const NFACategory category = NFA_OTHER;
+ static const u32 stateAlign = 2;
+ static const nfa_dispatch_fn has_accel;
+ static const nfa_dispatch_fn has_repeats;
+ static const nfa_dispatch_fn has_repeats_other_than_firsts;
+};
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_accel = has_accel_mcsheng;
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_repeats = dispatch_false;
+const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
+#if defined(DUMP_SUPPORT)
+const char *NFATraits<MCSHENG_NFA_16>::name = "Shengy McShengFace 16";
#endif
-template<> struct NFATraits<SHENG_NFA> {
- UNUSED static const char *name;
- static const NFACategory category = NFA_OTHER;
- static const u32 stateAlign = 1;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
-};
-const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_accel = has_accel_sheng;
-const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<SHENG_NFA>::has_repeats_other_than_firsts = dispatch_false;
-#if defined(DUMP_SUPPORT)
-const char *NFATraits<SHENG_NFA>::name = "Sheng";
-#endif
-
-template<> struct NFATraits<TAMARAMA_NFA> {
- UNUSED static const char *name;
- static const NFACategory category = NFA_OTHER;
- static const u32 stateAlign = 64;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
-};
-const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_accel = dispatch_false;
-const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<TAMARAMA_NFA>::has_repeats_other_than_firsts = dispatch_false;
-#if defined(DUMP_SUPPORT)
-const char *NFATraits<TAMARAMA_NFA>::name = "Tamarama";
-#endif
-
-template<> struct NFATraits<MCSHENG_NFA_8> {
- UNUSED static const char *name;
- static const NFACategory category = NFA_OTHER;
- static const u32 stateAlign = 1;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
-};
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_accel = has_accel_mcsheng;
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_8>::has_repeats_other_than_firsts = dispatch_false;
-#if defined(DUMP_SUPPORT)
-const char *NFATraits<MCSHENG_NFA_8>::name = "Shengy McShengFace 8";
-#endif
-
-template<> struct NFATraits<MCSHENG_NFA_16> {
- UNUSED static const char *name;
- static const NFACategory category = NFA_OTHER;
- static const u32 stateAlign = 2;
- static const nfa_dispatch_fn has_accel;
- static const nfa_dispatch_fn has_repeats;
- static const nfa_dispatch_fn has_repeats_other_than_firsts;
-};
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_accel = has_accel_mcsheng;
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_repeats = dispatch_false;
-const nfa_dispatch_fn NFATraits<MCSHENG_NFA_16>::has_repeats_other_than_firsts = dispatch_false;
-#if defined(DUMP_SUPPORT)
-const char *NFATraits<MCSHENG_NFA_16>::name = "Shengy McShengFace 16";
-#endif
-
template<> struct NFATraits<SHENG_NFA_32> {
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
@@ -525,39 +525,39 @@ struct is_limex {
};
}
-namespace {
-template<NFAEngineType t>
-struct has_repeats_other_than_firsts_dispatch {
- static nfa_dispatch_fn call(const void *) {
- return NFATraits<t>::has_repeats_other_than_firsts;
+namespace {
+template<NFAEngineType t>
+struct has_repeats_other_than_firsts_dispatch {
+ static nfa_dispatch_fn call(const void *) {
+ return NFATraits<t>::has_repeats_other_than_firsts;
}
-};
-}
-
-bool has_bounded_repeats_other_than_firsts(const NFA &nfa) {
- return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type,
- has_repeats_other_than_firsts_dispatch,
- &nfa)(&nfa);
-}
-
-namespace {
-template<NFAEngineType t>
-struct has_repeats_dispatch {
- static nfa_dispatch_fn call(const void *) {
- return NFATraits<t>::has_repeats;
+};
+}
+
+bool has_bounded_repeats_other_than_firsts(const NFA &nfa) {
+ return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type,
+ has_repeats_other_than_firsts_dispatch,
+ &nfa)(&nfa);
+}
+
+namespace {
+template<NFAEngineType t>
+struct has_repeats_dispatch {
+ static nfa_dispatch_fn call(const void *) {
+ return NFATraits<t>::has_repeats;
}
-};
+};
}
bool has_bounded_repeats(const NFA &nfa) {
- return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, has_repeats_dispatch,
- &nfa)(&nfa);
+ return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, has_repeats_dispatch,
+ &nfa)(&nfa);
}
namespace {
template<NFAEngineType t>
struct has_accel_dispatch {
- static nfa_dispatch_fn call(const void *) {
+ static nfa_dispatch_fn call(const void *) {
return NFATraits<t>::has_accel;
}
};
@@ -565,7 +565,7 @@ struct has_accel_dispatch {
bool has_accel(const NFA &nfa) {
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, has_accel_dispatch,
- &nfa)(&nfa);
+ &nfa)(&nfa);
}
bool requires_decompress_key(const NFA &nfa) {
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_internal.h b/contrib/libs/hyperscan/src/nfa/nfa_internal.h
index 58832fd14d9..ad27e28b14d 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/nfa_internal.h
@@ -51,27 +51,27 @@ extern "C"
// Common data structures for NFAs
enum NFAEngineType {
- LIMEX_NFA_32,
- LIMEX_NFA_64,
- LIMEX_NFA_128,
- LIMEX_NFA_256,
- LIMEX_NFA_384,
- LIMEX_NFA_512,
+ LIMEX_NFA_32,
+ LIMEX_NFA_64,
+ LIMEX_NFA_128,
+ LIMEX_NFA_256,
+ LIMEX_NFA_384,
+ LIMEX_NFA_512,
MCCLELLAN_NFA_8, /**< magic pseudo nfa */
MCCLELLAN_NFA_16, /**< magic pseudo nfa */
GOUGH_NFA_8, /**< magic pseudo nfa */
GOUGH_NFA_16, /**< magic pseudo nfa */
- MPV_NFA, /**< magic pseudo nfa */
- LBR_NFA_DOT, /**< magic pseudo nfa */
- LBR_NFA_VERM, /**< magic pseudo nfa */
- LBR_NFA_NVERM, /**< magic pseudo nfa */
- LBR_NFA_SHUF, /**< magic pseudo nfa */
- LBR_NFA_TRUF, /**< magic pseudo nfa */
- CASTLE_NFA, /**< magic pseudo nfa */
- SHENG_NFA, /**< magic pseudo nfa */
- TAMARAMA_NFA, /**< magic nfa container */
- MCSHENG_NFA_8, /**< magic pseudo nfa */
- MCSHENG_NFA_16, /**< magic pseudo nfa */
+ MPV_NFA, /**< magic pseudo nfa */
+ LBR_NFA_DOT, /**< magic pseudo nfa */
+ LBR_NFA_VERM, /**< magic pseudo nfa */
+ LBR_NFA_NVERM, /**< magic pseudo nfa */
+ LBR_NFA_SHUF, /**< magic pseudo nfa */
+ LBR_NFA_TRUF, /**< magic pseudo nfa */
+ CASTLE_NFA, /**< magic pseudo nfa */
+ SHENG_NFA, /**< magic pseudo nfa */
+ TAMARAMA_NFA, /**< magic nfa container */
+ MCSHENG_NFA_8, /**< magic pseudo nfa */
+ MCSHENG_NFA_16, /**< magic pseudo nfa */
SHENG_NFA_32, /**< magic pseudo nfa */
SHENG_NFA_64, /**< magic pseudo nfa */
MCSHENG_64_NFA_8, /**< magic pseudo nfa */
@@ -149,23 +149,23 @@ static really_inline int isMcClellanType(u8 t) {
return t == MCCLELLAN_NFA_8 || t == MCCLELLAN_NFA_16;
}
-/** \brief True if the given type (from NFA::type) is a Sheng-McClellan hybrid
- * DFA. */
-static really_inline int isShengMcClellanType(u8 t) {
+/** \brief True if the given type (from NFA::type) is a Sheng-McClellan hybrid
+ * DFA. */
+static really_inline int isShengMcClellanType(u8 t) {
return t == MCSHENG_NFA_8 || t == MCSHENG_NFA_16 ||
t == MCSHENG_64_NFA_8 || t == MCSHENG_64_NFA_16;
-}
-
+}
+
/** \brief True if the given type (from NFA::type) is a Gough DFA. */
static really_inline int isGoughType(u8 t) {
return t == GOUGH_NFA_8 || t == GOUGH_NFA_16;
}
-/** \brief True if the given type (from NFA::type) is a Sheng DFA. */
+/** \brief True if the given type (from NFA::type) is a Sheng DFA. */
static really_inline int isSheng16Type(u8 t) {
- return t == SHENG_NFA;
-}
-
+ return t == SHENG_NFA;
+}
+
/** \brief True if the given type (from NFA::type) is a Sheng32 DFA. */
static really_inline int isSheng32Type(u8 t) {
return t == SHENG_NFA_32;
@@ -181,32 +181,32 @@ static really_inline int isShengType(u8 t) {
return t == SHENG_NFA || t == SHENG_NFA_32 || t == SHENG_NFA_64;
}
-/**
- * \brief True if the given type (from NFA::type) is a McClellan, Gough or
- * Sheng DFA.
- */
+/**
+ * \brief True if the given type (from NFA::type) is a McClellan, Gough or
+ * Sheng DFA.
+ */
static really_inline int isDfaType(u8 t) {
- return isMcClellanType(t) || isGoughType(t) || isShengType(t)
- || isShengMcClellanType(t);
+ return isMcClellanType(t) || isGoughType(t) || isShengType(t)
+ || isShengMcClellanType(t);
+}
+
+static really_inline int isBigDfaType(u8 t) {
+ return t == MCCLELLAN_NFA_16 || t == MCSHENG_NFA_16 || t == GOUGH_NFA_16;
+}
+
+static really_inline int isSmallDfaType(u8 t) {
+ return isDfaType(t) && !isBigDfaType(t);
}
-static really_inline int isBigDfaType(u8 t) {
- return t == MCCLELLAN_NFA_16 || t == MCSHENG_NFA_16 || t == GOUGH_NFA_16;
-}
-
-static really_inline int isSmallDfaType(u8 t) {
- return isDfaType(t) && !isBigDfaType(t);
-}
-
/** \brief True if the given type (from NFA::type) is an NFA. */
static really_inline int isNfaType(u8 t) {
switch (t) {
- case LIMEX_NFA_32:
- case LIMEX_NFA_64:
- case LIMEX_NFA_128:
- case LIMEX_NFA_256:
- case LIMEX_NFA_384:
- case LIMEX_NFA_512:
+ case LIMEX_NFA_32:
+ case LIMEX_NFA_64:
+ case LIMEX_NFA_128:
+ case LIMEX_NFA_256:
+ case LIMEX_NFA_384:
+ case LIMEX_NFA_512:
return 1;
default:
break;
@@ -217,17 +217,17 @@ static really_inline int isNfaType(u8 t) {
/** \brief True if the given type (from NFA::type) is an LBR. */
static really_inline
int isLbrType(u8 t) {
- return t == LBR_NFA_DOT || t == LBR_NFA_VERM || t == LBR_NFA_NVERM ||
- t == LBR_NFA_SHUF || t == LBR_NFA_TRUF;
+ return t == LBR_NFA_DOT || t == LBR_NFA_VERM || t == LBR_NFA_NVERM ||
+ t == LBR_NFA_SHUF || t == LBR_NFA_TRUF;
+}
+
+/** \brief True if the given type (from NFA::type) is a container engine. */
+static really_inline
+int isContainerType(u8 t) {
+ return t == TAMARAMA_NFA;
}
-/** \brief True if the given type (from NFA::type) is a container engine. */
static really_inline
-int isContainerType(u8 t) {
- return t == TAMARAMA_NFA;
-}
-
-static really_inline
int isMultiTopType(u8 t) {
return !isDfaType(t) && !isLbrType(t);
}
@@ -239,14 +239,14 @@ int isMultiTopType(u8 t) {
/* Use for functions that return an integer. */
#define NFA_API_NO_IMPL(...) \
({ \
- assert(!"not implemented for this engine!"); \
+ assert(!"not implemented for this engine!"); \
0; /* return value, for places that need it */ \
})
/* Use for _zombie_status functions. */
#define NFA_API_ZOMBIE_NO_IMPL(...) \
({ \
- assert(!"not implemented for this engine!"); \
+ assert(!"not implemented for this engine!"); \
NFA_ZOMBIE_NO; \
})
diff --git a/contrib/libs/hyperscan/src/nfa/nfa_kind.h b/contrib/libs/hyperscan/src/nfa/nfa_kind.h
index 37e38ccacfa..f2ac6189b18 100644
--- a/contrib/libs/hyperscan/src/nfa/nfa_kind.h
+++ b/contrib/libs/hyperscan/src/nfa/nfa_kind.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,19 +26,19 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Data structures and helper functions used to describe the purpose of
- * a particular NFA engine at build time.
- */
-
+/**
+ * \file
+ * \brief Data structures and helper functions used to describe the purpose of
+ * a particular NFA engine at build time.
+ */
+
#ifndef NFA_KIND_H
#define NFA_KIND_H
#include "ue2common.h"
-#include <string>
-
+#include <string>
+
namespace ue2 {
/** \brief Specify the use-case for an nfa engine. */
@@ -47,102 +47,102 @@ enum nfa_kind {
NFA_INFIX, //!< rose infix
NFA_SUFFIX, //!< rose suffix
NFA_OUTFIX, //!< "outfix" nfa not triggered by external events
- NFA_OUTFIX_RAW, //!< "outfix", but with unmanaged reports
+ NFA_OUTFIX_RAW, //!< "outfix", but with unmanaged reports
NFA_REV_PREFIX, //! reverse running prefixes (for som)
- NFA_EAGER_PREFIX, //!< rose prefix that is also run up to matches
+ NFA_EAGER_PREFIX, //!< rose prefix that is also run up to matches
};
-/** \brief True if this kind of engine is triggered by a top event. */
-inline
+/** \brief True if this kind of engine is triggered by a top event. */
+inline
bool is_triggered(enum nfa_kind k) {
- switch (k) {
- case NFA_INFIX:
- case NFA_SUFFIX:
- case NFA_REV_PREFIX:
- return true;
- default:
- return false;
- }
+ switch (k) {
+ case NFA_INFIX:
+ case NFA_SUFFIX:
+ case NFA_REV_PREFIX:
+ return true;
+ default:
+ return false;
+ }
}
-/**
- * \brief True if this kind of engine generates actively checks for accept
- * states either to halt matching or to raise a callback. Only these engines
- * generated with this property should call nfaQueueExec() or
- * nfaQueueExecToMatch().
- */
-inline
+/**
+ * \brief True if this kind of engine generates actively checks for accept
+ * states either to halt matching or to raise a callback. Only these engines
+ * generated with this property should call nfaQueueExec() or
+ * nfaQueueExecToMatch().
+ */
+inline
bool generates_callbacks(enum nfa_kind k) {
- switch (k) {
- case NFA_SUFFIX:
- case NFA_OUTFIX:
- case NFA_OUTFIX_RAW:
- case NFA_REV_PREFIX:
- case NFA_EAGER_PREFIX:
- return true;
- default:
- return false;
- }
+ switch (k) {
+ case NFA_SUFFIX:
+ case NFA_OUTFIX:
+ case NFA_OUTFIX_RAW:
+ case NFA_REV_PREFIX:
+ case NFA_EAGER_PREFIX:
+ return true;
+ default:
+ return false;
+ }
}
-/**
- * \brief True if this kind of engine has its state inspected to see if it is in
- * an accept state. Engines generated with this property will commonly call
- * nfaQueueExecRose(), nfaInAcceptState(), and nfaInAnyAcceptState().
- */
-inline
-bool inspects_states_for_accepts(enum nfa_kind k) {
- switch (k) {
- case NFA_PREFIX:
- case NFA_INFIX:
- case NFA_EAGER_PREFIX:
- return true;
- default:
- return false;
- }
-}
-
-/**
- * \brief True if this kind of engine has reports that are managed by the \ref
- * ReportManager.
- */
-inline
-bool has_managed_reports(enum nfa_kind k) {
- switch (k) {
- case NFA_SUFFIX:
- case NFA_OUTFIX:
- return true;
- default:
- return false;
- }
-}
-
-#if defined(DEBUG) || defined(DUMP_SUPPORT)
-
-inline
-std::string to_string(nfa_kind k) {
- switch (k) {
- case NFA_PREFIX:
- return "PREFIX";
- case NFA_INFIX:
- return "INFIX";
- case NFA_SUFFIX:
- return "SUFFIX";
- case NFA_OUTFIX:
- return "OUTFIX";
- case NFA_REV_PREFIX:
- return "REV_PREFIX";
- case NFA_OUTFIX_RAW:
- return "OUTFIX_RAW";
- case NFA_EAGER_PREFIX:
- return "EAGER_PREFIX";
- }
- assert(0);
- return "?";
-}
-
-#endif
-
+/**
+ * \brief True if this kind of engine has its state inspected to see if it is in
+ * an accept state. Engines generated with this property will commonly call
+ * nfaQueueExecRose(), nfaInAcceptState(), and nfaInAnyAcceptState().
+ */
+inline
+bool inspects_states_for_accepts(enum nfa_kind k) {
+ switch (k) {
+ case NFA_PREFIX:
+ case NFA_INFIX:
+ case NFA_EAGER_PREFIX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * \brief True if this kind of engine has reports that are managed by the \ref
+ * ReportManager.
+ */
+inline
+bool has_managed_reports(enum nfa_kind k) {
+ switch (k) {
+ case NFA_SUFFIX:
+ case NFA_OUTFIX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#if defined(DEBUG) || defined(DUMP_SUPPORT)
+
+inline
+std::string to_string(nfa_kind k) {
+ switch (k) {
+ case NFA_PREFIX:
+ return "PREFIX";
+ case NFA_INFIX:
+ return "INFIX";
+ case NFA_SUFFIX:
+ return "SUFFIX";
+ case NFA_OUTFIX:
+ return "OUTFIX";
+ case NFA_REV_PREFIX:
+ return "REV_PREFIX";
+ case NFA_OUTFIX_RAW:
+ return "OUTFIX_RAW";
+ case NFA_EAGER_PREFIX:
+ return "EAGER_PREFIX";
+ }
+ assert(0);
+ return "?";
+}
+
+#endif
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfa/rdfa.cpp b/contrib/libs/hyperscan/src/nfa/rdfa.cpp
index f12120e2026..ae857b6af23 100644
--- a/contrib/libs/hyperscan/src/nfa/rdfa.cpp
+++ b/contrib/libs/hyperscan/src/nfa/rdfa.cpp
@@ -1,55 +1,55 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rdfa.h"
-
-namespace ue2 {
-
-// prevent weak vtables
-raw_dfa::~raw_dfa() {}
-
-void raw_dfa::stripExtraEodReports(void) {
- /* if a state generates a given report as a normal accept - then it does
- * not also need to generate an eod report for it */
- for (dstate &ds : states) {
- for (const ReportID &report : ds.reports) {
- ds.reports_eod.erase(report);
- }
- }
-}
-
-bool raw_dfa::hasEodReports(void) const {
- for (const dstate &ds : states) {
- if (!ds.reports_eod.empty()) {
- return true;
- }
- }
- return false;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rdfa.h"
+
+namespace ue2 {
+
+// prevent weak vtables
+raw_dfa::~raw_dfa() {}
+
+void raw_dfa::stripExtraEodReports(void) {
+ /* if a state generates a given report as a normal accept - then it does
+ * not also need to generate an eod report for it */
+ for (dstate &ds : states) {
+ for (const ReportID &report : ds.reports) {
+ ds.reports_eod.erase(report);
+ }
+ }
+}
+
+bool raw_dfa::hasEodReports(void) const {
+ for (const dstate &ds : states) {
+ if (!ds.reports_eod.empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/rdfa.h b/contrib/libs/hyperscan/src/nfa/rdfa.h
index 88597c4480c..6b994e4f2f3 100644
--- a/contrib/libs/hyperscan/src/nfa/rdfa.h
+++ b/contrib/libs/hyperscan/src/nfa/rdfa.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,7 @@
#include "nfa_kind.h"
#include "ue2common.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <array>
#include <vector>
@@ -81,7 +81,7 @@ struct raw_dfa {
explicit raw_dfa(nfa_kind k) : kind(k) {}
virtual ~raw_dfa();
- u16 getImplAlphaSize() const { return alpha_size - N_SPECIAL_SYMBOL; }
+ u16 getImplAlphaSize() const { return alpha_size - N_SPECIAL_SYMBOL; }
virtual void stripExtraEodReports(void);
bool hasEodReports(void) const;
};
diff --git a/contrib/libs/hyperscan/src/nfa/rdfa_graph.cpp b/contrib/libs/hyperscan/src/nfa/rdfa_graph.cpp
index ee404234cdf..2467748b989 100644
--- a/contrib/libs/hyperscan/src/nfa/rdfa_graph.cpp
+++ b/contrib/libs/hyperscan/src/nfa/rdfa_graph.cpp
@@ -1,68 +1,68 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-
-#include "rdfa_graph.h"
-
-#include "rdfa.h"
-#include "util/container.h"
-
-#include <vector>
-
-using namespace std;
-
-namespace ue2 {
-
-RdfaGraph::RdfaGraph(const raw_dfa &rdfa) {
- RdfaGraph &g = *this;
-
- vector<RdfaGraph::vertex_descriptor> verts;
- verts.reserve(rdfa.states.size());
- for (dstate_id_t i = 0; i < rdfa.states.size(); i++) {
- verts.push_back(add_vertex(g));
- assert(g[verts.back()].index == i);
- }
-
- symbol_t symbol_end = rdfa.alpha_size - 1;
-
- flat_set<dstate_id_t> local_succs;
- for (dstate_id_t i = 0; i < rdfa.states.size(); i++) {
- local_succs.clear();
- for (symbol_t s = 0; s < symbol_end; s++) {
- dstate_id_t next = rdfa.states[i].next[s];
- if (contains(local_succs, next)) {
- continue;
- }
- DEBUG_PRINTF("%hu->%hu\n", i, next);
- add_edge(verts[i], verts[next], g);
- local_succs.insert(next);
- }
- }
-}
-
-}
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+
+#include "rdfa_graph.h"
+
+#include "rdfa.h"
+#include "util/container.h"
+
+#include <vector>
+
+using namespace std;
+
+namespace ue2 {
+
+RdfaGraph::RdfaGraph(const raw_dfa &rdfa) {
+ RdfaGraph &g = *this;
+
+ vector<RdfaGraph::vertex_descriptor> verts;
+ verts.reserve(rdfa.states.size());
+ for (dstate_id_t i = 0; i < rdfa.states.size(); i++) {
+ verts.push_back(add_vertex(g));
+ assert(g[verts.back()].index == i);
+ }
+
+ symbol_t symbol_end = rdfa.alpha_size - 1;
+
+ flat_set<dstate_id_t> local_succs;
+ for (dstate_id_t i = 0; i < rdfa.states.size(); i++) {
+ local_succs.clear();
+ for (symbol_t s = 0; s < symbol_end; s++) {
+ dstate_id_t next = rdfa.states[i].next[s];
+ if (contains(local_succs, next)) {
+ continue;
+ }
+ DEBUG_PRINTF("%hu->%hu\n", i, next);
+ add_edge(verts[i], verts[next], g);
+ local_succs.insert(next);
+ }
+ }
+}
+
+}
diff --git a/contrib/libs/hyperscan/src/nfa/rdfa_graph.h b/contrib/libs/hyperscan/src/nfa/rdfa_graph.h
index 63e1233a70a..6d166c2fb7c 100644
--- a/contrib/libs/hyperscan/src/nfa/rdfa_graph.h
+++ b/contrib/libs/hyperscan/src/nfa/rdfa_graph.h
@@ -1,54 +1,54 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef RDFA_GRAPH_H
-#define RDFA_GRAPH_H
-
-#include "ue2common.h"
-#include "util/ue2_graph.h"
-
-namespace ue2 {
-
-struct raw_dfa;
-
-struct RdfaVertexProps {
- size_t index = 0;
-};
-
-struct RdfaEdgeProps {
- size_t index = 0;
-};
-
-struct RdfaGraph : public ue2_graph<RdfaGraph, RdfaVertexProps, RdfaEdgeProps> {
- RdfaGraph(const raw_dfa &rdfa);
-};
-
-
-}
-
-#endif
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef RDFA_GRAPH_H
+#define RDFA_GRAPH_H
+
+#include "ue2common.h"
+#include "util/ue2_graph.h"
+
+namespace ue2 {
+
+struct raw_dfa;
+
+struct RdfaVertexProps {
+ size_t index = 0;
+};
+
+struct RdfaEdgeProps {
+ size_t index = 0;
+};
+
+struct RdfaGraph : public ue2_graph<RdfaGraph, RdfaVertexProps, RdfaEdgeProps> {
+ RdfaGraph(const raw_dfa &rdfa);
+};
+
+
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/rdfa_merge.cpp b/contrib/libs/hyperscan/src/nfa/rdfa_merge.cpp
index 430551be716..2ad871234f0 100644
--- a/contrib/libs/hyperscan/src/nfa/rdfa_merge.cpp
+++ b/contrib/libs/hyperscan/src/nfa/rdfa_merge.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,12 +36,12 @@
#include "nfagraph/ng_mcclellan_internal.h"
#include "util/container.h"
#include "util/determinise.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/make_unique.h"
#include "util/report_manager.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
-#include <algorithm>
+#include <algorithm>
#include <queue>
using namespace std;
@@ -54,8 +54,8 @@ namespace {
class Automaton_Merge {
public:
- using StateSet = vector<u16>;
- using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
+ using StateSet = vector<u16>;
+ using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
Automaton_Merge(const raw_dfa *rdfa1, const raw_dfa *rdfa2,
const ReportManager *rm_in, const Grey &grey_in)
@@ -137,10 +137,10 @@ public:
}
}
- // Sort so that our alphabet mapping isn't dependent on the order of
- // rdfas passed in.
- sort(esets.begin(), esets.end());
-
+ // Sort so that our alphabet mapping isn't dependent on the order of
+ // rdfas passed in.
+ sort(esets.begin(), esets.end());
+
alphasize = buildAlphabetFromEquivSets(esets, alpha, unalpha);
}
@@ -290,7 +290,7 @@ unique_ptr<raw_dfa> mergeTwoDfas(const raw_dfa *d1, const raw_dfa *d2,
auto rdfa = ue2::make_unique<raw_dfa>(d1->kind);
Automaton_Merge autom(d1, d2, rm, grey);
- if (determinise(autom, rdfa->states, max_states)) {
+ if (determinise(autom, rdfa->states, max_states)) {
rdfa->start_anchored = autom.start_anchored;
rdfa->start_floating = autom.start_floating;
rdfa->alpha_size = autom.alphasize;
@@ -375,7 +375,7 @@ unique_ptr<raw_dfa> mergeAllDfas(const vector<const raw_dfa *> &dfas,
DEBUG_PRINTF("merging dfa\n");
- if (!determinise(n, rdfa->states, max_states)) {
+ if (!determinise(n, rdfa->states, max_states)) {
DEBUG_PRINTF("state limit (%zu) exceeded\n", max_states);
return nullptr; /* over state limit */
}
diff --git a/contrib/libs/hyperscan/src/nfa/repeat.c b/contrib/libs/hyperscan/src/nfa/repeat.c
index 21cddd6f8ab..5b2e4df4ed5 100644
--- a/contrib/libs/hyperscan/src/nfa/repeat.c
+++ b/contrib/libs/hyperscan/src/nfa/repeat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -177,10 +177,10 @@ u64a repeatLastTopRange(const union RepeatControl *ctrl, const void *state) {
u64a repeatLastTopBitmap(const union RepeatControl *ctrl) {
const struct RepeatBitmapControl *xs = &ctrl->bitmap;
- if (!xs->bitmap) {
- /* last top was too long ago */
- return 0;
- }
+ if (!xs->bitmap) {
+ /* last top was too long ago */
+ return 0;
+ }
return xs->offset + 63 - clz64(xs->bitmap);
}
@@ -886,25 +886,25 @@ enum RepeatMatch repeatHasMatchTrailer(const struct RepeatInfo *info,
return REPEAT_NOMATCH;
}
-/** \brief True if the given value can be packed into len bytes. */
+/** \brief True if the given value can be packed into len bytes. */
+static really_inline
+int fits_in_len_bytes(u64a val, u32 len) {
+ if (len >= 8) {
+ return 1;
+ }
+ return val <= (1ULL << (len * 8));
+}
+
static really_inline
-int fits_in_len_bytes(u64a val, u32 len) {
- if (len >= 8) {
- return 1;
- }
- return val <= (1ULL << (len * 8));
-}
-
-static really_inline
void storePackedRelative(char *dest, u64a val, u64a offset, u64a max, u32 len) {
assert(val <= offset);
- assert(fits_in_len_bytes(max, len));
+ assert(fits_in_len_bytes(max, len));
u64a delta = offset - val;
if (delta >= max) {
delta = max;
}
DEBUG_PRINTF("delta %llu\n", delta);
- assert(fits_in_len_bytes(delta, len));
+ assert(fits_in_len_bytes(delta, len));
partial_store_u64a(dest, delta, len);
}
@@ -936,11 +936,11 @@ void repeatPackOffset(char *dest, const struct RepeatInfo *info,
const union RepeatControl *ctrl, u64a offset) {
const struct RepeatOffsetControl *xs = &ctrl->offset;
DEBUG_PRINTF("packing offset %llu [h %u]\n", xs->offset, info->horizon);
- if (!info->packedCtrlSize) {
- assert(info->type == REPEAT_ALWAYS);
- DEBUG_PRINTF("externally guarded .*\n");
- return;
- }
+ if (!info->packedCtrlSize) {
+ assert(info->type == REPEAT_ALWAYS);
+ DEBUG_PRINTF("externally guarded .*\n");
+ return;
+ }
storePackedRelative(dest, xs->offset, offset, info->horizon,
info->packedCtrlSize);
}
@@ -981,7 +981,7 @@ void repeatPackBitmap(char *dest, const struct RepeatInfo *info,
DEBUG_PRINTF("packing %llu into %u bytes\n", bitmap, info->packedCtrlSize);
// Write out packed bitmap.
- assert(fits_in_len_bytes(bitmap, info->packedCtrlSize));
+ assert(fits_in_len_bytes(bitmap, info->packedCtrlSize));
partial_store_u64a(dest, bitmap, info->packedCtrlSize);
}
@@ -1060,9 +1060,9 @@ void repeatPack(char *dest, const struct RepeatInfo *info,
case REPEAT_TRAILER:
repeatPackTrailer(dest, info, ctrl, offset);
break;
- case REPEAT_ALWAYS:
- /* nothing to do - no state */
- break;
+ case REPEAT_ALWAYS:
+ /* nothing to do - no state */
+ break;
}
}
@@ -1095,13 +1095,13 @@ static
void repeatUnpackOffset(const char *src, const struct RepeatInfo *info,
u64a offset, union RepeatControl *ctrl) {
struct RepeatOffsetControl *xs = &ctrl->offset;
- if (!info->packedCtrlSize) {
- assert(info->type == REPEAT_ALWAYS);
- DEBUG_PRINTF("externally guarded .*\n");
- xs->offset = 0;
- } else {
- xs->offset = loadPackedRelative(src, offset, info->packedCtrlSize);
- }
+ if (!info->packedCtrlSize) {
+ assert(info->type == REPEAT_ALWAYS);
+ DEBUG_PRINTF("externally guarded .*\n");
+ xs->offset = 0;
+ } else {
+ xs->offset = loadPackedRelative(src, offset, info->packedCtrlSize);
+ }
DEBUG_PRINTF("unpacking offset %llu [h%u]\n", xs->offset,
info->horizon);
}
@@ -1178,9 +1178,9 @@ void repeatUnpack(const char *src, const struct RepeatInfo *info, u64a offset,
case REPEAT_TRAILER:
repeatUnpackTrailer(src, info, offset, ctrl);
break;
- case REPEAT_ALWAYS:
- /* nothing to do - no state */
- break;
+ case REPEAT_ALWAYS:
+ /* nothing to do - no state */
+ break;
}
}
@@ -1455,7 +1455,7 @@ void repeatStoreSparseOptimalP(const struct RepeatInfo *info,
DEBUG_PRINTF("xs->first:%u xs->last:%u patch:%u\n",
xs->first, xs->last, patch);
DEBUG_PRINTF("value:%llu\n", val);
- assert(fits_in_len_bytes(val, encoding_size));
+ assert(fits_in_len_bytes(val, encoding_size));
partial_store_u64a(ring + encoding_size * idx, val, encoding_size);
mmbit_set(active, patch_count, idx);
}
diff --git a/contrib/libs/hyperscan/src/nfa/repeat.h b/contrib/libs/hyperscan/src/nfa/repeat.h
index ae735401332..d4f84ea0a97 100644
--- a/contrib/libs/hyperscan/src/nfa/repeat.h
+++ b/contrib/libs/hyperscan/src/nfa/repeat.h
@@ -135,8 +135,8 @@ u64a repeatLastTop(const struct RepeatInfo *info,
return repeatLastTopSparseOptimalP(info, ctrl, state);
case REPEAT_TRAILER:
return repeatLastTopTrailer(info, ctrl);
- case REPEAT_ALWAYS:
- return 0;
+ case REPEAT_ALWAYS:
+ return 0;
}
DEBUG_PRINTF("bad repeat type %u\n", info->type);
@@ -202,8 +202,8 @@ u64a repeatNextMatch(const struct RepeatInfo *info,
return repeatNextMatchSparseOptimalP(info, ctrl, state, offset);
case REPEAT_TRAILER:
return repeatNextMatchTrailer(info, ctrl, offset);
- case REPEAT_ALWAYS:
- return offset + 1;
+ case REPEAT_ALWAYS:
+ return offset + 1;
}
DEBUG_PRINTF("bad repeat type %u\n", info->type);
@@ -279,9 +279,9 @@ void repeatStore(const struct RepeatInfo *info, union RepeatControl *ctrl,
case REPEAT_TRAILER:
repeatStoreTrailer(info, ctrl, offset, is_alive);
break;
- case REPEAT_ALWAYS:
- /* nothing to do - no state */
- break;
+ case REPEAT_ALWAYS:
+ /* nothing to do - no state */
+ break;
}
}
@@ -355,8 +355,8 @@ enum RepeatMatch repeatHasMatch(const struct RepeatInfo *info,
return repeatHasMatchSparseOptimalP(info, ctrl, state, offset);
case REPEAT_TRAILER:
return repeatHasMatchTrailer(info, ctrl, offset);
- case REPEAT_ALWAYS:
- return REPEAT_MATCH;
+ case REPEAT_ALWAYS:
+ return REPEAT_MATCH;
}
assert(0);
diff --git a/contrib/libs/hyperscan/src/nfa/repeat_internal.h b/contrib/libs/hyperscan/src/nfa/repeat_internal.h
index 1c99e7919ad..9e3f455c80d 100644
--- a/contrib/libs/hyperscan/src/nfa/repeat_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/repeat_internal.h
@@ -47,26 +47,26 @@ enum RepeatType {
/** General mechanism for tracking {N,M} repeats. Stores the first top as
* an absolute offset, then subsequent tops in the {N,M} range as a ring of
* relative top indices stored in a multibit. */
- REPEAT_RING,
+ REPEAT_RING,
/** Used to track {N,} repeats. Uses the \ref RepeatOffsetControl structure,
* since only the first top encountered needs to be stored. */
- REPEAT_FIRST,
+ REPEAT_FIRST,
/** Used to track {0,N} repeats. Much like ::REPEAT_FIRST, except that we
* store the most recent top encountered. */
- REPEAT_LAST,
+ REPEAT_LAST,
/** Like ::REPEAT_RING, this is also used for {N,M} repeats, but for cases
* where there is a large difference between N and M, and developed to
* reduce the state requirements of this case (relative to the RING model).
* Uses a small ordered array of top indices relative to \ref
* RepeatRangeControl::offset. */
- REPEAT_RANGE,
+ REPEAT_RANGE,
/** Used for {N,M} repeats where 0 < M <= 64. Uses the \ref
* RepeatBitmapControl structure at runtime. */
- REPEAT_BITMAP,
+ REPEAT_BITMAP,
/** Optimal mechanism for tracking {N,M} repeats when there is a bound on
* how frequently they can be retriggered.
@@ -78,17 +78,17 @@ enum RepeatType {
* referencing a table that stores values from f(0, min) to f(repeat, min)
* eg: repeat = 5, min = 2. 10001 => f(4,2) + f(0,2) = 9.
* We search the optimal patch size between min and repeat in advance and
- * use the scheme above to do encoding and decoding to reduce stream state
- * size. */
- REPEAT_SPARSE_OPTIMAL_P,
-
- /** Used for {N,M} repeats where 0 < N < 64. Uses the
- * \ref RepeatTrailerControl structure at runtime. */
- REPEAT_TRAILER,
-
- /** Degenerate repeat that always returns true. Used by castle for pseudo
- * [^X]* repeats. */
- REPEAT_ALWAYS,
+ * use the scheme above to do encoding and decoding to reduce stream state
+ * size. */
+ REPEAT_SPARSE_OPTIMAL_P,
+
+ /** Used for {N,M} repeats where 0 < N < 64. Uses the
+ * \ref RepeatTrailerControl structure at runtime. */
+ REPEAT_TRAILER,
+
+ /** Degenerate repeat that always returns true. Used by castle for pseudo
+ * [^X]* repeats. */
+ REPEAT_ALWAYS,
};
/**
@@ -208,8 +208,8 @@ const char *repeatTypeName(u8 type) {
return "SPARSE_OPTIMAL_P";
case REPEAT_TRAILER:
return "TRAILER";
- case REPEAT_ALWAYS:
- return "ALWAYS";
+ case REPEAT_ALWAYS:
+ return "ALWAYS";
}
assert(0);
return "UNKNOWN";
diff --git a/contrib/libs/hyperscan/src/nfa/repeatcompile.cpp b/contrib/libs/hyperscan/src/nfa/repeatcompile.cpp
index c33851ff9ff..934dd29e6b9 100644
--- a/contrib/libs/hyperscan/src/nfa/repeatcompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/repeatcompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@
#include "util/charreach.h"
#include "util/depth.h"
#include "util/dump_charclass.h"
-#include "util/multibit_build.h"
+#include "util/multibit_build.h"
#include "util/verify_types.h"
#include <algorithm>
@@ -206,13 +206,13 @@ RepeatStateInfo::RepeatStateInfo(enum RepeatType type, const depth &repeatMin,
packedFieldSizes[1] = repeatMin;
packedCtrlSize = (packedFieldSizes[0] + packedFieldSizes[1] + 7U) / 8U;
break;
- case REPEAT_ALWAYS:
- assert(repeatMin == 0ULL);
- assert(repeatMax.is_infinite());
- stateSize = 0; // everything is in the control block.
- horizon = 0;
- packedCtrlSize = 0;
- break;
+ case REPEAT_ALWAYS:
+ assert(repeatMin == 0ULL);
+ assert(repeatMax.is_infinite());
+ stateSize = 0; // everything is in the control block.
+ horizon = 0;
+ packedCtrlSize = 0;
+ break;
}
DEBUG_PRINTF("stateSize=%u, packedCtrlSize=%u, horizon=%u\n", stateSize,
packedCtrlSize, horizon);
@@ -239,14 +239,14 @@ u32 streamStateSize(enum RepeatType type, const depth &repeatMin,
}
enum RepeatType chooseRepeatType(const depth &repeatMin, const depth &repeatMax,
- u32 minPeriod, bool is_reset,
- bool has_external_guard) {
+ u32 minPeriod, bool is_reset,
+ bool has_external_guard) {
if (repeatMax.is_infinite()) {
- if (has_external_guard && !repeatMin) {
- return REPEAT_ALWAYS;
- } else {
- return REPEAT_FIRST;
- }
+ if (has_external_guard && !repeatMin) {
+ return REPEAT_ALWAYS;
+ } else {
+ return REPEAT_FIRST;
+ }
}
if (repeatMin == depth(0) || is_reset) {
diff --git a/contrib/libs/hyperscan/src/nfa/repeatcompile.h b/contrib/libs/hyperscan/src/nfa/repeatcompile.h
index 84c28be5686..fe9a7106236 100644
--- a/contrib/libs/hyperscan/src/nfa/repeatcompile.h
+++ b/contrib/libs/hyperscan/src/nfa/repeatcompile.h
@@ -68,8 +68,8 @@ struct RepeatStateInfo {
* type.
*/
enum RepeatType chooseRepeatType(const depth &repeatMin, const depth &repeatMax,
- u32 minPeriod, bool is_reset,
- bool has_external_guard = false);
+ u32 minPeriod, bool is_reset,
+ bool has_external_guard = false);
u32 calcPackedBytes(u64a val);
diff --git a/contrib/libs/hyperscan/src/nfa/sheng.c b/contrib/libs/hyperscan/src/nfa/sheng.c
index d4fb1250f23..3f36e218917 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng.c
+++ b/contrib/libs/hyperscan/src/nfa/sheng.c
@@ -1,159 +1,159 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "sheng.h"
-
-#include "accel.h"
-#include "sheng_internal.h"
-#include "nfa_api.h"
-#include "nfa_api_queue.h"
-#include "nfa_internal.h"
-#include "util/bitutils.h"
-#include "util/compare.h"
-#include "util/join.h"
-#include "util/simd_utils.h"
-
-enum MatchMode {
- CALLBACK_OUTPUT,
- STOP_AT_MATCH,
- NO_MATCHES
-};
-
-static really_inline
-const struct sheng *get_sheng(const struct NFA *n) {
- return (const struct sheng *)getImplNfa(n);
-}
-
-static really_inline
-const struct sstate_aux *get_aux(const struct sheng *sh, u8 id) {
- u32 offset = sh->aux_offset - sizeof(struct NFA) +
- (id & SHENG_STATE_MASK) * sizeof(struct sstate_aux);
- DEBUG_PRINTF("Getting aux for state %u at offset %llu\n",
- id & SHENG_STATE_MASK, (u64a)offset + sizeof(struct NFA));
- return (const struct sstate_aux *)((const char *) sh + offset);
-}
-
-static really_inline
-const union AccelAux *get_accel(const struct sheng *sh, u8 id) {
- const struct sstate_aux *saux = get_aux(sh, id);
- DEBUG_PRINTF("Getting accel aux at offset %u\n", saux->accel);
- const union AccelAux *aux = (const union AccelAux *)
- ((const char *)sh + saux->accel - sizeof(struct NFA));
- return aux;
-}
-
-static really_inline
-const struct report_list *get_rl(const struct sheng *sh,
- const struct sstate_aux *aux) {
- DEBUG_PRINTF("Getting report list at offset %u\n", aux->accept);
- return (const struct report_list *)
- ((const char *)sh + aux->accept - sizeof(struct NFA));
-}
-
-static really_inline
-const struct report_list *get_eod_rl(const struct sheng *sh,
- const struct sstate_aux *aux) {
- DEBUG_PRINTF("Getting EOD report list at offset %u\n", aux->accept);
- return (const struct report_list *)
- ((const char *)sh + aux->accept_eod - sizeof(struct NFA));
-}
-
-static really_inline
-char shengHasAccept(const struct sheng *sh, const struct sstate_aux *aux,
- ReportID report) {
- assert(sh && aux);
-
- const struct report_list *rl = get_rl(sh, aux);
- assert(ISALIGNED_N(rl, 4));
-
- DEBUG_PRINTF("report list has %u entries\n", rl->count);
-
- for (u32 i = 0; i < rl->count; i++) {
- if (rl->report[i] == report) {
- DEBUG_PRINTF("reporting %u\n", rl->report[i]);
- return 1;
- }
- }
-
- return 0;
-}
-
-static really_inline
-char fireSingleReport(NfaCallback cb, void *ctxt, ReportID r, u64a loc) {
- DEBUG_PRINTF("reporting %u\n", r);
- if (cb(0, loc, r, ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
- return MO_CONTINUE_MATCHING; /* continue execution */
-}
-
-static really_inline
-char fireReports(const struct sheng *sh, NfaCallback cb, void *ctxt,
- const u8 state, u64a loc, u8 *const cached_accept_state,
- ReportID *const cached_accept_id, char eod) {
- DEBUG_PRINTF("reporting matches @ %llu\n", loc);
-
- if (!eod && state == *cached_accept_state) {
- DEBUG_PRINTF("reporting %u\n", *cached_accept_id);
- if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
-
- return MO_CONTINUE_MATCHING; /* continue execution */
- }
- const struct sstate_aux *aux = get_aux(sh, state);
- const struct report_list *rl = eod ? get_eod_rl(sh, aux) : get_rl(sh, aux);
- assert(ISALIGNED(rl));
-
- DEBUG_PRINTF("report list has %u entries\n", rl->count);
- u32 count = rl->count;
-
- if (!eod && count == 1) {
- *cached_accept_state = state;
- *cached_accept_id = rl->report[0];
-
- DEBUG_PRINTF("reporting %u\n", rl->report[0]);
- if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
-
- return MO_CONTINUE_MATCHING; /* continue execution */
- }
-
- for (u32 i = 0; i < count; i++) {
- DEBUG_PRINTF("reporting %u\n", rl->report[i]);
- if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING; /* termination requested */
- }
- }
- return MO_CONTINUE_MATCHING; /* continue execution */
-}
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "sheng.h"
+
+#include "accel.h"
+#include "sheng_internal.h"
+#include "nfa_api.h"
+#include "nfa_api_queue.h"
+#include "nfa_internal.h"
+#include "util/bitutils.h"
+#include "util/compare.h"
+#include "util/join.h"
+#include "util/simd_utils.h"
+
+enum MatchMode {
+ CALLBACK_OUTPUT,
+ STOP_AT_MATCH,
+ NO_MATCHES
+};
+
+static really_inline
+const struct sheng *get_sheng(const struct NFA *n) {
+ return (const struct sheng *)getImplNfa(n);
+}
+
+static really_inline
+const struct sstate_aux *get_aux(const struct sheng *sh, u8 id) {
+ u32 offset = sh->aux_offset - sizeof(struct NFA) +
+ (id & SHENG_STATE_MASK) * sizeof(struct sstate_aux);
+ DEBUG_PRINTF("Getting aux for state %u at offset %llu\n",
+ id & SHENG_STATE_MASK, (u64a)offset + sizeof(struct NFA));
+ return (const struct sstate_aux *)((const char *) sh + offset);
+}
+
+static really_inline
+const union AccelAux *get_accel(const struct sheng *sh, u8 id) {
+ const struct sstate_aux *saux = get_aux(sh, id);
+ DEBUG_PRINTF("Getting accel aux at offset %u\n", saux->accel);
+ const union AccelAux *aux = (const union AccelAux *)
+ ((const char *)sh + saux->accel - sizeof(struct NFA));
+ return aux;
+}
+
+static really_inline
+const struct report_list *get_rl(const struct sheng *sh,
+ const struct sstate_aux *aux) {
+ DEBUG_PRINTF("Getting report list at offset %u\n", aux->accept);
+ return (const struct report_list *)
+ ((const char *)sh + aux->accept - sizeof(struct NFA));
+}
+
+static really_inline
+const struct report_list *get_eod_rl(const struct sheng *sh,
+ const struct sstate_aux *aux) {
+ DEBUG_PRINTF("Getting EOD report list at offset %u\n", aux->accept);
+ return (const struct report_list *)
+ ((const char *)sh + aux->accept_eod - sizeof(struct NFA));
+}
+
+static really_inline
+char shengHasAccept(const struct sheng *sh, const struct sstate_aux *aux,
+ ReportID report) {
+ assert(sh && aux);
+
+ const struct report_list *rl = get_rl(sh, aux);
+ assert(ISALIGNED_N(rl, 4));
+
+ DEBUG_PRINTF("report list has %u entries\n", rl->count);
+
+ for (u32 i = 0; i < rl->count; i++) {
+ if (rl->report[i] == report) {
+ DEBUG_PRINTF("reporting %u\n", rl->report[i]);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static really_inline
+char fireSingleReport(NfaCallback cb, void *ctxt, ReportID r, u64a loc) {
+ DEBUG_PRINTF("reporting %u\n", r);
+ if (cb(0, loc, r, ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+ return MO_CONTINUE_MATCHING; /* continue execution */
+}
+
+static really_inline
+char fireReports(const struct sheng *sh, NfaCallback cb, void *ctxt,
+ const u8 state, u64a loc, u8 *const cached_accept_state,
+ ReportID *const cached_accept_id, char eod) {
+ DEBUG_PRINTF("reporting matches @ %llu\n", loc);
+
+ if (!eod && state == *cached_accept_state) {
+ DEBUG_PRINTF("reporting %u\n", *cached_accept_id);
+ if (cb(0, loc, *cached_accept_id, ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+
+ return MO_CONTINUE_MATCHING; /* continue execution */
+ }
+ const struct sstate_aux *aux = get_aux(sh, state);
+ const struct report_list *rl = eod ? get_eod_rl(sh, aux) : get_rl(sh, aux);
+ assert(ISALIGNED(rl));
+
+ DEBUG_PRINTF("report list has %u entries\n", rl->count);
+ u32 count = rl->count;
+
+ if (!eod && count == 1) {
+ *cached_accept_state = state;
+ *cached_accept_id = rl->report[0];
+
+ DEBUG_PRINTF("reporting %u\n", rl->report[0]);
+ if (cb(0, loc, rl->report[0], ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+
+ return MO_CONTINUE_MATCHING; /* continue execution */
+ }
+
+ for (u32 i = 0; i < count; i++) {
+ DEBUG_PRINTF("reporting %u\n", rl->report[i]);
+ if (cb(0, loc, rl->report[i], ctxt) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING; /* termination requested */
+ }
+ }
+ return MO_CONTINUE_MATCHING; /* continue execution */
+}
+
#if defined(HAVE_AVX512VBMI)
// Sheng32
static really_inline
@@ -353,523 +353,523 @@ char fireReports64(const struct sheng64 *sh, NfaCallback cb, void *ctxt,
}
#endif // end of HAVE_AVX512VBMI
-/* include Sheng function definitions */
-#include "sheng_defs.h"
-
-static really_inline
-char runShengCb(const struct sheng *sh, NfaCallback cb, void *ctxt, u64a offset,
- u8 *const cached_accept_state, ReportID *const cached_accept_id,
- const u8 *cur_buf, const u8 *start, const u8 *end, u8 can_die,
- u8 has_accel, u8 single, const u8 **scanned, u8 *state) {
- DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in callback mode\n",
- (u64a)(end - start), offset);
- DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
- (s64a)(end - cur_buf));
- DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
- !!has_accel, !!single);
- int rv;
- /* scan and report all matches */
- if (can_die) {
- if (has_accel) {
- rv = sheng4_coda(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- } else {
- rv = sheng4_cod(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- rv = sheng_cod(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, *scanned, end,
- scanned);
- } else {
- if (has_accel) {
- rv = sheng4_coa(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- } else {
- rv = sheng4_co(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- rv = sheng_co(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, *scanned, end,
- scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- return MO_ALIVE;
-}
-
-static really_inline
-void runShengNm(const struct sheng *sh, NfaCallback cb, void *ctxt, u64a offset,
- u8 *const cached_accept_state, ReportID *const cached_accept_id,
- const u8 *cur_buf, const u8 *start, const u8 *end, u8 can_die,
- u8 has_accel, u8 single, const u8 **scanned, u8 *state) {
- DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in nomatch mode\n",
- (u64a)(end - start), offset);
- DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
- (s64a)(end - cur_buf));
- DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
- !!has_accel, !!single);
- /* just scan the buffer */
- if (can_die) {
- if (has_accel) {
- sheng4_nmda(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start, end,
- scanned);
- } else {
- sheng4_nmd(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start, end,
- scanned);
- }
- sheng_nmd(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
- single, offset, cur_buf, *scanned, end, scanned);
- } else {
- sheng4_nm(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
- single, offset, cur_buf, start, end, scanned);
- sheng_nm(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
- single, offset, cur_buf, *scanned, end, scanned);
- }
-}
-
-static really_inline
-char runShengSam(const struct sheng *sh, NfaCallback cb, void *ctxt,
- u64a offset, u8 *const cached_accept_state,
- ReportID *const cached_accept_id, const u8 *cur_buf,
- const u8 *start, const u8 *end, u8 can_die, u8 has_accel,
- u8 single, const u8 **scanned, u8 *state) {
- DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in stop at match mode\n",
- (u64a)(end - start), offset);
- DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
- (s64a)(end - cur_buf));
- DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
- !!has_accel, !!single);
- int rv;
- /* scan until first match */
- if (can_die) {
- if (has_accel) {
- rv = sheng4_samda(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- } else {
- rv = sheng4_samd(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- /* if we stopped before we expected, we found a match */
- if (rv == MO_MATCHES_PENDING) {
- return MO_MATCHES_PENDING;
- }
-
- rv = sheng_samd(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, *scanned,
- end, scanned);
- } else {
- if (has_accel) {
- rv = sheng4_sama(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- } else {
- rv = sheng4_sam(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, start,
- end, scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- /* if we stopped before we expected, we found a match */
- if (rv == MO_MATCHES_PENDING) {
- return MO_MATCHES_PENDING;
- }
-
- rv = sheng_sam(state, cb, ctxt, sh, cached_accept_state,
- cached_accept_id, single, offset, cur_buf, *scanned, end,
- scanned);
- }
- if (rv == MO_HALT_MATCHING) {
- return MO_DEAD;
- }
- /* if we stopped before we expected, we found a match */
- if (rv == MO_MATCHES_PENDING) {
- return MO_MATCHES_PENDING;
- }
- return MO_ALIVE;
-}
-
-static never_inline
-char runSheng(const struct sheng *sh, struct mq *q, s64a b_end,
- enum MatchMode mode) {
- u8 state = *(u8 *)q->state;
- u8 can_die = sh->flags & SHENG_FLAG_CAN_DIE;
- u8 has_accel = sh->flags & SHENG_FLAG_HAS_ACCEL;
- u8 single = sh->flags & SHENG_FLAG_SINGLE_REPORT;
-
- u8 cached_accept_state = 0;
- ReportID cached_accept_id = 0;
-
- DEBUG_PRINTF("starting Sheng execution in state %u\n",
- state & SHENG_STATE_MASK);
-
- if (q->report_current) {
- DEBUG_PRINTF("reporting current pending matches\n");
- assert(sh);
-
- q->report_current = 0;
-
- int rv;
- if (single) {
- rv = fireSingleReport(q->cb, q->context, sh->report,
- q_cur_offset(q));
- } else {
- rv = fireReports(sh, q->cb, q->context, state, q_cur_offset(q),
- &cached_accept_state, &cached_accept_id, 0);
- }
- if (rv == MO_HALT_MATCHING) {
- DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
- return MO_DEAD;
- }
-
- DEBUG_PRINTF("proceeding with matching\n");
- }
-
- assert(q_cur_type(q) == MQE_START);
- s64a start = q_cur_loc(q);
-
- DEBUG_PRINTF("offset: %lli, location: %lli, mode: %s\n", q->offset, start,
- mode == CALLBACK_OUTPUT ? "CALLBACK OUTPUT" :
- mode == NO_MATCHES ? "NO MATCHES" :
- mode == STOP_AT_MATCH ? "STOP AT MATCH" : "???");
-
- DEBUG_PRINTF("processing event @ %lli: %s\n", q->offset + q_cur_loc(q),
- q_cur_type(q) == MQE_START ? "START" :
- q_cur_type(q) == MQE_TOP ? "TOP" :
- q_cur_type(q) == MQE_END ? "END" : "???");
-
- const u8* cur_buf;
- if (start < 0) {
- DEBUG_PRINTF("negative location, scanning history\n");
- DEBUG_PRINTF("min location: %zd\n", -q->hlength);
- cur_buf = q->history + q->hlength;
- } else {
- DEBUG_PRINTF("positive location, scanning buffer\n");
- DEBUG_PRINTF("max location: %lli\n", b_end);
- cur_buf = q->buffer;
- }
-
- /* if we our queue event is past our end */
- if (mode != NO_MATCHES && q_cur_loc(q) > b_end) {
- DEBUG_PRINTF("current location past buffer end\n");
- DEBUG_PRINTF("setting q location to %llu\n", b_end);
- DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
- q->items[q->cur].location = b_end;
- return MO_ALIVE;
- }
-
- q->cur++;
-
- s64a cur_start = start;
-
- while (1) {
- DEBUG_PRINTF("processing event @ %lli: %s\n", q->offset + q_cur_loc(q),
- q_cur_type(q) == MQE_START ? "START" :
- q_cur_type(q) == MQE_TOP ? "TOP" :
- q_cur_type(q) == MQE_END ? "END" : "???");
- s64a end = q_cur_loc(q);
- if (mode != NO_MATCHES) {
- end = MIN(end, b_end);
- }
- assert(end <= (s64a) q->length);
- s64a cur_end = end;
-
- /* we may cross the border between history and current buffer */
- if (cur_start < 0) {
- cur_end = MIN(0, cur_end);
- }
-
- DEBUG_PRINTF("start: %lli end: %lli\n", start, end);
-
- /* don't scan zero length buffer */
- if (cur_start != cur_end) {
- const u8 * scanned = cur_buf;
- char rv;
-
- if (mode == NO_MATCHES) {
- runShengNm(sh, q->cb, q->context, q->offset,
- &cached_accept_state, &cached_accept_id, cur_buf,
- cur_buf + cur_start, cur_buf + cur_end, can_die,
- has_accel, single, &scanned, &state);
- } else if (mode == CALLBACK_OUTPUT) {
- rv = runShengCb(sh, q->cb, q->context, q->offset,
- &cached_accept_state, &cached_accept_id,
- cur_buf, cur_buf + cur_start, cur_buf + cur_end,
- can_die, has_accel, single, &scanned, &state);
- if (rv == MO_DEAD) {
- DEBUG_PRINTF("exiting in state %u\n",
- state & SHENG_STATE_MASK);
- return MO_DEAD;
- }
- } else if (mode == STOP_AT_MATCH) {
- rv = runShengSam(sh, q->cb, q->context, q->offset,
- &cached_accept_state, &cached_accept_id,
- cur_buf, cur_buf + cur_start,
- cur_buf + cur_end, can_die, has_accel, single,
- &scanned, &state);
- if (rv == MO_DEAD) {
- DEBUG_PRINTF("exiting in state %u\n",
- state & SHENG_STATE_MASK);
- return rv;
- } else if (rv == MO_MATCHES_PENDING) {
- assert(q->cur);
- DEBUG_PRINTF("found a match, setting q location to %zd\n",
- scanned - cur_buf + 1);
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location =
- scanned - cur_buf + 1; /* due to exiting early */
- *(u8 *)q->state = state;
- DEBUG_PRINTF("exiting in state %u\n",
- state & SHENG_STATE_MASK);
- return rv;
- }
- } else {
- assert(!"invalid scanning mode!");
- }
- assert(scanned == cur_buf + cur_end);
-
- cur_start = cur_end;
- }
-
- /* if we our queue event is past our end */
- if (mode != NO_MATCHES && q_cur_loc(q) > b_end) {
- DEBUG_PRINTF("current location past buffer end\n");
- DEBUG_PRINTF("setting q location to %llu\n", b_end);
- DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
- q->cur--;
- q->items[q->cur].type = MQE_START;
- q->items[q->cur].location = b_end;
- *(u8 *)q->state = state;
- return MO_ALIVE;
- }
-
- /* crossing over into actual buffer */
- if (cur_start == 0) {
- DEBUG_PRINTF("positive location, scanning buffer\n");
- DEBUG_PRINTF("max offset: %lli\n", b_end);
- cur_buf = q->buffer;
- }
-
- /* continue scanning the same buffer */
- if (end != cur_end) {
- continue;
- }
-
- switch (q_cur_type(q)) {
- case MQE_END:
- *(u8 *)q->state = state;
- q->cur++;
- DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
- if (can_die) {
- return (state & SHENG_STATE_DEAD) ? MO_DEAD : MO_ALIVE;
- }
- return MO_ALIVE;
- case MQE_TOP:
- if (q->offset + cur_start == 0) {
- DEBUG_PRINTF("Anchored start, going to state %u\n",
- sh->anchored);
- state = sh->anchored;
- } else {
- u8 new_state = get_aux(sh, state)->top;
- DEBUG_PRINTF("Top event %u->%u\n", state & SHENG_STATE_MASK,
- new_state & SHENG_STATE_MASK);
- state = new_state;
- }
- break;
- default:
- assert(!"invalid queue event");
- break;
- }
- q->cur++;
- }
-}
-
-char nfaExecSheng_B(const struct NFA *n, u64a offset, const u8 *buffer,
- size_t length, NfaCallback cb, void *context) {
- DEBUG_PRINTF("smallwrite Sheng\n");
- assert(n->type == SHENG_NFA);
- const struct sheng *sh = getImplNfa(n);
- u8 state = sh->anchored;
- u8 can_die = sh->flags & SHENG_FLAG_CAN_DIE;
- u8 has_accel = sh->flags & SHENG_FLAG_HAS_ACCEL;
- u8 single = sh->flags & SHENG_FLAG_SINGLE_REPORT;
- u8 cached_accept_state = 0;
- ReportID cached_accept_id = 0;
-
- /* scan and report all matches */
- int rv;
- s64a end = length;
- const u8 *scanned;
-
- rv = runShengCb(sh, cb, context, offset, &cached_accept_state,
- &cached_accept_id, buffer, buffer, buffer + end, can_die,
- has_accel, single, &scanned, &state);
- if (rv == MO_DEAD) {
- DEBUG_PRINTF("exiting in state %u\n",
- state & SHENG_STATE_MASK);
- return MO_DEAD;
- }
-
- DEBUG_PRINTF("%u\n", state & SHENG_STATE_MASK);
-
- const struct sstate_aux *aux = get_aux(sh, state);
-
- if (aux->accept_eod) {
- DEBUG_PRINTF("Reporting EOD matches\n");
- fireReports(sh, cb, context, state, end + offset, &cached_accept_state,
- &cached_accept_id, 1);
- }
-
- return state & SHENG_STATE_DEAD ? MO_DEAD : MO_ALIVE;
-}
-
-char nfaExecSheng_Q(const struct NFA *n, struct mq *q, s64a end) {
- const struct sheng *sh = get_sheng(n);
- char rv = runSheng(sh, q, end, CALLBACK_OUTPUT);
- return rv;
-}
-
-char nfaExecSheng_Q2(const struct NFA *n, struct mq *q, s64a end) {
- const struct sheng *sh = get_sheng(n);
- char rv = runSheng(sh, q, end, STOP_AT_MATCH);
- return rv;
-}
-
-char nfaExecSheng_QR(const struct NFA *n, struct mq *q, ReportID report) {
- assert(q_cur_type(q) == MQE_START);
-
- const struct sheng *sh = get_sheng(n);
- char rv = runSheng(sh, q, 0 /* end */, NO_MATCHES);
-
- if (rv && nfaExecSheng_inAccept(n, report, q)) {
- return MO_MATCHES_PENDING;
- }
- return rv;
-}
-
-char nfaExecSheng_inAccept(const struct NFA *n, ReportID report, struct mq *q) {
- assert(n && q);
-
- const struct sheng *sh = get_sheng(n);
- u8 s = *(const u8 *)q->state;
- DEBUG_PRINTF("checking accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
-
- const struct sstate_aux *aux = get_aux(sh, s);
-
- if (!aux->accept) {
- return 0;
- }
-
- return shengHasAccept(sh, aux, report);
-}
-
-char nfaExecSheng_inAnyAccept(const struct NFA *n, struct mq *q) {
- assert(n && q);
-
- const struct sheng *sh = get_sheng(n);
- u8 s = *(const u8 *)q->state;
- DEBUG_PRINTF("checking accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
-
- const struct sstate_aux *aux = get_aux(sh, s);
- return !!aux->accept;
-}
-
-char nfaExecSheng_testEOD(const struct NFA *nfa, const char *state,
- UNUSED const char *streamState, u64a offset,
- NfaCallback cb, void *ctxt) {
- assert(nfa);
-
- const struct sheng *sh = get_sheng(nfa);
- u8 s = *(const u8 *)state;
- DEBUG_PRINTF("checking EOD accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
-
- const struct sstate_aux *aux = get_aux(sh, s);
-
- if (!aux->accept_eod) {
- return MO_CONTINUE_MATCHING;
- }
-
- return fireReports(sh, cb, ctxt, s, offset, NULL, NULL, 1);
-}
-
-char nfaExecSheng_reportCurrent(const struct NFA *n, struct mq *q) {
- const struct sheng *sh = (const struct sheng *)getImplNfa(n);
- NfaCallback cb = q->cb;
- void *ctxt = q->context;
- u8 s = *(u8 *)q->state;
- const struct sstate_aux *aux = get_aux(sh, s);
- u64a offset = q_cur_offset(q);
- u8 cached_state_id = 0;
- ReportID cached_report_id = 0;
- assert(q_cur_type(q) == MQE_START);
-
- if (aux->accept) {
- if (sh->flags & SHENG_FLAG_SINGLE_REPORT) {
- fireSingleReport(cb, ctxt, sh->report, offset);
- } else {
- fireReports(sh, cb, ctxt, s, offset, &cached_state_id,
+/* include Sheng function definitions */
+#include "sheng_defs.h"
+
+static really_inline
+char runShengCb(const struct sheng *sh, NfaCallback cb, void *ctxt, u64a offset,
+ u8 *const cached_accept_state, ReportID *const cached_accept_id,
+ const u8 *cur_buf, const u8 *start, const u8 *end, u8 can_die,
+ u8 has_accel, u8 single, const u8 **scanned, u8 *state) {
+ DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in callback mode\n",
+ (u64a)(end - start), offset);
+ DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
+ (s64a)(end - cur_buf));
+ DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
+ !!has_accel, !!single);
+ int rv;
+ /* scan and report all matches */
+ if (can_die) {
+ if (has_accel) {
+ rv = sheng4_coda(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ } else {
+ rv = sheng4_cod(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ rv = sheng_cod(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, *scanned, end,
+ scanned);
+ } else {
+ if (has_accel) {
+ rv = sheng4_coa(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ } else {
+ rv = sheng4_co(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ rv = sheng_co(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, *scanned, end,
+ scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ return MO_ALIVE;
+}
+
+static really_inline
+void runShengNm(const struct sheng *sh, NfaCallback cb, void *ctxt, u64a offset,
+ u8 *const cached_accept_state, ReportID *const cached_accept_id,
+ const u8 *cur_buf, const u8 *start, const u8 *end, u8 can_die,
+ u8 has_accel, u8 single, const u8 **scanned, u8 *state) {
+ DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in nomatch mode\n",
+ (u64a)(end - start), offset);
+ DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
+ (s64a)(end - cur_buf));
+ DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
+ !!has_accel, !!single);
+ /* just scan the buffer */
+ if (can_die) {
+ if (has_accel) {
+ sheng4_nmda(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start, end,
+ scanned);
+ } else {
+ sheng4_nmd(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start, end,
+ scanned);
+ }
+ sheng_nmd(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
+ single, offset, cur_buf, *scanned, end, scanned);
+ } else {
+ sheng4_nm(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
+ single, offset, cur_buf, start, end, scanned);
+ sheng_nm(state, cb, ctxt, sh, cached_accept_state, cached_accept_id,
+ single, offset, cur_buf, *scanned, end, scanned);
+ }
+}
+
+static really_inline
+char runShengSam(const struct sheng *sh, NfaCallback cb, void *ctxt,
+ u64a offset, u8 *const cached_accept_state,
+ ReportID *const cached_accept_id, const u8 *cur_buf,
+ const u8 *start, const u8 *end, u8 can_die, u8 has_accel,
+ u8 single, const u8 **scanned, u8 *state) {
+ DEBUG_PRINTF("Scanning %llu bytes (offset %llu) in stop at match mode\n",
+ (u64a)(end - start), offset);
+ DEBUG_PRINTF("start: %lli end: %lli\n", (s64a)(start - cur_buf),
+ (s64a)(end - cur_buf));
+ DEBUG_PRINTF("can die: %u has accel: %u single: %u\n", !!can_die,
+ !!has_accel, !!single);
+ int rv;
+ /* scan until first match */
+ if (can_die) {
+ if (has_accel) {
+ rv = sheng4_samda(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ } else {
+ rv = sheng4_samd(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ /* if we stopped before we expected, we found a match */
+ if (rv == MO_MATCHES_PENDING) {
+ return MO_MATCHES_PENDING;
+ }
+
+ rv = sheng_samd(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, *scanned,
+ end, scanned);
+ } else {
+ if (has_accel) {
+ rv = sheng4_sama(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ } else {
+ rv = sheng4_sam(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, start,
+ end, scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ /* if we stopped before we expected, we found a match */
+ if (rv == MO_MATCHES_PENDING) {
+ return MO_MATCHES_PENDING;
+ }
+
+ rv = sheng_sam(state, cb, ctxt, sh, cached_accept_state,
+ cached_accept_id, single, offset, cur_buf, *scanned, end,
+ scanned);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ return MO_DEAD;
+ }
+ /* if we stopped before we expected, we found a match */
+ if (rv == MO_MATCHES_PENDING) {
+ return MO_MATCHES_PENDING;
+ }
+ return MO_ALIVE;
+}
+
+static never_inline
+char runSheng(const struct sheng *sh, struct mq *q, s64a b_end,
+ enum MatchMode mode) {
+ u8 state = *(u8 *)q->state;
+ u8 can_die = sh->flags & SHENG_FLAG_CAN_DIE;
+ u8 has_accel = sh->flags & SHENG_FLAG_HAS_ACCEL;
+ u8 single = sh->flags & SHENG_FLAG_SINGLE_REPORT;
+
+ u8 cached_accept_state = 0;
+ ReportID cached_accept_id = 0;
+
+ DEBUG_PRINTF("starting Sheng execution in state %u\n",
+ state & SHENG_STATE_MASK);
+
+ if (q->report_current) {
+ DEBUG_PRINTF("reporting current pending matches\n");
+ assert(sh);
+
+ q->report_current = 0;
+
+ int rv;
+ if (single) {
+ rv = fireSingleReport(q->cb, q->context, sh->report,
+ q_cur_offset(q));
+ } else {
+ rv = fireReports(sh, q->cb, q->context, state, q_cur_offset(q),
+ &cached_accept_state, &cached_accept_id, 0);
+ }
+ if (rv == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
+ return MO_DEAD;
+ }
+
+ DEBUG_PRINTF("proceeding with matching\n");
+ }
+
+ assert(q_cur_type(q) == MQE_START);
+ s64a start = q_cur_loc(q);
+
+ DEBUG_PRINTF("offset: %lli, location: %lli, mode: %s\n", q->offset, start,
+ mode == CALLBACK_OUTPUT ? "CALLBACK OUTPUT" :
+ mode == NO_MATCHES ? "NO MATCHES" :
+ mode == STOP_AT_MATCH ? "STOP AT MATCH" : "???");
+
+ DEBUG_PRINTF("processing event @ %lli: %s\n", q->offset + q_cur_loc(q),
+ q_cur_type(q) == MQE_START ? "START" :
+ q_cur_type(q) == MQE_TOP ? "TOP" :
+ q_cur_type(q) == MQE_END ? "END" : "???");
+
+ const u8* cur_buf;
+ if (start < 0) {
+ DEBUG_PRINTF("negative location, scanning history\n");
+ DEBUG_PRINTF("min location: %zd\n", -q->hlength);
+ cur_buf = q->history + q->hlength;
+ } else {
+ DEBUG_PRINTF("positive location, scanning buffer\n");
+ DEBUG_PRINTF("max location: %lli\n", b_end);
+ cur_buf = q->buffer;
+ }
+
+ /* if we our queue event is past our end */
+ if (mode != NO_MATCHES && q_cur_loc(q) > b_end) {
+ DEBUG_PRINTF("current location past buffer end\n");
+ DEBUG_PRINTF("setting q location to %llu\n", b_end);
+ DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
+ q->items[q->cur].location = b_end;
+ return MO_ALIVE;
+ }
+
+ q->cur++;
+
+ s64a cur_start = start;
+
+ while (1) {
+ DEBUG_PRINTF("processing event @ %lli: %s\n", q->offset + q_cur_loc(q),
+ q_cur_type(q) == MQE_START ? "START" :
+ q_cur_type(q) == MQE_TOP ? "TOP" :
+ q_cur_type(q) == MQE_END ? "END" : "???");
+ s64a end = q_cur_loc(q);
+ if (mode != NO_MATCHES) {
+ end = MIN(end, b_end);
+ }
+ assert(end <= (s64a) q->length);
+ s64a cur_end = end;
+
+ /* we may cross the border between history and current buffer */
+ if (cur_start < 0) {
+ cur_end = MIN(0, cur_end);
+ }
+
+ DEBUG_PRINTF("start: %lli end: %lli\n", start, end);
+
+ /* don't scan zero length buffer */
+ if (cur_start != cur_end) {
+ const u8 * scanned = cur_buf;
+ char rv;
+
+ if (mode == NO_MATCHES) {
+ runShengNm(sh, q->cb, q->context, q->offset,
+ &cached_accept_state, &cached_accept_id, cur_buf,
+ cur_buf + cur_start, cur_buf + cur_end, can_die,
+ has_accel, single, &scanned, &state);
+ } else if (mode == CALLBACK_OUTPUT) {
+ rv = runShengCb(sh, q->cb, q->context, q->offset,
+ &cached_accept_state, &cached_accept_id,
+ cur_buf, cur_buf + cur_start, cur_buf + cur_end,
+ can_die, has_accel, single, &scanned, &state);
+ if (rv == MO_DEAD) {
+ DEBUG_PRINTF("exiting in state %u\n",
+ state & SHENG_STATE_MASK);
+ return MO_DEAD;
+ }
+ } else if (mode == STOP_AT_MATCH) {
+ rv = runShengSam(sh, q->cb, q->context, q->offset,
+ &cached_accept_state, &cached_accept_id,
+ cur_buf, cur_buf + cur_start,
+ cur_buf + cur_end, can_die, has_accel, single,
+ &scanned, &state);
+ if (rv == MO_DEAD) {
+ DEBUG_PRINTF("exiting in state %u\n",
+ state & SHENG_STATE_MASK);
+ return rv;
+ } else if (rv == MO_MATCHES_PENDING) {
+ assert(q->cur);
+ DEBUG_PRINTF("found a match, setting q location to %zd\n",
+ scanned - cur_buf + 1);
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location =
+ scanned - cur_buf + 1; /* due to exiting early */
+ *(u8 *)q->state = state;
+ DEBUG_PRINTF("exiting in state %u\n",
+ state & SHENG_STATE_MASK);
+ return rv;
+ }
+ } else {
+ assert(!"invalid scanning mode!");
+ }
+ assert(scanned == cur_buf + cur_end);
+
+ cur_start = cur_end;
+ }
+
+ /* if we our queue event is past our end */
+ if (mode != NO_MATCHES && q_cur_loc(q) > b_end) {
+ DEBUG_PRINTF("current location past buffer end\n");
+ DEBUG_PRINTF("setting q location to %llu\n", b_end);
+ DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
+ q->cur--;
+ q->items[q->cur].type = MQE_START;
+ q->items[q->cur].location = b_end;
+ *(u8 *)q->state = state;
+ return MO_ALIVE;
+ }
+
+ /* crossing over into actual buffer */
+ if (cur_start == 0) {
+ DEBUG_PRINTF("positive location, scanning buffer\n");
+ DEBUG_PRINTF("max offset: %lli\n", b_end);
+ cur_buf = q->buffer;
+ }
+
+ /* continue scanning the same buffer */
+ if (end != cur_end) {
+ continue;
+ }
+
+ switch (q_cur_type(q)) {
+ case MQE_END:
+ *(u8 *)q->state = state;
+ q->cur++;
+ DEBUG_PRINTF("exiting in state %u\n", state & SHENG_STATE_MASK);
+ if (can_die) {
+ return (state & SHENG_STATE_DEAD) ? MO_DEAD : MO_ALIVE;
+ }
+ return MO_ALIVE;
+ case MQE_TOP:
+ if (q->offset + cur_start == 0) {
+ DEBUG_PRINTF("Anchored start, going to state %u\n",
+ sh->anchored);
+ state = sh->anchored;
+ } else {
+ u8 new_state = get_aux(sh, state)->top;
+ DEBUG_PRINTF("Top event %u->%u\n", state & SHENG_STATE_MASK,
+ new_state & SHENG_STATE_MASK);
+ state = new_state;
+ }
+ break;
+ default:
+ assert(!"invalid queue event");
+ break;
+ }
+ q->cur++;
+ }
+}
+
+char nfaExecSheng_B(const struct NFA *n, u64a offset, const u8 *buffer,
+ size_t length, NfaCallback cb, void *context) {
+ DEBUG_PRINTF("smallwrite Sheng\n");
+ assert(n->type == SHENG_NFA);
+ const struct sheng *sh = getImplNfa(n);
+ u8 state = sh->anchored;
+ u8 can_die = sh->flags & SHENG_FLAG_CAN_DIE;
+ u8 has_accel = sh->flags & SHENG_FLAG_HAS_ACCEL;
+ u8 single = sh->flags & SHENG_FLAG_SINGLE_REPORT;
+ u8 cached_accept_state = 0;
+ ReportID cached_accept_id = 0;
+
+ /* scan and report all matches */
+ int rv;
+ s64a end = length;
+ const u8 *scanned;
+
+ rv = runShengCb(sh, cb, context, offset, &cached_accept_state,
+ &cached_accept_id, buffer, buffer, buffer + end, can_die,
+ has_accel, single, &scanned, &state);
+ if (rv == MO_DEAD) {
+ DEBUG_PRINTF("exiting in state %u\n",
+ state & SHENG_STATE_MASK);
+ return MO_DEAD;
+ }
+
+ DEBUG_PRINTF("%u\n", state & SHENG_STATE_MASK);
+
+ const struct sstate_aux *aux = get_aux(sh, state);
+
+ if (aux->accept_eod) {
+ DEBUG_PRINTF("Reporting EOD matches\n");
+ fireReports(sh, cb, context, state, end + offset, &cached_accept_state,
+ &cached_accept_id, 1);
+ }
+
+ return state & SHENG_STATE_DEAD ? MO_DEAD : MO_ALIVE;
+}
+
+char nfaExecSheng_Q(const struct NFA *n, struct mq *q, s64a end) {
+ const struct sheng *sh = get_sheng(n);
+ char rv = runSheng(sh, q, end, CALLBACK_OUTPUT);
+ return rv;
+}
+
+char nfaExecSheng_Q2(const struct NFA *n, struct mq *q, s64a end) {
+ const struct sheng *sh = get_sheng(n);
+ char rv = runSheng(sh, q, end, STOP_AT_MATCH);
+ return rv;
+}
+
+char nfaExecSheng_QR(const struct NFA *n, struct mq *q, ReportID report) {
+ assert(q_cur_type(q) == MQE_START);
+
+ const struct sheng *sh = get_sheng(n);
+ char rv = runSheng(sh, q, 0 /* end */, NO_MATCHES);
+
+ if (rv && nfaExecSheng_inAccept(n, report, q)) {
+ return MO_MATCHES_PENDING;
+ }
+ return rv;
+}
+
+char nfaExecSheng_inAccept(const struct NFA *n, ReportID report, struct mq *q) {
+ assert(n && q);
+
+ const struct sheng *sh = get_sheng(n);
+ u8 s = *(const u8 *)q->state;
+ DEBUG_PRINTF("checking accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
+
+ const struct sstate_aux *aux = get_aux(sh, s);
+
+ if (!aux->accept) {
+ return 0;
+ }
+
+ return shengHasAccept(sh, aux, report);
+}
+
+char nfaExecSheng_inAnyAccept(const struct NFA *n, struct mq *q) {
+ assert(n && q);
+
+ const struct sheng *sh = get_sheng(n);
+ u8 s = *(const u8 *)q->state;
+ DEBUG_PRINTF("checking accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
+
+ const struct sstate_aux *aux = get_aux(sh, s);
+ return !!aux->accept;
+}
+
+char nfaExecSheng_testEOD(const struct NFA *nfa, const char *state,
+ UNUSED const char *streamState, u64a offset,
+ NfaCallback cb, void *ctxt) {
+ assert(nfa);
+
+ const struct sheng *sh = get_sheng(nfa);
+ u8 s = *(const u8 *)state;
+ DEBUG_PRINTF("checking EOD accepts for %u\n", (u8)(s & SHENG_STATE_MASK));
+
+ const struct sstate_aux *aux = get_aux(sh, s);
+
+ if (!aux->accept_eod) {
+ return MO_CONTINUE_MATCHING;
+ }
+
+ return fireReports(sh, cb, ctxt, s, offset, NULL, NULL, 1);
+}
+
+char nfaExecSheng_reportCurrent(const struct NFA *n, struct mq *q) {
+ const struct sheng *sh = (const struct sheng *)getImplNfa(n);
+ NfaCallback cb = q->cb;
+ void *ctxt = q->context;
+ u8 s = *(u8 *)q->state;
+ const struct sstate_aux *aux = get_aux(sh, s);
+ u64a offset = q_cur_offset(q);
+ u8 cached_state_id = 0;
+ ReportID cached_report_id = 0;
+ assert(q_cur_type(q) == MQE_START);
+
+ if (aux->accept) {
+ if (sh->flags & SHENG_FLAG_SINGLE_REPORT) {
+ fireSingleReport(cb, ctxt, sh->report, offset);
+ } else {
+ fireReports(sh, cb, ctxt, s, offset, &cached_state_id,
&cached_report_id, 0);
- }
- }
-
- return 0;
-}
-
-char nfaExecSheng_initCompressedState(const struct NFA *nfa, u64a offset,
- void *state, UNUSED u8 key) {
- const struct sheng *sh = get_sheng(nfa);
- u8 *s = (u8 *)state;
- *s = offset ? sh->floating: sh->anchored;
- return !(*s & SHENG_STATE_DEAD);
-}
-
-char nfaExecSheng_queueInitState(const struct NFA *nfa, struct mq *q) {
- assert(nfa->scratchStateSize == 1);
-
- /* starting in floating state */
- const struct sheng *sh = get_sheng(nfa);
- *(u8 *)q->state = sh->floating;
- DEBUG_PRINTF("starting in floating state\n");
- return 0;
-}
-
-char nfaExecSheng_queueCompressState(UNUSED const struct NFA *nfa,
- const struct mq *q, UNUSED s64a loc) {
- void *dest = q->streamState;
- const void *src = q->state;
- assert(nfa->scratchStateSize == 1);
- assert(nfa->streamStateSize == 1);
- *(u8 *)dest = *(const u8 *)src;
- return 0;
-}
-
-char nfaExecSheng_expandState(UNUSED const struct NFA *nfa, void *dest,
- const void *src, UNUSED u64a offset,
- UNUSED u8 key) {
- assert(nfa->scratchStateSize == 1);
- assert(nfa->streamStateSize == 1);
- *(u8 *)dest = *(const u8 *)src;
- return 0;
-}
+ }
+ }
+
+ return 0;
+}
+
+char nfaExecSheng_initCompressedState(const struct NFA *nfa, u64a offset,
+ void *state, UNUSED u8 key) {
+ const struct sheng *sh = get_sheng(nfa);
+ u8 *s = (u8 *)state;
+ *s = offset ? sh->floating: sh->anchored;
+ return !(*s & SHENG_STATE_DEAD);
+}
+
+char nfaExecSheng_queueInitState(const struct NFA *nfa, struct mq *q) {
+ assert(nfa->scratchStateSize == 1);
+
+ /* starting in floating state */
+ const struct sheng *sh = get_sheng(nfa);
+ *(u8 *)q->state = sh->floating;
+ DEBUG_PRINTF("starting in floating state\n");
+ return 0;
+}
+
+char nfaExecSheng_queueCompressState(UNUSED const struct NFA *nfa,
+ const struct mq *q, UNUSED s64a loc) {
+ void *dest = q->streamState;
+ const void *src = q->state;
+ assert(nfa->scratchStateSize == 1);
+ assert(nfa->streamStateSize == 1);
+ *(u8 *)dest = *(const u8 *)src;
+ return 0;
+}
+
+char nfaExecSheng_expandState(UNUSED const struct NFA *nfa, void *dest,
+ const void *src, UNUSED u64a offset,
+ UNUSED u8 key) {
+ assert(nfa->scratchStateSize == 1);
+ assert(nfa->streamStateSize == 1);
+ *(u8 *)dest = *(const u8 *)src;
+ return 0;
+}
#if defined(HAVE_AVX512VBMI)
// Sheng32
diff --git a/contrib/libs/hyperscan/src/nfa/sheng.h b/contrib/libs/hyperscan/src/nfa/sheng.h
index b9785008e85..7b90e3034f0 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng.h
+++ b/contrib/libs/hyperscan/src/nfa/sheng.h
@@ -1,63 +1,63 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef SHENG_H_
-#define SHENG_H_
-
-#include "callback.h"
-#include "ue2common.h"
-
-struct mq;
-struct NFA;
-
-#define nfaExecSheng_B_Reverse NFA_API_NO_IMPL
-#define nfaExecSheng_zombie_status NFA_API_ZOMBIE_NO_IMPL
-
-char nfaExecSheng_Q(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecSheng_Q2(const struct NFA *n, struct mq *q, s64a end);
-char nfaExecSheng_QR(const struct NFA *n, struct mq *q, ReportID report);
-char nfaExecSheng_inAccept(const struct NFA *n, ReportID report, struct mq *q);
-char nfaExecSheng_inAnyAccept(const struct NFA *n, struct mq *q);
-char nfaExecSheng_queueInitState(const struct NFA *nfa, struct mq *q);
-char nfaExecSheng_queueCompressState(const struct NFA *nfa, const struct mq *q,
- s64a loc);
-char nfaExecSheng_expandState(const struct NFA *nfa, void *dest,
- const void *src, u64a offset, u8 key);
-char nfaExecSheng_initCompressedState(const struct NFA *nfa, u64a offset,
- void *state, u8 key);
-char nfaExecSheng_testEOD(const struct NFA *nfa, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context);
-char nfaExecSheng_reportCurrent(const struct NFA *n, struct mq *q);
-
-char nfaExecSheng_B(const struct NFA *n, u64a offset, const u8 *buffer,
- size_t length, NfaCallback cb, void *context);
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef SHENG_H_
+#define SHENG_H_
+
+#include "callback.h"
+#include "ue2common.h"
+
+struct mq;
+struct NFA;
+
+#define nfaExecSheng_B_Reverse NFA_API_NO_IMPL
+#define nfaExecSheng_zombie_status NFA_API_ZOMBIE_NO_IMPL
+
+char nfaExecSheng_Q(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecSheng_Q2(const struct NFA *n, struct mq *q, s64a end);
+char nfaExecSheng_QR(const struct NFA *n, struct mq *q, ReportID report);
+char nfaExecSheng_inAccept(const struct NFA *n, ReportID report, struct mq *q);
+char nfaExecSheng_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecSheng_queueInitState(const struct NFA *nfa, struct mq *q);
+char nfaExecSheng_queueCompressState(const struct NFA *nfa, const struct mq *q,
+ s64a loc);
+char nfaExecSheng_expandState(const struct NFA *nfa, void *dest,
+ const void *src, u64a offset, u8 key);
+char nfaExecSheng_initCompressedState(const struct NFA *nfa, u64a offset,
+ void *state, u8 key);
+char nfaExecSheng_testEOD(const struct NFA *nfa, const char *state,
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context);
+char nfaExecSheng_reportCurrent(const struct NFA *n, struct mq *q);
+
+char nfaExecSheng_B(const struct NFA *n, u64a offset, const u8 *buffer,
+ size_t length, NfaCallback cb, void *context);
+
#if defined(HAVE_AVX512VBMI)
#define nfaExecSheng32_B_Reverse NFA_API_NO_IMPL
#define nfaExecSheng32_zombie_status NFA_API_ZOMBIE_NO_IMPL
@@ -140,4 +140,4 @@ char nfaExecSheng64_B(const struct NFA *n, u64a offset, const u8 *buffer,
#define nfaExecSheng64_B NFA_API_NO_IMPL
#endif // end of HAVE_AVX512VBMI
-#endif /* SHENG_H_ */
+#endif /* SHENG_H_ */
diff --git a/contrib/libs/hyperscan/src/nfa/sheng_defs.h b/contrib/libs/hyperscan/src/nfa/sheng_defs.h
index c2ec1d09fa2..390af752212 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng_defs.h
+++ b/contrib/libs/hyperscan/src/nfa/sheng_defs.h
@@ -1,57 +1,57 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef SHENG_DEFS_H
-#define SHENG_DEFS_H
-
-/*
- * Utility functions used by various versions of Sheng engine
- */
-static really_inline
-u8 isDeadState(const u8 a) {
- return a & SHENG_STATE_DEAD;
-}
-
-static really_inline
-u8 isAcceptState(const u8 a) {
- return a & SHENG_STATE_ACCEPT;
-}
-
-static really_inline
-u8 isAccelState(const u8 a) {
- return a & SHENG_STATE_ACCEL;
-}
-
-static really_inline
-u8 hasInterestingStates(const u8 a, const u8 b, const u8 c, const u8 d) {
- return (a | b | c | d) & (SHENG_STATE_FLAG_MASK);
-}
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef SHENG_DEFS_H
+#define SHENG_DEFS_H
+
+/*
+ * Utility functions used by various versions of Sheng engine
+ */
+static really_inline
+u8 isDeadState(const u8 a) {
+ return a & SHENG_STATE_DEAD;
+}
+
+static really_inline
+u8 isAcceptState(const u8 a) {
+ return a & SHENG_STATE_ACCEPT;
+}
+
+static really_inline
+u8 isAccelState(const u8 a) {
+ return a & SHENG_STATE_ACCEL;
+}
+
+static really_inline
+u8 hasInterestingStates(const u8 a, const u8 b, const u8 c, const u8 d) {
+ return (a | b | c | d) & (SHENG_STATE_FLAG_MASK);
+}
+
#if defined(HAVE_AVX512VBMI)
static really_inline
u8 isDeadState32(const u8 a) {
@@ -89,25 +89,25 @@ u8 hasInterestingStates64(const u8 a, const u8 b, const u8 c, const u8 d) {
}
#endif
-/* these functions should be optimized out, used by NO_MATCHES mode */
-static really_inline
-u8 dummyFunc4(UNUSED const u8 a, UNUSED const u8 b, UNUSED const u8 c,
- UNUSED const u8 d) {
- return 0;
-}
-
-static really_inline
-u8 dummyFunc(UNUSED const u8 a) {
- return 0;
-}
-
-/*
- * Sheng function definitions for single byte loops
- */
-/* callback output, can die */
-#define SHENG_IMPL sheng_cod
-#define DEAD_FUNC isDeadState
-#define ACCEPT_FUNC isAcceptState
+/* these functions should be optimized out, used by NO_MATCHES mode */
+static really_inline
+u8 dummyFunc4(UNUSED const u8 a, UNUSED const u8 b, UNUSED const u8 c,
+ UNUSED const u8 d) {
+ return 0;
+}
+
+static really_inline
+u8 dummyFunc(UNUSED const u8 a) {
+ return 0;
+}
+
+/*
+ * Sheng function definitions for single byte loops
+ */
+/* callback output, can die */
+#define SHENG_IMPL sheng_cod
+#define DEAD_FUNC isDeadState
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_cod
#define DEAD_FUNC32 isDeadState32
@@ -116,11 +116,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 isDeadState64
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -129,12 +129,12 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* callback output, can't die */
-#define SHENG_IMPL sheng_co
-#define DEAD_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* callback output, can't die */
+#define SHENG_IMPL sheng_co
+#define DEAD_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_co
#define DEAD_FUNC32 dummyFunc
@@ -143,11 +143,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -156,12 +156,12 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can die */
-#define SHENG_IMPL sheng_samd
-#define DEAD_FUNC isDeadState
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can die */
+#define SHENG_IMPL sheng_samd
+#define DEAD_FUNC isDeadState
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_samd
#define DEAD_FUNC32 isDeadState32
@@ -170,11 +170,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 isDeadState64
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -183,12 +183,12 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can't die */
-#define SHENG_IMPL sheng_sam
-#define DEAD_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can't die */
+#define SHENG_IMPL sheng_sam
+#define DEAD_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_sam
#define DEAD_FUNC32 dummyFunc
@@ -197,11 +197,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -210,12 +210,12 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* no match, can die */
-#define SHENG_IMPL sheng_nmd
-#define DEAD_FUNC isDeadState
-#define ACCEPT_FUNC dummyFunc
+#undef STOP_AT_MATCH
+
+/* no match, can die */
+#define SHENG_IMPL sheng_nmd
+#define DEAD_FUNC isDeadState
+#define ACCEPT_FUNC dummyFunc
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_nmd
#define DEAD_FUNC32 isDeadState32
@@ -224,11 +224,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 isDeadState64
#define ACCEPT_FUNC64 dummyFunc
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -237,12 +237,12 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* no match, can't die */
-#define SHENG_IMPL sheng_nm
-#define DEAD_FUNC dummyFunc
-#define ACCEPT_FUNC dummyFunc
+#undef STOP_AT_MATCH
+
+/* no match, can't die */
+#define SHENG_IMPL sheng_nm
+#define DEAD_FUNC dummyFunc
+#define ACCEPT_FUNC dummyFunc
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_nm
#define DEAD_FUNC32 dummyFunc
@@ -251,11 +251,11 @@ u8 dummyFunc(UNUSED const u8 a) {
#define DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 dummyFunc
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl.h"
-#undef SHENG_IMPL
-#undef DEAD_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl.h"
+#undef SHENG_IMPL
+#undef DEAD_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef DEAD_FUNC32
@@ -264,19 +264,19 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/*
- * Sheng function definitions for 4-byte loops
- */
-/* callback output, can die, accelerated */
-#define SHENG_IMPL sheng4_coda
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC isDeadState
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC isAccelState
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/*
+ * Sheng function definitions for 4-byte loops
+ */
+/* callback output, can die, accelerated */
+#define SHENG_IMPL sheng4_coda
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC isDeadState
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC isAccelState
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_coda
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -287,15 +287,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define ACCEPT_FUNC32 isAcceptState32
#define NO_SHENG64_IMPL
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -306,16 +306,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef ACCEPT_FUNC32
#undef NO_SHENG64_IMPL
#endif
-#undef STOP_AT_MATCH
-
-/* callback output, can die, not accelerated */
-#define SHENG_IMPL sheng4_cod
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC isDeadState
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* callback output, can die, not accelerated */
+#define SHENG_IMPL sheng4_cod
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC isDeadState
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_cod
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -330,15 +330,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -353,16 +353,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* callback output, can't die, accelerated */
-#define SHENG_IMPL sheng4_coa
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC isAccelState
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* callback output, can't die, accelerated */
+#define SHENG_IMPL sheng4_coa
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC isAccelState
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_coa
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -373,15 +373,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define ACCEPT_FUNC32 isAcceptState32
#define NO_SHENG64_IMPL
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -392,16 +392,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef ACCEPT_FUNC32
#undef NO_SHENG64_IMPL
#endif
-#undef STOP_AT_MATCH
-
-/* callback output, can't die, not accelerated */
-#define SHENG_IMPL sheng4_co
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* callback output, can't die, not accelerated */
+#define SHENG_IMPL sheng4_co
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_co
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -416,15 +416,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -439,16 +439,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can die, accelerated */
-#define SHENG_IMPL sheng4_samda
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC isDeadState
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC isAccelState
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can die, accelerated */
+#define SHENG_IMPL sheng4_samda
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC isDeadState
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC isAccelState
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_samda
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -459,15 +459,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define ACCEPT_FUNC32 isAcceptState32
#define NO_SHENG64_IMPL
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -478,16 +478,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef ACCEPT_FUNC32
#undef NO_SHENG64_IMPL
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can die, not accelerated */
-#define SHENG_IMPL sheng4_samd
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC isDeadState
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can die, not accelerated */
+#define SHENG_IMPL sheng4_samd
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC isDeadState
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_samd
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -502,15 +502,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -525,16 +525,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can't die, accelerated */
-#define SHENG_IMPL sheng4_sama
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC isAccelState
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can't die, accelerated */
+#define SHENG_IMPL sheng4_sama
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC isAccelState
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_sama
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -545,15 +545,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define ACCEPT_FUNC32 isAcceptState32
#define NO_SHENG64_IMPL
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -564,16 +564,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef ACCEPT_FUNC32
#undef NO_SHENG64_IMPL
#endif
-#undef STOP_AT_MATCH
-
-/* stop at match, can't die, not accelerated */
-#define SHENG_IMPL sheng4_sam
-#define INTERESTING_FUNC hasInterestingStates
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC isAcceptState
+#undef STOP_AT_MATCH
+
+/* stop at match, can't die, not accelerated */
+#define SHENG_IMPL sheng4_sam
+#define INTERESTING_FUNC hasInterestingStates
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC isAcceptState
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_sam
#define INTERESTING_FUNC32 hasInterestingStates32
@@ -588,15 +588,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 isAcceptState64
#endif
-#define STOP_AT_MATCH 1
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 1
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -611,18 +611,18 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* no-match have interesting func as dummy, and die/accel checks are outer */
-
-/* no match, can die, accelerated */
-#define SHENG_IMPL sheng4_nmda
-#define INTERESTING_FUNC dummyFunc4
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC isDeadState
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC isAccelState
-#define ACCEPT_FUNC dummyFunc
+#undef STOP_AT_MATCH
+
+/* no-match have interesting func as dummy, and die/accel checks are outer */
+
+/* no match, can die, accelerated */
+#define SHENG_IMPL sheng4_nmda
+#define INTERESTING_FUNC dummyFunc4
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC isDeadState
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC isAccelState
+#define ACCEPT_FUNC dummyFunc
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_nmda
#define INTERESTING_FUNC32 dummyFunc4
@@ -633,15 +633,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define ACCEPT_FUNC32 dummyFunc
#define NO_SHENG64_IMPL
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -652,16 +652,16 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef ACCEPT_FUNC32
#undef NO_SHENG64_IMPL
#endif
-#undef STOP_AT_MATCH
-
-/* no match, can die, not accelerated */
-#define SHENG_IMPL sheng4_nmd
-#define INTERESTING_FUNC dummyFunc4
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC isDeadState
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC dummyFunc
+#undef STOP_AT_MATCH
+
+/* no match, can die, not accelerated */
+#define SHENG_IMPL sheng4_nmd
+#define INTERESTING_FUNC dummyFunc4
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC isDeadState
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC dummyFunc
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_nmd
#define INTERESTING_FUNC32 dummyFunc4
@@ -676,15 +676,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 isDeadState64
#define ACCEPT_FUNC64 dummyFunc
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -699,19 +699,19 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-/* there is no performance benefit in accelerating a no-match case that can't
- * die */
-
-/* no match, can't die */
-#define SHENG_IMPL sheng4_nm
-#define INTERESTING_FUNC dummyFunc4
-#define INNER_DEAD_FUNC dummyFunc
-#define OUTER_DEAD_FUNC dummyFunc
-#define INNER_ACCEL_FUNC dummyFunc
-#define OUTER_ACCEL_FUNC dummyFunc
-#define ACCEPT_FUNC dummyFunc
+#undef STOP_AT_MATCH
+
+/* there is no performance benefit in accelerating a no-match case that can't
+ * die */
+
+/* no match, can't die */
+#define SHENG_IMPL sheng4_nm
+#define INTERESTING_FUNC dummyFunc4
+#define INNER_DEAD_FUNC dummyFunc
+#define OUTER_DEAD_FUNC dummyFunc
+#define INNER_ACCEL_FUNC dummyFunc
+#define OUTER_ACCEL_FUNC dummyFunc
+#define ACCEPT_FUNC dummyFunc
#if defined(HAVE_AVX512VBMI)
#define SHENG32_IMPL sheng32_4_nm
#define INTERESTING_FUNC32 dummyFunc4
@@ -726,15 +726,15 @@ u8 dummyFunc(UNUSED const u8 a) {
#define OUTER_DEAD_FUNC64 dummyFunc
#define ACCEPT_FUNC64 dummyFunc
#endif
-#define STOP_AT_MATCH 0
-#include "sheng_impl4.h"
-#undef SHENG_IMPL
-#undef INTERESTING_FUNC
-#undef INNER_DEAD_FUNC
-#undef OUTER_DEAD_FUNC
-#undef INNER_ACCEL_FUNC
-#undef OUTER_ACCEL_FUNC
-#undef ACCEPT_FUNC
+#define STOP_AT_MATCH 0
+#include "sheng_impl4.h"
+#undef SHENG_IMPL
+#undef INTERESTING_FUNC
+#undef INNER_DEAD_FUNC
+#undef OUTER_DEAD_FUNC
+#undef INNER_ACCEL_FUNC
+#undef OUTER_ACCEL_FUNC
+#undef ACCEPT_FUNC
#if defined(HAVE_AVX512VBMI)
#undef SHENG32_IMPL
#undef INTERESTING_FUNC32
@@ -749,6 +749,6 @@ u8 dummyFunc(UNUSED const u8 a) {
#undef OUTER_DEAD_FUNC64
#undef ACCEPT_FUNC64
#endif
-#undef STOP_AT_MATCH
-
-#endif // SHENG_DEFS_H
+#undef STOP_AT_MATCH
+
+#endif // SHENG_DEFS_H
diff --git a/contrib/libs/hyperscan/src/nfa/sheng_impl.h b/contrib/libs/hyperscan/src/nfa/sheng_impl.h
index 8c427540836..fb8ee168345 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng_impl.h
+++ b/contrib/libs/hyperscan/src/nfa/sheng_impl.h
@@ -1,100 +1,100 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/*
- * In order to use this macro, the following things need to be defined:
- *
- * - SHENG_IMPL (name of the Sheng implementation function)
- * - DEAD_FUNC (name of the function checking for dead states)
- * - ACCEPT_FUNC (name of the function checking for accept state)
- * - STOP_AT_MATCH (can be 1 or 0, enable or disable stop at match)
- */
-
-/* byte-by-byte version. we don't do byte-by-byte death checking as it's
- * pretty pointless to do it over a buffer that's at most 3 bytes long */
-static really_inline
-char SHENG_IMPL(u8 *state, NfaCallback cb, void *ctxt, const struct sheng *s,
- u8 *const cached_accept_state, ReportID *const cached_accept_id,
- u8 single, u64a base_offset, const u8 *buf, const u8 *start,
- const u8 *end, const u8 **scan_end) {
- DEBUG_PRINTF("Starting DFA execution in state %u\n",
- *state & SHENG_STATE_MASK);
- const u8 *cur_buf = start;
- if (DEAD_FUNC(*state)) {
- DEBUG_PRINTF("Dead on arrival\n");
- *scan_end = end;
- return MO_CONTINUE_MATCHING;
- }
- DEBUG_PRINTF("Scanning %lli bytes\n", (s64a)(end - start));
-
- m128 cur_state = set16x8(*state);
- const m128 *masks = s->shuffle_masks;
-
- while (likely(cur_buf != end)) {
- const u8 c = *cur_buf;
- const m128 shuffle_mask = masks[c];
- cur_state = pshufb_m128(shuffle_mask, cur_state);
- const u8 tmp = movd(cur_state);
-
- DEBUG_PRINTF("c: %02hhx '%c'\n", c, ourisprint(c) ? c : '?');
- DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", tmp, (tmp & 0xF0) >> 4,
- tmp & 0xF);
-
- if (unlikely(ACCEPT_FUNC(tmp))) {
- DEBUG_PRINTF("Accept state %u reached\n", tmp & SHENG_STATE_MASK);
- u64a match_offset = base_offset + (cur_buf - buf) + 1;
- DEBUG_PRINTF("Match @ %llu\n", match_offset);
- if (STOP_AT_MATCH) {
- DEBUG_PRINTF("Stopping at match @ %lli\n",
- (u64a)(cur_buf - start));
- *state = tmp;
- *scan_end = cur_buf;
- return MO_MATCHES_PENDING;
- }
- if (single) {
- if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
- MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- } else {
- if (fireReports(s, cb, ctxt, tmp, match_offset,
- cached_accept_state, cached_accept_id,
- 0) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- }
- }
- cur_buf++;
- }
- *state = movd(cur_state);
- *scan_end = cur_buf;
- return MO_CONTINUE_MATCHING;
-}
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/*
+ * In order to use this macro, the following things need to be defined:
+ *
+ * - SHENG_IMPL (name of the Sheng implementation function)
+ * - DEAD_FUNC (name of the function checking for dead states)
+ * - ACCEPT_FUNC (name of the function checking for accept state)
+ * - STOP_AT_MATCH (can be 1 or 0, enable or disable stop at match)
+ */
+
+/* byte-by-byte version. we don't do byte-by-byte death checking as it's
+ * pretty pointless to do it over a buffer that's at most 3 bytes long */
+static really_inline
+char SHENG_IMPL(u8 *state, NfaCallback cb, void *ctxt, const struct sheng *s,
+ u8 *const cached_accept_state, ReportID *const cached_accept_id,
+ u8 single, u64a base_offset, const u8 *buf, const u8 *start,
+ const u8 *end, const u8 **scan_end) {
+ DEBUG_PRINTF("Starting DFA execution in state %u\n",
+ *state & SHENG_STATE_MASK);
+ const u8 *cur_buf = start;
+ if (DEAD_FUNC(*state)) {
+ DEBUG_PRINTF("Dead on arrival\n");
+ *scan_end = end;
+ return MO_CONTINUE_MATCHING;
+ }
+ DEBUG_PRINTF("Scanning %lli bytes\n", (s64a)(end - start));
+
+ m128 cur_state = set16x8(*state);
+ const m128 *masks = s->shuffle_masks;
+
+ while (likely(cur_buf != end)) {
+ const u8 c = *cur_buf;
+ const m128 shuffle_mask = masks[c];
+ cur_state = pshufb_m128(shuffle_mask, cur_state);
+ const u8 tmp = movd(cur_state);
+
+ DEBUG_PRINTF("c: %02hhx '%c'\n", c, ourisprint(c) ? c : '?');
+ DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", tmp, (tmp & 0xF0) >> 4,
+ tmp & 0xF);
+
+ if (unlikely(ACCEPT_FUNC(tmp))) {
+ DEBUG_PRINTF("Accept state %u reached\n", tmp & SHENG_STATE_MASK);
+ u64a match_offset = base_offset + (cur_buf - buf) + 1;
+ DEBUG_PRINTF("Match @ %llu\n", match_offset);
+ if (STOP_AT_MATCH) {
+ DEBUG_PRINTF("Stopping at match @ %lli\n",
+ (u64a)(cur_buf - start));
+ *state = tmp;
+ *scan_end = cur_buf;
+ return MO_MATCHES_PENDING;
+ }
+ if (single) {
+ if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
+ MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ } else {
+ if (fireReports(s, cb, ctxt, tmp, match_offset,
+ cached_accept_state, cached_accept_id,
+ 0) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ }
+ }
+ cur_buf++;
+ }
+ *state = movd(cur_state);
+ *scan_end = cur_buf;
+ return MO_CONTINUE_MATCHING;
+}
#if defined(HAVE_AVX512VBMI)
static really_inline
diff --git a/contrib/libs/hyperscan/src/nfa/sheng_impl4.h b/contrib/libs/hyperscan/src/nfa/sheng_impl4.h
index fffb88a437a..440e7396e2f 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng_impl4.h
+++ b/contrib/libs/hyperscan/src/nfa/sheng_impl4.h
@@ -1,287 +1,287 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/*
- * In order to use this macro, the following things need to be defined:
- *
- * - SHENG_IMPL (name of the Sheng implementation function)
- * - INTERESTING_FUNC (name of the function checking for accept, accel or dead
- * states)
- * - INNER_DEAD_FUNC (name of the inner function checking for dead states)
- * - OUTER_DEAD_FUNC (name of the outer function checking for dead states)
- * - INNER_ACCEL_FUNC (name of the inner function checking for accel states)
- * - OUTER_ACCEL_FUNC (name of the outer function checking for accel states)
- * - ACCEPT_FUNC (name of the function checking for accept state)
- * - STOP_AT_MATCH (can be 1 or 0, enable or disable stop at match)
- */
-
-/* unrolled 4-byte-at-a-time version.
- *
- * we put innerDeadFunc inside interestingFunc() block so that we don't pay for
- * dead states checking. however, if interestingFunc is dummy, innerDeadFunc
- * gets lost with it, so we need an additional check outside the
- * interestingFunc() branch - it's normally dummy so we don't pay for it, but
- * when interestingFunc is dummy, outerDeadFunc should be set if we want to
- * check for dead states.
- *
- * also, deadFunc only checks the last known state, but since we can't ever get
- * out of the dead state and we don't really care where we died, it's not a
- * problem.
- */
-static really_inline
-char SHENG_IMPL(u8 *state, NfaCallback cb, void *ctxt, const struct sheng *s,
- u8 *const cached_accept_state, ReportID *const cached_accept_id,
- u8 single, u64a base_offset, const u8 *buf, const u8 *start,
- const u8 *end, const u8 **scan_end) {
- DEBUG_PRINTF("Starting DFAx4 execution in state %u\n",
- *state & SHENG_STATE_MASK);
- const u8 *cur_buf = start;
- const u8 *min_accel_dist = start;
- base_offset++;
- DEBUG_PRINTF("Scanning %llu bytes\n", (u64a)(end - start));
-
- if (INNER_ACCEL_FUNC(*state) || OUTER_ACCEL_FUNC(*state)) {
- DEBUG_PRINTF("Accel state reached @ 0\n");
- const union AccelAux *aaux = get_accel(s, *state & SHENG_STATE_MASK);
- const u8 *new_offset = run_accel(aaux, cur_buf, end);
- if (new_offset < cur_buf + BAD_ACCEL_DIST) {
- min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
- } else {
- min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
- }
- DEBUG_PRINTF("Next accel chance: %llu\n",
- (u64a)(min_accel_dist - start));
- DEBUG_PRINTF("Accel scanned %zu bytes\n", new_offset - cur_buf);
- cur_buf = new_offset;
- DEBUG_PRINTF("New offset: %lli\n", (s64a)(cur_buf - start));
- }
- if (INNER_DEAD_FUNC(*state) || OUTER_DEAD_FUNC(*state)) {
- DEBUG_PRINTF("Dead on arrival\n");
- *scan_end = end;
- return MO_CONTINUE_MATCHING;
- }
-
- m128 cur_state = set16x8(*state);
- const m128 *masks = s->shuffle_masks;
-
- while (likely(end - cur_buf >= 4)) {
- const u8 *b1 = cur_buf;
- const u8 *b2 = cur_buf + 1;
- const u8 *b3 = cur_buf + 2;
- const u8 *b4 = cur_buf + 3;
- const u8 c1 = *b1;
- const u8 c2 = *b2;
- const u8 c3 = *b3;
- const u8 c4 = *b4;
-
- const m128 shuffle_mask1 = masks[c1];
- cur_state = pshufb_m128(shuffle_mask1, cur_state);
- const u8 a1 = movd(cur_state);
-
- const m128 shuffle_mask2 = masks[c2];
- cur_state = pshufb_m128(shuffle_mask2, cur_state);
- const u8 a2 = movd(cur_state);
-
- const m128 shuffle_mask3 = masks[c3];
- cur_state = pshufb_m128(shuffle_mask3, cur_state);
- const u8 a3 = movd(cur_state);
-
- const m128 shuffle_mask4 = masks[c4];
- cur_state = pshufb_m128(shuffle_mask4, cur_state);
- const u8 a4 = movd(cur_state);
-
- DEBUG_PRINTF("c: %02hhx '%c'\n", c1, ourisprint(c1) ? c1 : '?');
- DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a1, (a1 & 0xF0) >> 4, a1 & 0xF);
-
- DEBUG_PRINTF("c: %02hhx '%c'\n", c2, ourisprint(c2) ? c2 : '?');
- DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a2, (a2 & 0xF0) >> 4, a2 & 0xF);
-
- DEBUG_PRINTF("c: %02hhx '%c'\n", c3, ourisprint(c3) ? c3 : '?');
- DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a3, (a3 & 0xF0) >> 4, a3 & 0xF);
-
- DEBUG_PRINTF("c: %02hhx '%c'\n", c4, ourisprint(c4) ? c4 : '?');
- DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a4, (a4 & 0xF0) >> 4, a4 & 0xF);
-
- if (unlikely(INTERESTING_FUNC(a1, a2, a3, a4))) {
- if (ACCEPT_FUNC(a1)) {
- u64a match_offset = base_offset + b1 - buf;
- DEBUG_PRINTF("Accept state %u reached\n",
- a1 & SHENG_STATE_MASK);
- DEBUG_PRINTF("Match @ %llu\n", match_offset);
- if (STOP_AT_MATCH) {
- DEBUG_PRINTF("Stopping at match @ %lli\n",
- (s64a)(b1 - start));
- *scan_end = b1;
- *state = a1;
- return MO_MATCHES_PENDING;
- }
- if (single) {
- if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
- MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- } else {
- if (fireReports(s, cb, ctxt, a1, match_offset,
- cached_accept_state, cached_accept_id,
- 0) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- }
- }
- if (ACCEPT_FUNC(a2)) {
- u64a match_offset = base_offset + b2 - buf;
- DEBUG_PRINTF("Accept state %u reached\n",
- a2 & SHENG_STATE_MASK);
- DEBUG_PRINTF("Match @ %llu\n", match_offset);
- if (STOP_AT_MATCH) {
- DEBUG_PRINTF("Stopping at match @ %lli\n",
- (s64a)(b2 - start));
- *scan_end = b2;
- *state = a2;
- return MO_MATCHES_PENDING;
- }
- if (single) {
- if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
- MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- } else {
- if (fireReports(s, cb, ctxt, a2, match_offset,
- cached_accept_state, cached_accept_id,
- 0) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- }
- }
- if (ACCEPT_FUNC(a3)) {
- u64a match_offset = base_offset + b3 - buf;
- DEBUG_PRINTF("Accept state %u reached\n",
- a3 & SHENG_STATE_MASK);
- DEBUG_PRINTF("Match @ %llu\n", match_offset);
- if (STOP_AT_MATCH) {
- DEBUG_PRINTF("Stopping at match @ %lli\n",
- (s64a)(b3 - start));
- *scan_end = b3;
- *state = a3;
- return MO_MATCHES_PENDING;
- }
- if (single) {
- if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
- MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- } else {
- if (fireReports(s, cb, ctxt, a3, match_offset,
- cached_accept_state, cached_accept_id,
- 0) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- }
- }
- if (ACCEPT_FUNC(a4)) {
- u64a match_offset = base_offset + b4 - buf;
- DEBUG_PRINTF("Accept state %u reached\n",
- a4 & SHENG_STATE_MASK);
- DEBUG_PRINTF("Match @ %llu\n", match_offset);
- if (STOP_AT_MATCH) {
- DEBUG_PRINTF("Stopping at match @ %lli\n",
- (s64a)(b4 - start));
- *scan_end = b4;
- *state = a4;
- return MO_MATCHES_PENDING;
- }
- if (single) {
- if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
- MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- } else {
- if (fireReports(s, cb, ctxt, a4, match_offset,
- cached_accept_state, cached_accept_id,
- 0) == MO_HALT_MATCHING) {
- return MO_HALT_MATCHING;
- }
- }
- }
- if (INNER_DEAD_FUNC(a4)) {
- DEBUG_PRINTF("Dead state reached @ %lli\n", (s64a)(b4 - buf));
- *scan_end = end;
- *state = a4;
- return MO_CONTINUE_MATCHING;
- }
- if (cur_buf > min_accel_dist && INNER_ACCEL_FUNC(a4)) {
- DEBUG_PRINTF("Accel state reached @ %lli\n", (s64a)(b4 - buf));
- const union AccelAux *aaux =
- get_accel(s, a4 & SHENG_STATE_MASK);
- const u8 *new_offset = run_accel(aaux, cur_buf + 4, end);
- if (new_offset < cur_buf + 4 + BAD_ACCEL_DIST) {
- min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
- } else {
- min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
- }
- DEBUG_PRINTF("Next accel chance: %llu\n",
- (u64a)(min_accel_dist - start));
- DEBUG_PRINTF("Accel scanned %llu bytes\n",
- (u64a)(new_offset - cur_buf - 4));
- cur_buf = new_offset;
- DEBUG_PRINTF("New offset: %llu\n", (u64a)(cur_buf - buf));
- continue;
- }
- }
- if (OUTER_DEAD_FUNC(a4)) {
- DEBUG_PRINTF("Dead state reached @ %lli\n", (s64a)(cur_buf - buf));
- *scan_end = end;
- *state = a4;
- return MO_CONTINUE_MATCHING;
- };
- if (cur_buf > min_accel_dist && OUTER_ACCEL_FUNC(a4)) {
- DEBUG_PRINTF("Accel state reached @ %lli\n", (s64a)(b4 - buf));
- const union AccelAux *aaux = get_accel(s, a4 & SHENG_STATE_MASK);
- const u8 *new_offset = run_accel(aaux, cur_buf + 4, end);
- if (new_offset < cur_buf + 4 + BAD_ACCEL_DIST) {
- min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
- } else {
- min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
- }
- DEBUG_PRINTF("Next accel chance: %llu\n",
- (u64a)(min_accel_dist - start));
- DEBUG_PRINTF("Accel scanned %llu bytes\n",
- (u64a)(new_offset - cur_buf - 4));
- cur_buf = new_offset;
- DEBUG_PRINTF("New offset: %llu\n", (u64a)(cur_buf - buf));
- continue;
- };
- cur_buf += 4;
- }
- *state = movd(cur_state);
- *scan_end = cur_buf;
- return MO_CONTINUE_MATCHING;
-}
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/*
+ * In order to use this macro, the following things need to be defined:
+ *
+ * - SHENG_IMPL (name of the Sheng implementation function)
+ * - INTERESTING_FUNC (name of the function checking for accept, accel or dead
+ * states)
+ * - INNER_DEAD_FUNC (name of the inner function checking for dead states)
+ * - OUTER_DEAD_FUNC (name of the outer function checking for dead states)
+ * - INNER_ACCEL_FUNC (name of the inner function checking for accel states)
+ * - OUTER_ACCEL_FUNC (name of the outer function checking for accel states)
+ * - ACCEPT_FUNC (name of the function checking for accept state)
+ * - STOP_AT_MATCH (can be 1 or 0, enable or disable stop at match)
+ */
+
+/* unrolled 4-byte-at-a-time version.
+ *
+ * we put innerDeadFunc inside interestingFunc() block so that we don't pay for
+ * dead states checking. however, if interestingFunc is dummy, innerDeadFunc
+ * gets lost with it, so we need an additional check outside the
+ * interestingFunc() branch - it's normally dummy so we don't pay for it, but
+ * when interestingFunc is dummy, outerDeadFunc should be set if we want to
+ * check for dead states.
+ *
+ * also, deadFunc only checks the last known state, but since we can't ever get
+ * out of the dead state and we don't really care where we died, it's not a
+ * problem.
+ */
+static really_inline
+char SHENG_IMPL(u8 *state, NfaCallback cb, void *ctxt, const struct sheng *s,
+ u8 *const cached_accept_state, ReportID *const cached_accept_id,
+ u8 single, u64a base_offset, const u8 *buf, const u8 *start,
+ const u8 *end, const u8 **scan_end) {
+ DEBUG_PRINTF("Starting DFAx4 execution in state %u\n",
+ *state & SHENG_STATE_MASK);
+ const u8 *cur_buf = start;
+ const u8 *min_accel_dist = start;
+ base_offset++;
+ DEBUG_PRINTF("Scanning %llu bytes\n", (u64a)(end - start));
+
+ if (INNER_ACCEL_FUNC(*state) || OUTER_ACCEL_FUNC(*state)) {
+ DEBUG_PRINTF("Accel state reached @ 0\n");
+ const union AccelAux *aaux = get_accel(s, *state & SHENG_STATE_MASK);
+ const u8 *new_offset = run_accel(aaux, cur_buf, end);
+ if (new_offset < cur_buf + BAD_ACCEL_DIST) {
+ min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
+ } else {
+ min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
+ }
+ DEBUG_PRINTF("Next accel chance: %llu\n",
+ (u64a)(min_accel_dist - start));
+ DEBUG_PRINTF("Accel scanned %zu bytes\n", new_offset - cur_buf);
+ cur_buf = new_offset;
+ DEBUG_PRINTF("New offset: %lli\n", (s64a)(cur_buf - start));
+ }
+ if (INNER_DEAD_FUNC(*state) || OUTER_DEAD_FUNC(*state)) {
+ DEBUG_PRINTF("Dead on arrival\n");
+ *scan_end = end;
+ return MO_CONTINUE_MATCHING;
+ }
+
+ m128 cur_state = set16x8(*state);
+ const m128 *masks = s->shuffle_masks;
+
+ while (likely(end - cur_buf >= 4)) {
+ const u8 *b1 = cur_buf;
+ const u8 *b2 = cur_buf + 1;
+ const u8 *b3 = cur_buf + 2;
+ const u8 *b4 = cur_buf + 3;
+ const u8 c1 = *b1;
+ const u8 c2 = *b2;
+ const u8 c3 = *b3;
+ const u8 c4 = *b4;
+
+ const m128 shuffle_mask1 = masks[c1];
+ cur_state = pshufb_m128(shuffle_mask1, cur_state);
+ const u8 a1 = movd(cur_state);
+
+ const m128 shuffle_mask2 = masks[c2];
+ cur_state = pshufb_m128(shuffle_mask2, cur_state);
+ const u8 a2 = movd(cur_state);
+
+ const m128 shuffle_mask3 = masks[c3];
+ cur_state = pshufb_m128(shuffle_mask3, cur_state);
+ const u8 a3 = movd(cur_state);
+
+ const m128 shuffle_mask4 = masks[c4];
+ cur_state = pshufb_m128(shuffle_mask4, cur_state);
+ const u8 a4 = movd(cur_state);
+
+ DEBUG_PRINTF("c: %02hhx '%c'\n", c1, ourisprint(c1) ? c1 : '?');
+ DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a1, (a1 & 0xF0) >> 4, a1 & 0xF);
+
+ DEBUG_PRINTF("c: %02hhx '%c'\n", c2, ourisprint(c2) ? c2 : '?');
+ DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a2, (a2 & 0xF0) >> 4, a2 & 0xF);
+
+ DEBUG_PRINTF("c: %02hhx '%c'\n", c3, ourisprint(c3) ? c3 : '?');
+ DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a3, (a3 & 0xF0) >> 4, a3 & 0xF);
+
+ DEBUG_PRINTF("c: %02hhx '%c'\n", c4, ourisprint(c4) ? c4 : '?');
+ DEBUG_PRINTF("s: %u (hi: %u lo: %u)\n", a4, (a4 & 0xF0) >> 4, a4 & 0xF);
+
+ if (unlikely(INTERESTING_FUNC(a1, a2, a3, a4))) {
+ if (ACCEPT_FUNC(a1)) {
+ u64a match_offset = base_offset + b1 - buf;
+ DEBUG_PRINTF("Accept state %u reached\n",
+ a1 & SHENG_STATE_MASK);
+ DEBUG_PRINTF("Match @ %llu\n", match_offset);
+ if (STOP_AT_MATCH) {
+ DEBUG_PRINTF("Stopping at match @ %lli\n",
+ (s64a)(b1 - start));
+ *scan_end = b1;
+ *state = a1;
+ return MO_MATCHES_PENDING;
+ }
+ if (single) {
+ if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
+ MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ } else {
+ if (fireReports(s, cb, ctxt, a1, match_offset,
+ cached_accept_state, cached_accept_id,
+ 0) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ }
+ }
+ if (ACCEPT_FUNC(a2)) {
+ u64a match_offset = base_offset + b2 - buf;
+ DEBUG_PRINTF("Accept state %u reached\n",
+ a2 & SHENG_STATE_MASK);
+ DEBUG_PRINTF("Match @ %llu\n", match_offset);
+ if (STOP_AT_MATCH) {
+ DEBUG_PRINTF("Stopping at match @ %lli\n",
+ (s64a)(b2 - start));
+ *scan_end = b2;
+ *state = a2;
+ return MO_MATCHES_PENDING;
+ }
+ if (single) {
+ if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
+ MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ } else {
+ if (fireReports(s, cb, ctxt, a2, match_offset,
+ cached_accept_state, cached_accept_id,
+ 0) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ }
+ }
+ if (ACCEPT_FUNC(a3)) {
+ u64a match_offset = base_offset + b3 - buf;
+ DEBUG_PRINTF("Accept state %u reached\n",
+ a3 & SHENG_STATE_MASK);
+ DEBUG_PRINTF("Match @ %llu\n", match_offset);
+ if (STOP_AT_MATCH) {
+ DEBUG_PRINTF("Stopping at match @ %lli\n",
+ (s64a)(b3 - start));
+ *scan_end = b3;
+ *state = a3;
+ return MO_MATCHES_PENDING;
+ }
+ if (single) {
+ if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
+ MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ } else {
+ if (fireReports(s, cb, ctxt, a3, match_offset,
+ cached_accept_state, cached_accept_id,
+ 0) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ }
+ }
+ if (ACCEPT_FUNC(a4)) {
+ u64a match_offset = base_offset + b4 - buf;
+ DEBUG_PRINTF("Accept state %u reached\n",
+ a4 & SHENG_STATE_MASK);
+ DEBUG_PRINTF("Match @ %llu\n", match_offset);
+ if (STOP_AT_MATCH) {
+ DEBUG_PRINTF("Stopping at match @ %lli\n",
+ (s64a)(b4 - start));
+ *scan_end = b4;
+ *state = a4;
+ return MO_MATCHES_PENDING;
+ }
+ if (single) {
+ if (fireSingleReport(cb, ctxt, s->report, match_offset) ==
+ MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ } else {
+ if (fireReports(s, cb, ctxt, a4, match_offset,
+ cached_accept_state, cached_accept_id,
+ 0) == MO_HALT_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+ }
+ }
+ if (INNER_DEAD_FUNC(a4)) {
+ DEBUG_PRINTF("Dead state reached @ %lli\n", (s64a)(b4 - buf));
+ *scan_end = end;
+ *state = a4;
+ return MO_CONTINUE_MATCHING;
+ }
+ if (cur_buf > min_accel_dist && INNER_ACCEL_FUNC(a4)) {
+ DEBUG_PRINTF("Accel state reached @ %lli\n", (s64a)(b4 - buf));
+ const union AccelAux *aaux =
+ get_accel(s, a4 & SHENG_STATE_MASK);
+ const u8 *new_offset = run_accel(aaux, cur_buf + 4, end);
+ if (new_offset < cur_buf + 4 + BAD_ACCEL_DIST) {
+ min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
+ } else {
+ min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
+ }
+ DEBUG_PRINTF("Next accel chance: %llu\n",
+ (u64a)(min_accel_dist - start));
+ DEBUG_PRINTF("Accel scanned %llu bytes\n",
+ (u64a)(new_offset - cur_buf - 4));
+ cur_buf = new_offset;
+ DEBUG_PRINTF("New offset: %llu\n", (u64a)(cur_buf - buf));
+ continue;
+ }
+ }
+ if (OUTER_DEAD_FUNC(a4)) {
+ DEBUG_PRINTF("Dead state reached @ %lli\n", (s64a)(cur_buf - buf));
+ *scan_end = end;
+ *state = a4;
+ return MO_CONTINUE_MATCHING;
+ };
+ if (cur_buf > min_accel_dist && OUTER_ACCEL_FUNC(a4)) {
+ DEBUG_PRINTF("Accel state reached @ %lli\n", (s64a)(b4 - buf));
+ const union AccelAux *aaux = get_accel(s, a4 & SHENG_STATE_MASK);
+ const u8 *new_offset = run_accel(aaux, cur_buf + 4, end);
+ if (new_offset < cur_buf + 4 + BAD_ACCEL_DIST) {
+ min_accel_dist = new_offset + BIG_ACCEL_PENALTY;
+ } else {
+ min_accel_dist = new_offset + SMALL_ACCEL_PENALTY;
+ }
+ DEBUG_PRINTF("Next accel chance: %llu\n",
+ (u64a)(min_accel_dist - start));
+ DEBUG_PRINTF("Accel scanned %llu bytes\n",
+ (u64a)(new_offset - cur_buf - 4));
+ cur_buf = new_offset;
+ DEBUG_PRINTF("New offset: %llu\n", (u64a)(cur_buf - buf));
+ continue;
+ };
+ cur_buf += 4;
+ }
+ *state = movd(cur_state);
+ *scan_end = cur_buf;
+ return MO_CONTINUE_MATCHING;
+}
#if defined(HAVE_AVX512VBMI)
static really_inline
diff --git a/contrib/libs/hyperscan/src/nfa/sheng_internal.h b/contrib/libs/hyperscan/src/nfa/sheng_internal.h
index 70fc327a771..98536886c59 100644
--- a/contrib/libs/hyperscan/src/nfa/sheng_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/sheng_internal.h
@@ -1,43 +1,43 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef SHENG_INTERNAL_H_
-#define SHENG_INTERNAL_H_
-
-#include "ue2common.h"
-#include "util/simd_types.h"
-
-#define SHENG_STATE_ACCEPT 0x10
-#define SHENG_STATE_DEAD 0x20
-#define SHENG_STATE_ACCEL 0x40
-#define SHENG_STATE_MASK 0xF
-#define SHENG_STATE_FLAG_MASK 0x70
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef SHENG_INTERNAL_H_
+#define SHENG_INTERNAL_H_
+
+#include "ue2common.h"
+#include "util/simd_types.h"
+
+#define SHENG_STATE_ACCEPT 0x10
+#define SHENG_STATE_DEAD 0x20
+#define SHENG_STATE_ACCEL 0x40
+#define SHENG_STATE_MASK 0xF
+#define SHENG_STATE_FLAG_MASK 0x70
+
#define SHENG32_STATE_ACCEPT 0x20
#define SHENG32_STATE_DEAD 0x40
#define SHENG32_STATE_ACCEL 0x80
@@ -49,35 +49,35 @@
#define SHENG64_STATE_MASK 0x3F
#define SHENG64_STATE_FLAG_MASK 0xC0
-#define SHENG_FLAG_SINGLE_REPORT 0x1
-#define SHENG_FLAG_CAN_DIE 0x2
-#define SHENG_FLAG_HAS_ACCEL 0x4
-
-struct report_list {
- u32 count;
- ReportID report[];
-};
-
-struct sstate_aux {
- u32 accept;
- u32 accept_eod;
- u32 accel;
- u32 top;
-};
-
-struct sheng {
- m128 shuffle_masks[256];
- u32 length;
- u32 aux_offset;
- u32 report_offset;
- u32 accel_offset;
- u8 n_states;
- u8 anchored;
- u8 floating;
- u8 flags;
- ReportID report;
-};
-
+#define SHENG_FLAG_SINGLE_REPORT 0x1
+#define SHENG_FLAG_CAN_DIE 0x2
+#define SHENG_FLAG_HAS_ACCEL 0x4
+
+struct report_list {
+ u32 count;
+ ReportID report[];
+};
+
+struct sstate_aux {
+ u32 accept;
+ u32 accept_eod;
+ u32 accel;
+ u32 top;
+};
+
+struct sheng {
+ m128 shuffle_masks[256];
+ u32 length;
+ u32 aux_offset;
+ u32 report_offset;
+ u32 accel_offset;
+ u8 n_states;
+ u8 anchored;
+ u8 floating;
+ u8 flags;
+ ReportID report;
+};
+
struct sheng32 {
m512 succ_masks[256];
u32 length;
@@ -104,4 +104,4 @@ struct sheng64 {
ReportID report;
};
-#endif /* SHENG_INTERNAL_H_ */
+#endif /* SHENG_INTERNAL_H_ */
diff --git a/contrib/libs/hyperscan/src/nfa/shengcompile.cpp b/contrib/libs/hyperscan/src/nfa/shengcompile.cpp
index 8cc98eea8ad..aa3faeb09d5 100644
--- a/contrib/libs/hyperscan/src/nfa/shengcompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/shengcompile.cpp
@@ -1,306 +1,306 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "shengcompile.h"
-
-#include "accel.h"
-#include "accelcompile.h"
-#include "shufticompile.h"
-#include "trufflecompile.h"
-#include "util/alloc.h"
-#include "util/bitutils.h"
-#include "util/charreach.h"
-#include "util/compare.h"
-#include "util/container.h"
-#include "util/order_check.h"
-#include "util/report_manager.h"
-#include "util/unaligned.h"
-
-#include "grey.h"
-#include "nfa_internal.h"
-#include "sheng_internal.h"
-#include "ue2common.h"
-#include "util/compile_context.h"
-#include "util/make_unique.h"
-#include "util/verify_types.h"
-#include "util/simd_types.h"
-
-#include <map>
-#include <vector>
-#include <sstream>
-
-#include <boost/range/adaptor/map.hpp>
-
-using namespace std;
-using boost::adaptors::map_keys;
-
-namespace ue2 {
-
-#define ACCEL_DFA_MAX_OFFSET_DEPTH 4
-
-/** Maximum tolerated number of escape character from an accel state.
- * This is larger than nfa, as we don't have a budget and the nfa cheats on stop
- * characters for sets of states */
-#define ACCEL_DFA_MAX_STOP_CHAR 160
-
-/** Maximum tolerated number of escape character from a sds accel state. Larger
- * than normal states as accelerating sds is important. Matches NFA value */
-#define ACCEL_DFA_MAX_FLOATING_STOP_CHAR 192
-
-struct dfa_info {
- accel_dfa_build_strat &strat;
- raw_dfa &raw;
- vector<dstate> &states;
- dstate &floating;
- dstate &anchored;
- bool can_die;
-
- explicit dfa_info(accel_dfa_build_strat &s)
- : strat(s), raw(strat.get_raw()), states(raw.states),
- floating(states[raw.start_floating]),
- anchored(states[raw.start_anchored]), can_die(dfaCanDie(raw)) {}
-
- // returns adjusted size
- size_t size() const {
- return can_die ? states.size() : states.size() - 1;
- }
- // expects adjusted index
- dstate &operator[](dstate_id_t idx) {
- return states[raw_id(idx)];
- }
- dstate &top(dstate_id_t idx) {
- if (isDead(idx)) {
- return floating;
- }
- return next(idx, TOP);
- }
- dstate &next(dstate_id_t idx, u16 chr) {
- auto &src = (*this)[idx];
- auto next_id = src.next[raw.alpha_remap[chr]];
- return states[next_id];
- }
- // get original idx from adjusted idx
- dstate_id_t raw_id(dstate_id_t idx) {
- assert(idx < size());
- // if DFA can't die, shift all indices left by 1
- return can_die ? idx : idx + 1;
- }
- bool isDead(dstate &state) {
- return raw_id(state.impl_id) == DEAD_STATE;
- }
- bool isDead(dstate_id_t idx) {
- return raw_id(idx) == DEAD_STATE;
- }
-
-private:
- static bool dfaCanDie(raw_dfa &rdfa) {
- for (unsigned chr = 0; chr < 256; chr++) {
- for (dstate_id_t state = 0; state < rdfa.states.size(); state++) {
- auto succ = rdfa.states[state].next[rdfa.alpha_remap[chr]];
- if (succ == DEAD_STATE) {
- return true;
- }
- }
- }
- return false;
- }
-};
-
-namespace {
-
-struct raw_report_list {
- flat_set<ReportID> reports;
-
- raw_report_list(const flat_set<ReportID> &reports_in,
- const ReportManager &rm, bool do_remap) {
- if (do_remap) {
- for (auto &id : reports_in) {
- reports.insert(rm.getProgramOffset(id));
- }
- } else {
- reports = reports_in;
- }
- }
-
- bool operator<(const raw_report_list &b) const {
- return reports < b.reports;
- }
-};
-
-struct raw_report_info_impl : public raw_report_info {
- vector<raw_report_list> rl;
- u32 getReportListSize() const override;
- size_t size() const override;
- void fillReportLists(NFA *n, size_t base_offset,
- std::vector<u32> &ro /* out */) const override;
-};
-}
-
-u32 raw_report_info_impl::getReportListSize() const {
- u32 rv = 0;
-
- for (const auto &reps : rl) {
- rv += sizeof(report_list);
- rv += sizeof(ReportID) * reps.reports.size();
- }
-
- return rv;
-}
-
-size_t raw_report_info_impl::size() const {
- return rl.size();
-}
-
-void raw_report_info_impl::fillReportLists(NFA *n, size_t base_offset,
- vector<u32> &ro) const {
- for (const auto &reps : rl) {
- ro.push_back(base_offset);
-
- report_list *p = (report_list *)((char *)n + base_offset);
-
- u32 i = 0;
- for (const ReportID report : reps.reports) {
- p->report[i++] = report;
- }
- p->count = verify_u32(reps.reports.size());
-
- base_offset += sizeof(report_list);
- base_offset += sizeof(ReportID) * reps.reports.size();
- }
-}
-
-unique_ptr<raw_report_info> sheng_build_strat::gatherReports(
- vector<u32> &reports,
- vector<u32> &reports_eod,
- u8 *isSingleReport,
- ReportID *arbReport) const {
- DEBUG_PRINTF("gathering reports\n");
-
- const bool remap_reports = has_managed_reports(rdfa.kind);
-
- auto ri = ue2::make_unique<raw_report_info_impl>();
- map<raw_report_list, u32> rev;
-
- for (const dstate &s : rdfa.states) {
- if (s.reports.empty()) {
- reports.push_back(MO_INVALID_IDX);
- continue;
- }
-
- raw_report_list rrl(s.reports, rm, remap_reports);
- DEBUG_PRINTF("non empty r\n");
- if (rev.find(rrl) != rev.end()) {
- reports.push_back(rev[rrl]);
- } else {
- DEBUG_PRINTF("adding to rl %zu\n", ri->size());
- rev[rrl] = ri->size();
- reports.push_back(ri->size());
- ri->rl.push_back(rrl);
- }
- }
-
- for (const dstate &s : rdfa.states) {
- if (s.reports_eod.empty()) {
- reports_eod.push_back(MO_INVALID_IDX);
- continue;
- }
-
- DEBUG_PRINTF("non empty r eod\n");
- raw_report_list rrl(s.reports_eod, rm, remap_reports);
- if (rev.find(rrl) != rev.end()) {
- reports_eod.push_back(rev[rrl]);
- continue;
- }
-
- DEBUG_PRINTF("adding to rl eod %zu\n", s.reports_eod.size());
- rev[rrl] = ri->size();
- reports_eod.push_back(ri->size());
- ri->rl.push_back(rrl);
- }
-
- assert(!ri->rl.empty()); /* all components should be able to generate
- reports */
- if (!ri->rl.empty()) {
- *arbReport = *ri->rl.begin()->reports.begin();
- } else {
- *arbReport = 0;
- }
-
- /* if we have only a single report id generated from all accepts (not eod)
- * we can take some short cuts */
- set<ReportID> reps;
-
- for (u32 rl_index : reports) {
- if (rl_index == MO_INVALID_IDX) {
- continue;
- }
- assert(rl_index < ri->size());
- insert(&reps, ri->rl[rl_index].reports);
- }
-
- if (reps.size() == 1) {
- *isSingleReport = 1;
- *arbReport = *reps.begin();
- DEBUG_PRINTF("single -- %u\n", *arbReport);
- } else {
- *isSingleReport = 0;
- }
-
- return move(ri);
-}
-
-u32 sheng_build_strat::max_allowed_offset_accel() const {
- return ACCEL_DFA_MAX_OFFSET_DEPTH;
-}
-
-u32 sheng_build_strat::max_stop_char() const {
- return ACCEL_DFA_MAX_STOP_CHAR;
-}
-
-u32 sheng_build_strat::max_floating_stop_char() const {
- return ACCEL_DFA_MAX_FLOATING_STOP_CHAR;
-}
-
-size_t sheng_build_strat::accelSize() const {
- return sizeof(AccelAux);
-}
-
-#ifdef DEBUG
-static really_inline
-void dumpShuffleMask(const u8 chr, const u8 *buf, unsigned sz) {
- stringstream o;
-
- for (unsigned i = 0; i < sz; i++) {
- o.width(2);
- o << (buf[i] & SHENG_STATE_MASK) << " ";
- }
- DEBUG_PRINTF("chr %3u: %s\n", chr, o.str().c_str());
-}
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "shengcompile.h"
+
+#include "accel.h"
+#include "accelcompile.h"
+#include "shufticompile.h"
+#include "trufflecompile.h"
+#include "util/alloc.h"
+#include "util/bitutils.h"
+#include "util/charreach.h"
+#include "util/compare.h"
+#include "util/container.h"
+#include "util/order_check.h"
+#include "util/report_manager.h"
+#include "util/unaligned.h"
+
+#include "grey.h"
+#include "nfa_internal.h"
+#include "sheng_internal.h"
+#include "ue2common.h"
+#include "util/compile_context.h"
+#include "util/make_unique.h"
+#include "util/verify_types.h"
+#include "util/simd_types.h"
+
+#include <map>
+#include <vector>
+#include <sstream>
+
+#include <boost/range/adaptor/map.hpp>
+
+using namespace std;
+using boost::adaptors::map_keys;
+
+namespace ue2 {
+
+#define ACCEL_DFA_MAX_OFFSET_DEPTH 4
+
+/** Maximum tolerated number of escape character from an accel state.
+ * This is larger than nfa, as we don't have a budget and the nfa cheats on stop
+ * characters for sets of states */
+#define ACCEL_DFA_MAX_STOP_CHAR 160
+
+/** Maximum tolerated number of escape character from a sds accel state. Larger
+ * than normal states as accelerating sds is important. Matches NFA value */
+#define ACCEL_DFA_MAX_FLOATING_STOP_CHAR 192
+
+struct dfa_info {
+ accel_dfa_build_strat &strat;
+ raw_dfa &raw;
+ vector<dstate> &states;
+ dstate &floating;
+ dstate &anchored;
+ bool can_die;
+
+ explicit dfa_info(accel_dfa_build_strat &s)
+ : strat(s), raw(strat.get_raw()), states(raw.states),
+ floating(states[raw.start_floating]),
+ anchored(states[raw.start_anchored]), can_die(dfaCanDie(raw)) {}
+
+ // returns adjusted size
+ size_t size() const {
+ return can_die ? states.size() : states.size() - 1;
+ }
+ // expects adjusted index
+ dstate &operator[](dstate_id_t idx) {
+ return states[raw_id(idx)];
+ }
+ dstate &top(dstate_id_t idx) {
+ if (isDead(idx)) {
+ return floating;
+ }
+ return next(idx, TOP);
+ }
+ dstate &next(dstate_id_t idx, u16 chr) {
+ auto &src = (*this)[idx];
+ auto next_id = src.next[raw.alpha_remap[chr]];
+ return states[next_id];
+ }
+ // get original idx from adjusted idx
+ dstate_id_t raw_id(dstate_id_t idx) {
+ assert(idx < size());
+ // if DFA can't die, shift all indices left by 1
+ return can_die ? idx : idx + 1;
+ }
+ bool isDead(dstate &state) {
+ return raw_id(state.impl_id) == DEAD_STATE;
+ }
+ bool isDead(dstate_id_t idx) {
+ return raw_id(idx) == DEAD_STATE;
+ }
+
+private:
+ static bool dfaCanDie(raw_dfa &rdfa) {
+ for (unsigned chr = 0; chr < 256; chr++) {
+ for (dstate_id_t state = 0; state < rdfa.states.size(); state++) {
+ auto succ = rdfa.states[state].next[rdfa.alpha_remap[chr]];
+ if (succ == DEAD_STATE) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+};
+
+namespace {
+
+struct raw_report_list {
+ flat_set<ReportID> reports;
+
+ raw_report_list(const flat_set<ReportID> &reports_in,
+ const ReportManager &rm, bool do_remap) {
+ if (do_remap) {
+ for (auto &id : reports_in) {
+ reports.insert(rm.getProgramOffset(id));
+ }
+ } else {
+ reports = reports_in;
+ }
+ }
+
+ bool operator<(const raw_report_list &b) const {
+ return reports < b.reports;
+ }
+};
+
+struct raw_report_info_impl : public raw_report_info {
+ vector<raw_report_list> rl;
+ u32 getReportListSize() const override;
+ size_t size() const override;
+ void fillReportLists(NFA *n, size_t base_offset,
+ std::vector<u32> &ro /* out */) const override;
+};
+}
+
+u32 raw_report_info_impl::getReportListSize() const {
+ u32 rv = 0;
+
+ for (const auto &reps : rl) {
+ rv += sizeof(report_list);
+ rv += sizeof(ReportID) * reps.reports.size();
+ }
+
+ return rv;
+}
+
+size_t raw_report_info_impl::size() const {
+ return rl.size();
+}
+
+void raw_report_info_impl::fillReportLists(NFA *n, size_t base_offset,
+ vector<u32> &ro) const {
+ for (const auto &reps : rl) {
+ ro.push_back(base_offset);
+
+ report_list *p = (report_list *)((char *)n + base_offset);
+
+ u32 i = 0;
+ for (const ReportID report : reps.reports) {
+ p->report[i++] = report;
+ }
+ p->count = verify_u32(reps.reports.size());
+
+ base_offset += sizeof(report_list);
+ base_offset += sizeof(ReportID) * reps.reports.size();
+ }
+}
+
+unique_ptr<raw_report_info> sheng_build_strat::gatherReports(
+ vector<u32> &reports,
+ vector<u32> &reports_eod,
+ u8 *isSingleReport,
+ ReportID *arbReport) const {
+ DEBUG_PRINTF("gathering reports\n");
+
+ const bool remap_reports = has_managed_reports(rdfa.kind);
+
+ auto ri = ue2::make_unique<raw_report_info_impl>();
+ map<raw_report_list, u32> rev;
+
+ for (const dstate &s : rdfa.states) {
+ if (s.reports.empty()) {
+ reports.push_back(MO_INVALID_IDX);
+ continue;
+ }
+
+ raw_report_list rrl(s.reports, rm, remap_reports);
+ DEBUG_PRINTF("non empty r\n");
+ if (rev.find(rrl) != rev.end()) {
+ reports.push_back(rev[rrl]);
+ } else {
+ DEBUG_PRINTF("adding to rl %zu\n", ri->size());
+ rev[rrl] = ri->size();
+ reports.push_back(ri->size());
+ ri->rl.push_back(rrl);
+ }
+ }
+
+ for (const dstate &s : rdfa.states) {
+ if (s.reports_eod.empty()) {
+ reports_eod.push_back(MO_INVALID_IDX);
+ continue;
+ }
+
+ DEBUG_PRINTF("non empty r eod\n");
+ raw_report_list rrl(s.reports_eod, rm, remap_reports);
+ if (rev.find(rrl) != rev.end()) {
+ reports_eod.push_back(rev[rrl]);
+ continue;
+ }
+
+ DEBUG_PRINTF("adding to rl eod %zu\n", s.reports_eod.size());
+ rev[rrl] = ri->size();
+ reports_eod.push_back(ri->size());
+ ri->rl.push_back(rrl);
+ }
+
+ assert(!ri->rl.empty()); /* all components should be able to generate
+ reports */
+ if (!ri->rl.empty()) {
+ *arbReport = *ri->rl.begin()->reports.begin();
+ } else {
+ *arbReport = 0;
+ }
+
+ /* if we have only a single report id generated from all accepts (not eod)
+ * we can take some short cuts */
+ set<ReportID> reps;
+
+ for (u32 rl_index : reports) {
+ if (rl_index == MO_INVALID_IDX) {
+ continue;
+ }
+ assert(rl_index < ri->size());
+ insert(&reps, ri->rl[rl_index].reports);
+ }
+
+ if (reps.size() == 1) {
+ *isSingleReport = 1;
+ *arbReport = *reps.begin();
+ DEBUG_PRINTF("single -- %u\n", *arbReport);
+ } else {
+ *isSingleReport = 0;
+ }
+
+ return move(ri);
+}
+
+u32 sheng_build_strat::max_allowed_offset_accel() const {
+ return ACCEL_DFA_MAX_OFFSET_DEPTH;
+}
+
+u32 sheng_build_strat::max_stop_char() const {
+ return ACCEL_DFA_MAX_STOP_CHAR;
+}
+
+u32 sheng_build_strat::max_floating_stop_char() const {
+ return ACCEL_DFA_MAX_FLOATING_STOP_CHAR;
+}
+
+size_t sheng_build_strat::accelSize() const {
+ return sizeof(AccelAux);
+}
+
+#ifdef DEBUG
+static really_inline
+void dumpShuffleMask(const u8 chr, const u8 *buf, unsigned sz) {
+ stringstream o;
+
+ for (unsigned i = 0; i < sz; i++) {
+ o.width(2);
+ o << (buf[i] & SHENG_STATE_MASK) << " ";
+ }
+ DEBUG_PRINTF("chr %3u: %s\n", chr, o.str().c_str());
+}
static really_inline
void dumpShuffleMask32(const u8 chr, const u8 *buf, unsigned sz) {
@@ -323,18 +323,18 @@ void dumpShuffleMask64(const u8 chr, const u8 *buf, unsigned sz) {
}
DEBUG_PRINTF("chr %3u: %s\n", chr, o.str().c_str());
}
-#endif
-
-static
-void fillAccelOut(const map<dstate_id_t, AccelScheme> &accel_escape_info,
- set<dstate_id_t> *accel_states) {
- for (dstate_id_t i : accel_escape_info | map_keys) {
- accel_states->insert(i);
- }
-}
-
+#endif
+
+static
+void fillAccelOut(const map<dstate_id_t, AccelScheme> &accel_escape_info,
+ set<dstate_id_t> *accel_states) {
+ for (dstate_id_t i : accel_escape_info | map_keys) {
+ accel_states->insert(i);
+ }
+}
+
template <typename T>
-static
+static
u8 getShengState(UNUSED dstate &state, UNUSED dfa_info &info,
UNUSED map<dstate_id_t, AccelScheme> &accelInfo) {
return 0;
@@ -343,19 +343,19 @@ u8 getShengState(UNUSED dstate &state, UNUSED dfa_info &info,
template <>
u8 getShengState<sheng>(dstate &state, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo) {
- u8 s = state.impl_id;
- if (!state.reports.empty()) {
- s |= SHENG_STATE_ACCEPT;
- }
- if (info.isDead(state)) {
- s |= SHENG_STATE_DEAD;
- }
- if (accelInfo.find(info.raw_id(state.impl_id)) != accelInfo.end()) {
- s |= SHENG_STATE_ACCEL;
- }
- return s;
-}
-
+ u8 s = state.impl_id;
+ if (!state.reports.empty()) {
+ s |= SHENG_STATE_ACCEPT;
+ }
+ if (info.isDead(state)) {
+ s |= SHENG_STATE_DEAD;
+ }
+ if (accelInfo.find(info.raw_id(state.impl_id)) != accelInfo.end()) {
+ s |= SHENG_STATE_ACCEL;
+ }
+ return s;
+}
+
template <>
u8 getShengState<sheng32>(dstate &state, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo) {
@@ -386,30 +386,30 @@ u8 getShengState<sheng64>(dstate &state, dfa_info &info,
}
template <typename T>
-static
-void fillAccelAux(struct NFA *n, dfa_info &info,
- map<dstate_id_t, AccelScheme> &accelInfo) {
- DEBUG_PRINTF("Filling accel aux structures\n");
+static
+void fillAccelAux(struct NFA *n, dfa_info &info,
+ map<dstate_id_t, AccelScheme> &accelInfo) {
+ DEBUG_PRINTF("Filling accel aux structures\n");
T *s = (T *)getMutableImplNfa(n);
- u32 offset = s->accel_offset;
-
- for (dstate_id_t i = 0; i < info.size(); i++) {
- dstate_id_t state_id = info.raw_id(i);
- if (accelInfo.find(state_id) != accelInfo.end()) {
- s->flags |= SHENG_FLAG_HAS_ACCEL;
- AccelAux *aux = (AccelAux *)((char *)n + offset);
- info.strat.buildAccel(state_id, accelInfo[state_id], aux);
- sstate_aux *saux =
- (sstate_aux *)((char *)n + s->aux_offset) + state_id;
- saux->accel = offset;
- DEBUG_PRINTF("Accel offset: %u\n", offset);
- offset += ROUNDUP_N(sizeof(AccelAux), alignof(AccelAux));
- }
- }
-}
-
+ u32 offset = s->accel_offset;
+
+ for (dstate_id_t i = 0; i < info.size(); i++) {
+ dstate_id_t state_id = info.raw_id(i);
+ if (accelInfo.find(state_id) != accelInfo.end()) {
+ s->flags |= SHENG_FLAG_HAS_ACCEL;
+ AccelAux *aux = (AccelAux *)((char *)n + offset);
+ info.strat.buildAccel(state_id, accelInfo[state_id], aux);
+ sstate_aux *saux =
+ (sstate_aux *)((char *)n + s->aux_offset) + state_id;
+ saux->accel = offset;
+ DEBUG_PRINTF("Accel offset: %u\n", offset);
+ offset += ROUNDUP_N(sizeof(AccelAux), alignof(AccelAux));
+ }
+ }
+}
+
template <typename T>
-static
+static
void populateBasicInfo(UNUSED struct NFA *n, UNUSED dfa_info &info,
UNUSED map<dstate_id_t, AccelScheme> &accelInfo,
UNUSED u32 aux_offset, UNUSED u32 report_offset,
@@ -423,25 +423,25 @@ void populateBasicInfo<sheng>(struct NFA *n, dfa_info &info,
u32 aux_offset, u32 report_offset,
u32 accel_offset, u32 total_size,
u32 dfa_size) {
- n->length = total_size;
- n->scratchStateSize = 1;
- n->streamStateSize = 1;
- n->nPositions = info.size();
- n->type = SHENG_NFA;
- n->flags |= info.raw.hasEodReports() ? NFA_ACCEPTS_EOD : 0;
-
- sheng *s = (sheng *)getMutableImplNfa(n);
- s->aux_offset = aux_offset;
- s->report_offset = report_offset;
- s->accel_offset = accel_offset;
- s->n_states = info.size();
- s->length = dfa_size;
- s->flags |= info.can_die ? SHENG_FLAG_CAN_DIE : 0;
-
+ n->length = total_size;
+ n->scratchStateSize = 1;
+ n->streamStateSize = 1;
+ n->nPositions = info.size();
+ n->type = SHENG_NFA;
+ n->flags |= info.raw.hasEodReports() ? NFA_ACCEPTS_EOD : 0;
+
+ sheng *s = (sheng *)getMutableImplNfa(n);
+ s->aux_offset = aux_offset;
+ s->report_offset = report_offset;
+ s->accel_offset = accel_offset;
+ s->n_states = info.size();
+ s->length = dfa_size;
+ s->flags |= info.can_die ? SHENG_FLAG_CAN_DIE : 0;
+
s->anchored = getShengState<sheng>(info.anchored, info, accelInfo);
s->floating = getShengState<sheng>(info.floating, info, accelInfo);
-}
-
+}
+
template <>
void populateBasicInfo<sheng32>(struct NFA *n, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo,
@@ -493,65 +493,65 @@ void populateBasicInfo<sheng64>(struct NFA *n, dfa_info &info,
}
template <typename T>
-static
-void fillTops(NFA *n, dfa_info &info, dstate_id_t id,
- map<dstate_id_t, AccelScheme> &accelInfo) {
+static
+void fillTops(NFA *n, dfa_info &info, dstate_id_t id,
+ map<dstate_id_t, AccelScheme> &accelInfo) {
T *s = (T *)getMutableImplNfa(n);
- u32 aux_base = s->aux_offset;
-
- DEBUG_PRINTF("Filling tops for state %u\n", id);
-
- sstate_aux *aux = (sstate_aux *)((char *)n + aux_base) + id;
-
- DEBUG_PRINTF("Aux structure for state %u, offset %zd\n", id,
- (char *)aux - (char *)n);
-
- /* we could conceivably end up in an accept/dead state on a top event,
- * so mark top as accept/dead state if it indeed is.
- */
- auto &top_state = info.top(id);
-
- DEBUG_PRINTF("Top transition for state %u: %u\n", id, top_state.impl_id);
-
+ u32 aux_base = s->aux_offset;
+
+ DEBUG_PRINTF("Filling tops for state %u\n", id);
+
+ sstate_aux *aux = (sstate_aux *)((char *)n + aux_base) + id;
+
+ DEBUG_PRINTF("Aux structure for state %u, offset %zd\n", id,
+ (char *)aux - (char *)n);
+
+ /* we could conceivably end up in an accept/dead state on a top event,
+ * so mark top as accept/dead state if it indeed is.
+ */
+ auto &top_state = info.top(id);
+
+ DEBUG_PRINTF("Top transition for state %u: %u\n", id, top_state.impl_id);
+
aux->top = getShengState<T>(top_state, info, accelInfo);
-}
-
+}
+
template <typename T>
-static
-void fillAux(NFA *n, dfa_info &info, dstate_id_t id, vector<u32> &reports,
- vector<u32> &reports_eod, vector<u32> &report_offsets) {
+static
+void fillAux(NFA *n, dfa_info &info, dstate_id_t id, vector<u32> &reports,
+ vector<u32> &reports_eod, vector<u32> &report_offsets) {
T *s = (T *)getMutableImplNfa(n);
- u32 aux_base = s->aux_offset;
- auto raw_id = info.raw_id(id);
-
- auto &state = info[id];
-
- sstate_aux *aux = (sstate_aux *)((char *)n + aux_base) + id;
-
- DEBUG_PRINTF("Filling aux and report structures for state %u\n", id);
- DEBUG_PRINTF("Aux structure for state %u, offset %zd\n", id,
- (char *)aux - (char *)n);
-
- aux->accept = state.reports.empty() ? 0 : report_offsets[reports[raw_id]];
- aux->accept_eod =
- state.reports_eod.empty() ? 0 : report_offsets[reports_eod[raw_id]];
-
- DEBUG_PRINTF("Report list offset: %u\n", aux->accept);
- DEBUG_PRINTF("EOD report list offset: %u\n", aux->accept_eod);
-}
-
+ u32 aux_base = s->aux_offset;
+ auto raw_id = info.raw_id(id);
+
+ auto &state = info[id];
+
+ sstate_aux *aux = (sstate_aux *)((char *)n + aux_base) + id;
+
+ DEBUG_PRINTF("Filling aux and report structures for state %u\n", id);
+ DEBUG_PRINTF("Aux structure for state %u, offset %zd\n", id,
+ (char *)aux - (char *)n);
+
+ aux->accept = state.reports.empty() ? 0 : report_offsets[reports[raw_id]];
+ aux->accept_eod =
+ state.reports_eod.empty() ? 0 : report_offsets[reports_eod[raw_id]];
+
+ DEBUG_PRINTF("Report list offset: %u\n", aux->accept);
+ DEBUG_PRINTF("EOD report list offset: %u\n", aux->accept_eod);
+}
+
template <typename T>
-static
-void fillSingleReport(NFA *n, ReportID r_id) {
+static
+void fillSingleReport(NFA *n, ReportID r_id) {
T *s = (T *)getMutableImplNfa(n);
-
- DEBUG_PRINTF("Single report ID: %u\n", r_id);
- s->report = r_id;
- s->flags |= SHENG_FLAG_SINGLE_REPORT;
-}
-
+
+ DEBUG_PRINTF("Single report ID: %u\n", r_id);
+ s->report = r_id;
+ s->flags |= SHENG_FLAG_SINGLE_REPORT;
+}
+
template <typename T>
-static
+static
bool createShuffleMasks(UNUSED T *s, UNUSED dfa_info &info,
UNUSED map<dstate_id_t, AccelScheme> &accelInfo) {
return true;
@@ -560,28 +560,28 @@ bool createShuffleMasks(UNUSED T *s, UNUSED dfa_info &info,
template <>
bool createShuffleMasks<sheng>(sheng *s, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo) {
- for (u16 chr = 0; chr < 256; chr++) {
- u8 buf[16] = {0};
-
- for (dstate_id_t idx = 0; idx < info.size(); idx++) {
- auto &succ_state = info.next(idx, chr);
-
+ for (u16 chr = 0; chr < 256; chr++) {
+ u8 buf[16] = {0};
+
+ for (dstate_id_t idx = 0; idx < info.size(); idx++) {
+ auto &succ_state = info.next(idx, chr);
+
buf[idx] = getShengState<sheng>(succ_state, info, accelInfo);
- }
-#ifdef DEBUG
- dumpShuffleMask(chr, buf, sizeof(buf));
-#endif
- memcpy(&s->shuffle_masks[chr], buf, sizeof(m128));
- }
+ }
+#ifdef DEBUG
+ dumpShuffleMask(chr, buf, sizeof(buf));
+#endif
+ memcpy(&s->shuffle_masks[chr], buf, sizeof(m128));
+ }
return true;
-}
-
+}
+
template <>
bool createShuffleMasks<sheng32>(sheng32 *s, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo) {
for (u16 chr = 0; chr < 256; chr++) {
u8 buf[64] = {0};
-
+
assert(info.size() <= 32);
for (dstate_id_t idx = 0; idx < info.size(); idx++) {
auto &succ_state = info.next(idx, chr);
@@ -593,20 +593,20 @@ bool createShuffleMasks<sheng32>(sheng32 *s, dfa_info &info,
dumpShuffleMask32(chr, buf, sizeof(buf));
#endif
memcpy(&s->succ_masks[chr], buf, sizeof(m512));
- }
+ }
return true;
}
-
+
template <>
bool createShuffleMasks<sheng64>(sheng64 *s, dfa_info &info,
map<dstate_id_t, AccelScheme> &accelInfo) {
for (u16 chr = 0; chr < 256; chr++) {
u8 buf[64] = {0};
-
+
assert(info.size() <= 64);
for (dstate_id_t idx = 0; idx < info.size(); idx++) {
auto &succ_state = info.next(idx, chr);
-
+
if (accelInfo.find(info.raw_id(succ_state.impl_id))
!= accelInfo.end()) {
return false;
@@ -617,10 +617,10 @@ bool createShuffleMasks<sheng64>(sheng64 *s, dfa_info &info,
dumpShuffleMask64(chr, buf, sizeof(buf));
#endif
memcpy(&s->succ_masks[chr], buf, sizeof(m512));
- }
+ }
return true;
}
-
+
bool has_accel_sheng(const NFA *) {
return true; /* consider the sheng region as accelerated */
}
@@ -631,72 +631,72 @@ bytecode_ptr<NFA> shengCompile_int(raw_dfa &raw, const CompileContext &cc,
set<dstate_id_t> *accel_states,
sheng_build_strat &strat,
dfa_info &info) {
- if (!cc.streaming) { /* TODO: work out if we can do the strip in streaming
- * mode with our semantics */
- raw.stripExtraEodReports();
- }
- auto accelInfo = strat.getAccelInfo(cc.grey);
-
- // set impl_id of each dfa state
- for (dstate_id_t i = 0; i < info.size(); i++) {
- info[i].impl_id = i;
- }
-
- DEBUG_PRINTF("Anchored start state: %u, floating start state: %u\n",
- info.anchored.impl_id, info.floating.impl_id);
-
+ if (!cc.streaming) { /* TODO: work out if we can do the strip in streaming
+ * mode with our semantics */
+ raw.stripExtraEodReports();
+ }
+ auto accelInfo = strat.getAccelInfo(cc.grey);
+
+ // set impl_id of each dfa state
+ for (dstate_id_t i = 0; i < info.size(); i++) {
+ info[i].impl_id = i;
+ }
+
+ DEBUG_PRINTF("Anchored start state: %u, floating start state: %u\n",
+ info.anchored.impl_id, info.floating.impl_id);
+
u32 nfa_size = ROUNDUP_16(sizeof(NFA) + sizeof(T));
- vector<u32> reports, eod_reports, report_offsets;
- u8 isSingle = 0;
- ReportID single_report = 0;
-
- auto ri =
- strat.gatherReports(reports, eod_reports, &isSingle, &single_report);
-
- u32 total_aux = sizeof(sstate_aux) * info.size();
- u32 total_accel = strat.accelSize() * accelInfo.size();
- u32 total_reports = ri->getReportListSize();
-
- u32 reports_offset = nfa_size + total_aux;
- u32 accel_offset =
- ROUNDUP_N(reports_offset + total_reports, alignof(AccelAux));
- u32 total_size = ROUNDUP_N(accel_offset + total_accel, 64);
-
- DEBUG_PRINTF("NFA: %u, aux: %u, reports: %u, accel: %u, total: %u\n",
- nfa_size, total_aux, total_reports, total_accel, total_size);
-
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
-
+ vector<u32> reports, eod_reports, report_offsets;
+ u8 isSingle = 0;
+ ReportID single_report = 0;
+
+ auto ri =
+ strat.gatherReports(reports, eod_reports, &isSingle, &single_report);
+
+ u32 total_aux = sizeof(sstate_aux) * info.size();
+ u32 total_accel = strat.accelSize() * accelInfo.size();
+ u32 total_reports = ri->getReportListSize();
+
+ u32 reports_offset = nfa_size + total_aux;
+ u32 accel_offset =
+ ROUNDUP_N(reports_offset + total_reports, alignof(AccelAux));
+ u32 total_size = ROUNDUP_N(accel_offset + total_accel, 64);
+
+ DEBUG_PRINTF("NFA: %u, aux: %u, reports: %u, accel: %u, total: %u\n",
+ nfa_size, total_aux, total_reports, total_accel, total_size);
+
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+
populateBasicInfo<T>(nfa.get(), info, accelInfo, nfa_size,
reports_offset, accel_offset, total_size,
total_size - sizeof(NFA));
-
- DEBUG_PRINTF("Setting up aux and report structures\n");
-
- ri->fillReportLists(nfa.get(), reports_offset, report_offsets);
-
- for (dstate_id_t idx = 0; idx < info.size(); idx++) {
+
+ DEBUG_PRINTF("Setting up aux and report structures\n");
+
+ ri->fillReportLists(nfa.get(), reports_offset, report_offsets);
+
+ for (dstate_id_t idx = 0; idx < info.size(); idx++) {
fillTops<T>(nfa.get(), info, idx, accelInfo);
fillAux<T>(nfa.get(), info, idx, reports, eod_reports,
report_offsets);
- }
- if (isSingle) {
+ }
+ if (isSingle) {
fillSingleReport<T>(nfa.get(), single_report);
- }
-
+ }
+
fillAccelAux<T>(nfa.get(), info, accelInfo);
-
- if (accel_states) {
- fillAccelOut(accelInfo, accel_states);
- }
-
+
+ if (accel_states) {
+ fillAccelOut(accelInfo, accel_states);
+ }
+
if (!createShuffleMasks<T>((T *)getMutableImplNfa(nfa.get()), info, accelInfo)) {
return nullptr;
}
-
- return nfa;
-}
-
+
+ return nfa;
+}
+
bytecode_ptr<NFA> shengCompile(raw_dfa &raw, const CompileContext &cc,
const ReportManager &rm, bool only_accel_init,
set<dstate_id_t> *accel_states) {
@@ -792,4 +792,4 @@ bytecode_ptr<NFA> sheng64Compile(raw_dfa &raw, const CompileContext &cc,
return nfa;
}
-} // namespace ue2
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfa/shengcompile.h b/contrib/libs/hyperscan/src/nfa/shengcompile.h
index 30ed0d68a63..256f4a4e504 100644
--- a/contrib/libs/hyperscan/src/nfa/shengcompile.h
+++ b/contrib/libs/hyperscan/src/nfa/shengcompile.h
@@ -1,76 +1,76 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef SHENGCOMPILE_H
-#define SHENGCOMPILE_H
-
-#include "accel_dfa_build_strat.h"
-#include "rdfa.h"
-#include "util/bytecode_ptr.h"
-#include "util/charreach.h"
-#include "util/flat_containers.h"
-
-#include <memory>
-#include <set>
-
-struct NFA;
-
-namespace ue2 {
-
-class ReportManager;
-struct CompileContext;
-struct raw_dfa;
-
-class sheng_build_strat : public accel_dfa_build_strat {
-public:
- sheng_build_strat(raw_dfa &rdfa_in, const ReportManager &rm_in,
- bool only_accel_init_in)
- : accel_dfa_build_strat(rm_in, only_accel_init_in), rdfa(rdfa_in) {}
- raw_dfa &get_raw() const override { return rdfa; }
- std::unique_ptr<raw_report_info> gatherReports(
- std::vector<u32> &reports /* out */,
- std::vector<u32> &reports_eod /* out */,
- u8 *isSingleReport /* out */,
- ReportID *arbReport /* out */) const override;
- size_t accelSize(void) const override;
- u32 max_allowed_offset_accel() const override;
- u32 max_stop_char() const override;
- u32 max_floating_stop_char() const override;
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef SHENGCOMPILE_H
+#define SHENGCOMPILE_H
+
+#include "accel_dfa_build_strat.h"
+#include "rdfa.h"
+#include "util/bytecode_ptr.h"
+#include "util/charreach.h"
+#include "util/flat_containers.h"
+
+#include <memory>
+#include <set>
+
+struct NFA;
+
+namespace ue2 {
+
+class ReportManager;
+struct CompileContext;
+struct raw_dfa;
+
+class sheng_build_strat : public accel_dfa_build_strat {
+public:
+ sheng_build_strat(raw_dfa &rdfa_in, const ReportManager &rm_in,
+ bool only_accel_init_in)
+ : accel_dfa_build_strat(rm_in, only_accel_init_in), rdfa(rdfa_in) {}
+ raw_dfa &get_raw() const override { return rdfa; }
+ std::unique_ptr<raw_report_info> gatherReports(
+ std::vector<u32> &reports /* out */,
+ std::vector<u32> &reports_eod /* out */,
+ u8 *isSingleReport /* out */,
+ ReportID *arbReport /* out */) const override;
+ size_t accelSize(void) const override;
+ u32 max_allowed_offset_accel() const override;
+ u32 max_stop_char() const override;
+ u32 max_floating_stop_char() const override;
DfaType getType() const override { return Sheng; }
-
-private:
- raw_dfa &rdfa;
-};
-
-bytecode_ptr<NFA> shengCompile(raw_dfa &raw, const CompileContext &cc,
- const ReportManager &rm, bool only_accel_init,
- std::set<dstate_id_t> *accel_states = nullptr);
-
+
+private:
+ raw_dfa &rdfa;
+};
+
+bytecode_ptr<NFA> shengCompile(raw_dfa &raw, const CompileContext &cc,
+ const ReportManager &rm, bool only_accel_init,
+ std::set<dstate_id_t> *accel_states = nullptr);
+
bytecode_ptr<NFA> sheng32Compile(raw_dfa &raw, const CompileContext &cc,
const ReportManager &rm, bool only_accel_init,
std::set<dstate_id_t> *accel_states = nullptr);
@@ -79,15 +79,15 @@ bytecode_ptr<NFA> sheng64Compile(raw_dfa &raw, const CompileContext &cc,
const ReportManager &rm, bool only_accel_init,
std::set<dstate_id_t> *accel_states = nullptr);
-struct sheng_escape_info {
- CharReach outs;
- CharReach outs2_single;
- flat_set<std::pair<u8, u8>> outs2;
- bool outs2_broken = false;
-};
-
-bool has_accel_sheng(const NFA *nfa);
-
-} // namespace ue2
-
-#endif /* SHENGCOMPILE_H */
+struct sheng_escape_info {
+ CharReach outs;
+ CharReach outs2_single;
+ flat_set<std::pair<u8, u8>> outs2;
+ bool outs2_broken = false;
+};
+
+bool has_accel_sheng(const NFA *nfa);
+
+} // namespace ue2
+
+#endif /* SHENGCOMPILE_H */
diff --git a/contrib/libs/hyperscan/src/nfa/shufti.c b/contrib/libs/hyperscan/src/nfa/shufti.c
index 59138a47989..09ffc0cf9a4 100644
--- a/contrib/libs/hyperscan/src/nfa/shufti.c
+++ b/contrib/libs/hyperscan/src/nfa/shufti.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@
#include "shufti.h"
#include "ue2common.h"
-#include "util/arch.h"
+#include "util/arch.h"
#include "util/bitutils.h"
#include "util/simd_utils.h"
#include "util/unaligned.h"
@@ -71,65 +71,65 @@ void dumpMsk##_t##AsChars(m##_t msk) { \
#endif
-/** \brief Naive byte-by-byte implementation. */
-static really_inline
-const u8 *shuftiFwdSlow(const u8 *lo, const u8 *hi, const u8 *buf,
- const u8 *buf_end) {
- assert(buf < buf_end);
-
- for (; buf < buf_end; ++buf) {
- u8 c = *buf;
- if (lo[c & 0xf] & hi[c >> 4]) {
- break;
- }
- }
- return buf;
-}
-
-/** \brief Naive byte-by-byte implementation. */
-static really_inline
-const u8 *shuftiRevSlow(const u8 *lo, const u8 *hi, const u8 *buf,
- const u8 *buf_end) {
- assert(buf < buf_end);
-
- for (buf_end--; buf_end >= buf; buf_end--) {
- u8 c = *buf_end;
- if (lo[c & 0xf] & hi[c >> 4]) {
- break;
- }
- }
- return buf_end;
-}
-
-#if !defined(HAVE_AVX2)
+/** \brief Naive byte-by-byte implementation. */
+static really_inline
+const u8 *shuftiFwdSlow(const u8 *lo, const u8 *hi, const u8 *buf,
+ const u8 *buf_end) {
+ assert(buf < buf_end);
+
+ for (; buf < buf_end; ++buf) {
+ u8 c = *buf;
+ if (lo[c & 0xf] & hi[c >> 4]) {
+ break;
+ }
+ }
+ return buf;
+}
+
+/** \brief Naive byte-by-byte implementation. */
+static really_inline
+const u8 *shuftiRevSlow(const u8 *lo, const u8 *hi, const u8 *buf,
+ const u8 *buf_end) {
+ assert(buf < buf_end);
+
+ for (buf_end--; buf_end >= buf; buf_end--) {
+ u8 c = *buf_end;
+ if (lo[c & 0xf] & hi[c >> 4]) {
+ break;
+ }
+ }
+ return buf_end;
+}
+
+#if !defined(HAVE_AVX2)
/* Normal SSSE3 shufti */
-#ifdef DEBUG
-DUMP_MSK(128)
-#endif
-
+#ifdef DEBUG
+DUMP_MSK(128)
+#endif
+
#define GET_LO_4(chars) and128(chars, low4bits)
-#define GET_HI_4(chars) rshift64_m128(andnot128(low4bits, chars), 4)
+#define GET_HI_4(chars) rshift64_m128(andnot128(low4bits, chars), 4)
static really_inline
-u32 block(m128 mask_lo, m128 mask_hi, m128 chars, const m128 low4bits,
- const m128 compare) {
- m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(chars));
- m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(chars));
- m128 t = and128(c_lo, c_hi);
-
+u32 block(m128 mask_lo, m128 mask_hi, m128 chars, const m128 low4bits,
+ const m128 compare) {
+ m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(chars));
+ m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(chars));
+ m128 t = and128(c_lo, c_hi);
+
#ifdef DEBUG
- DEBUG_PRINTF(" chars: "); dumpMsk128AsChars(chars); printf("\n");
- DEBUG_PRINTF(" char: "); dumpMsk128(chars); printf("\n");
- DEBUG_PRINTF(" c_lo: "); dumpMsk128(c_lo); printf("\n");
- DEBUG_PRINTF(" c_hi: "); dumpMsk128(c_hi); printf("\n");
- DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
+ DEBUG_PRINTF(" chars: "); dumpMsk128AsChars(chars); printf("\n");
+ DEBUG_PRINTF(" char: "); dumpMsk128(chars); printf("\n");
+ DEBUG_PRINTF(" c_lo: "); dumpMsk128(c_lo); printf("\n");
+ DEBUG_PRINTF(" c_hi: "); dumpMsk128(c_hi); printf("\n");
+ DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
#endif
- return movemask128(eq128(t, compare));
-}
+ return movemask128(eq128(t, compare));
+}
-static really_inline
-const u8 *firstMatch(const u8 *buf, u32 z) {
+static really_inline
+const u8 *firstMatch(const u8 *buf, u32 z) {
if (unlikely(z != 0xffff)) {
u32 pos = ctz32(~z & 0xffff);
assert(pos < 16);
@@ -142,9 +142,9 @@ const u8 *firstMatch(const u8 *buf, u32 z) {
static really_inline
const u8 *fwdBlock(m128 mask_lo, m128 mask_hi, m128 chars, const u8 *buf,
const m128 low4bits, const m128 zeroes) {
- u32 z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
+ u32 z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
- return firstMatch(buf, z);
+ return firstMatch(buf, z);
}
const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
@@ -219,8 +219,8 @@ const u8 *lastMatch(const u8 *buf, m128 t, m128 compare) {
static really_inline
const u8 *revBlock(m128 mask_lo, m128 mask_hi, m128 chars, const u8 *buf,
const m128 low4bits, const m128 zeroes) {
- m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(chars));
- m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(chars));
+ m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(chars));
+ m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(chars));
m128 t = and128(c_lo, c_hi);
#ifdef DEBUG
@@ -289,8 +289,8 @@ const u8 *fwdBlock2(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo, m128 mask2_hi,
const m128 ones) {
m128 chars_lo = GET_LO_4(chars);
m128 chars_hi = GET_HI_4(chars);
- m128 c_lo = pshufb_m128(mask1_lo, chars_lo);
- m128 c_hi = pshufb_m128(mask1_hi, chars_hi);
+ m128 c_lo = pshufb_m128(mask1_lo, chars_lo);
+ m128 c_hi = pshufb_m128(mask1_hi, chars_hi);
m128 t = or128(c_lo, c_hi);
#ifdef DEBUG
@@ -301,9 +301,9 @@ const u8 *fwdBlock2(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo, m128 mask2_hi,
DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
#endif
- m128 c2_lo = pshufb_m128(mask2_lo, chars_lo);
- m128 c2_hi = pshufb_m128(mask2_hi, chars_hi);
- m128 t2 = or128(t, rshiftbyte_m128(or128(c2_lo, c2_hi), 1));
+ m128 c2_lo = pshufb_m128(mask2_lo, chars_lo);
+ m128 c2_hi = pshufb_m128(mask2_hi, chars_hi);
+ m128 t2 = or128(t, rshiftbyte_m128(or128(c2_lo, c2_hi), 1));
#ifdef DEBUG
DEBUG_PRINTF(" c2_lo: "); dumpMsk128(c2_lo); printf("\n");
@@ -311,9 +311,9 @@ const u8 *fwdBlock2(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo, m128 mask2_hi,
DEBUG_PRINTF(" t2: "); dumpMsk128(t2); printf("\n");
#endif
- u32 z = movemask128(eq128(t2, ones));
- DEBUG_PRINTF(" z: 0x%08x\n", z);
- return firstMatch(buf, z);
+ u32 z = movemask128(eq128(t2, ones));
+ DEBUG_PRINTF(" z: 0x%08x\n", z);
+ return firstMatch(buf, z);
}
const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
@@ -360,41 +360,41 @@ const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
return buf_end;
}
-#elif !defined(HAVE_AVX512)
-// AVX2 - 256 wide shuftis
+#elif !defined(HAVE_AVX512)
+// AVX2 - 256 wide shuftis
#ifdef DEBUG
DUMP_MSK(256)
#endif
#define GET_LO_4(chars) and256(chars, low4bits)
-#define GET_HI_4(chars) rshift64_m256(andnot256(low4bits, chars), 4)
+#define GET_HI_4(chars) rshift64_m256(andnot256(low4bits, chars), 4)
static really_inline
-u32 block(m256 mask_lo, m256 mask_hi, m256 chars, const m256 low4bits,
- const m256 compare) {
- m256 c_lo = pshufb_m256(mask_lo, GET_LO_4(chars));
- m256 c_hi = pshufb_m256(mask_hi, GET_HI_4(chars));
- m256 t = and256(c_lo, c_hi);
-
+u32 block(m256 mask_lo, m256 mask_hi, m256 chars, const m256 low4bits,
+ const m256 compare) {
+ m256 c_lo = pshufb_m256(mask_lo, GET_LO_4(chars));
+ m256 c_hi = pshufb_m256(mask_hi, GET_HI_4(chars));
+ m256 t = and256(c_lo, c_hi);
+
#ifdef DEBUG
- DEBUG_PRINTF(" chars: "); dumpMsk256AsChars(chars); printf("\n");
- DEBUG_PRINTF(" char: "); dumpMsk256(chars); printf("\n");
- DEBUG_PRINTF(" c_lo: "); dumpMsk256(c_lo); printf("\n");
- DEBUG_PRINTF(" c_hi: "); dumpMsk256(c_hi); printf("\n");
- DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
+ DEBUG_PRINTF(" chars: "); dumpMsk256AsChars(chars); printf("\n");
+ DEBUG_PRINTF(" char: "); dumpMsk256(chars); printf("\n");
+ DEBUG_PRINTF(" c_lo: "); dumpMsk256(c_lo); printf("\n");
+ DEBUG_PRINTF(" c_hi: "); dumpMsk256(c_hi); printf("\n");
+ DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
#endif
- return movemask256(eq256(t, compare));
-}
-
-static really_inline
-const u8 *firstMatch(const u8 *buf, u32 z) {
- DEBUG_PRINTF("z 0x%08x\n", z);
+ return movemask256(eq256(t, compare));
+}
+
+static really_inline
+const u8 *firstMatch(const u8 *buf, u32 z) {
+ DEBUG_PRINTF("z 0x%08x\n", z);
if (unlikely(z != 0xffffffff)) {
u32 pos = ctz32(~z);
assert(pos < 32);
- DEBUG_PRINTF("match @ pos %u\n", pos);
+ DEBUG_PRINTF("match @ pos %u\n", pos);
return buf + pos;
} else {
return NULL; // no match
@@ -402,44 +402,44 @@ const u8 *firstMatch(const u8 *buf, u32 z) {
}
static really_inline
-const u8 *fwdBlockShort(m256 mask, m128 chars, const u8 *buf,
- const m256 low4bits) {
- // do the hi and lo shuffles in the one avx register
- m256 c = combine2x128(rshift64_m128(chars, 4), chars);
- c = and256(c, low4bits);
- m256 c_shuf = pshufb_m256(mask, c);
- m128 t = and128(movdq_hi(c_shuf), cast256to128(c_shuf));
- // the upper 32-bits can't match
- u32 z = 0xffff0000U | movemask128(eq128(t, zeroes128()));
-
- return firstMatch(buf, z);
-}
-
-static really_inline
-const u8 *shuftiFwdShort(m128 mask_lo, m128 mask_hi, const u8 *buf,
- const u8 *buf_end, const m256 low4bits) {
- // run shufti over two overlapping 16-byte unaligned reads
- const m256 mask = combine2x128(mask_hi, mask_lo);
- m128 chars = loadu128(buf);
- const u8 *rv = fwdBlockShort(mask, chars, buf, low4bits);
- if (rv) {
- return rv;
- }
-
- chars = loadu128(buf_end - 16);
- rv = fwdBlockShort(mask, chars, buf_end - 16, low4bits);
- if (rv) {
- return rv;
- }
- return buf_end;
-}
-
-static really_inline
+const u8 *fwdBlockShort(m256 mask, m128 chars, const u8 *buf,
+ const m256 low4bits) {
+ // do the hi and lo shuffles in the one avx register
+ m256 c = combine2x128(rshift64_m128(chars, 4), chars);
+ c = and256(c, low4bits);
+ m256 c_shuf = pshufb_m256(mask, c);
+ m128 t = and128(movdq_hi(c_shuf), cast256to128(c_shuf));
+ // the upper 32-bits can't match
+ u32 z = 0xffff0000U | movemask128(eq128(t, zeroes128()));
+
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *shuftiFwdShort(m128 mask_lo, m128 mask_hi, const u8 *buf,
+ const u8 *buf_end, const m256 low4bits) {
+ // run shufti over two overlapping 16-byte unaligned reads
+ const m256 mask = combine2x128(mask_hi, mask_lo);
+ m128 chars = loadu128(buf);
+ const u8 *rv = fwdBlockShort(mask, chars, buf, low4bits);
+ if (rv) {
+ return rv;
+ }
+
+ chars = loadu128(buf_end - 16);
+ rv = fwdBlockShort(mask, chars, buf_end - 16, low4bits);
+ if (rv) {
+ return rv;
+ }
+ return buf_end;
+}
+
+static really_inline
const u8 *fwdBlock(m256 mask_lo, m256 mask_hi, m256 chars, const u8 *buf,
const m256 low4bits, const m256 zeroes) {
- u32 z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
+ u32 z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
- return firstMatch(buf, z);
+ return firstMatch(buf, z);
}
/* takes 128 bit masks, but operates on 256 bits of data */
@@ -447,20 +447,20 @@ const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
const u8 *buf_end) {
assert(buf && buf_end);
assert(buf < buf_end);
- DEBUG_PRINTF("shufti %p len %zu\n", buf, buf_end - buf);
+ DEBUG_PRINTF("shufti %p len %zu\n", buf, buf_end - buf);
// Slow path for small cases.
- if (buf_end - buf < 16) {
+ if (buf_end - buf < 16) {
return shuftiFwdSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
buf, buf_end);
}
- const m256 low4bits = set32x8(0xf);
-
- if (buf_end - buf <= 32) {
- return shuftiFwdShort(mask_lo, mask_hi, buf, buf_end, low4bits);
- }
-
+ const m256 low4bits = set32x8(0xf);
+
+ if (buf_end - buf <= 32) {
+ return shuftiFwdShort(mask_lo, mask_hi, buf, buf_end, low4bits);
+ }
+
const m256 zeroes = zeroes256();
const m256 wide_mask_lo = set2x128(mask_lo);
const m256 wide_mask_hi = set2x128(mask_hi);
@@ -503,7 +503,7 @@ const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
}
static really_inline
-const u8 *lastMatch(const u8 *buf, u32 z) {
+const u8 *lastMatch(const u8 *buf, u32 z) {
if (unlikely(z != 0xffffffff)) {
u32 pos = clz32(~z);
DEBUG_PRINTF("buf=%p, pos=%u\n", buf, pos);
@@ -516,8 +516,8 @@ const u8 *lastMatch(const u8 *buf, u32 z) {
static really_inline
const u8 *revBlock(m256 mask_lo, m256 mask_hi, m256 chars, const u8 *buf,
const m256 low4bits, const m256 zeroes) {
- m256 c_lo = pshufb_m256(mask_lo, GET_LO_4(chars));
- m256 c_hi = pshufb_m256(mask_hi, GET_HI_4(chars));
+ m256 c_lo = pshufb_m256(mask_lo, GET_LO_4(chars));
+ m256 c_hi = pshufb_m256(mask_hi, GET_HI_4(chars));
m256 t = and256(c_lo, c_hi);
#ifdef DEBUG
@@ -528,45 +528,45 @@ const u8 *revBlock(m256 mask_lo, m256 mask_hi, m256 chars, const u8 *buf,
DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
#endif
- u32 z = movemask256(eq256(t, zeroes));
- return lastMatch(buf, z);
+ u32 z = movemask256(eq256(t, zeroes));
+ return lastMatch(buf, z);
+}
+
+static really_inline
+const u8 *revBlockShort(m256 mask, m128 chars, const u8 *buf,
+ const m256 low4bits) {
+ // do the hi and lo shuffles in the one avx register
+ m256 c = combine2x128(rshift64_m128(chars, 4), chars);
+ c = and256(c, low4bits);
+ m256 c_shuf = pshufb_m256(mask, c);
+ m128 t = and128(movdq_hi(c_shuf), cast256to128(c_shuf));
+ // the upper 32-bits can't match
+ u32 z = 0xffff0000U | movemask128(eq128(t, zeroes128()));
+
+ return lastMatch(buf, z);
+}
+
+static really_inline
+const u8 *shuftiRevShort(m128 mask_lo, m128 mask_hi, const u8 *buf,
+ const u8 *buf_end, const m256 low4bits) {
+ // run shufti over two overlapping 16-byte unaligned reads
+ const m256 mask = combine2x128(mask_hi, mask_lo);
+
+ m128 chars = loadu128(buf_end - 16);
+ const u8 *rv = revBlockShort(mask, chars, buf_end - 16, low4bits);
+ if (rv) {
+ return rv;
+ }
+
+ chars = loadu128(buf);
+ rv = revBlockShort(mask, chars, buf, low4bits);
+ if (rv) {
+ return rv;
+ }
+ return buf - 1;
}
-static really_inline
-const u8 *revBlockShort(m256 mask, m128 chars, const u8 *buf,
- const m256 low4bits) {
- // do the hi and lo shuffles in the one avx register
- m256 c = combine2x128(rshift64_m128(chars, 4), chars);
- c = and256(c, low4bits);
- m256 c_shuf = pshufb_m256(mask, c);
- m128 t = and128(movdq_hi(c_shuf), cast256to128(c_shuf));
- // the upper 32-bits can't match
- u32 z = 0xffff0000U | movemask128(eq128(t, zeroes128()));
-
- return lastMatch(buf, z);
-}
-
-static really_inline
-const u8 *shuftiRevShort(m128 mask_lo, m128 mask_hi, const u8 *buf,
- const u8 *buf_end, const m256 low4bits) {
- // run shufti over two overlapping 16-byte unaligned reads
- const m256 mask = combine2x128(mask_hi, mask_lo);
-
- m128 chars = loadu128(buf_end - 16);
- const u8 *rv = revBlockShort(mask, chars, buf_end - 16, low4bits);
- if (rv) {
- return rv;
- }
-
- chars = loadu128(buf);
- rv = revBlockShort(mask, chars, buf, low4bits);
- if (rv) {
- return rv;
- }
- return buf - 1;
-}
-
-
+
/* takes 128 bit masks, but operates on 256 bits of data */
const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
const u8 *buf_end) {
@@ -574,17 +574,17 @@ const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
assert(buf < buf_end);
// Slow path for small cases.
- if (buf_end - buf < 16) {
+ if (buf_end - buf < 16) {
return shuftiRevSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
buf, buf_end);
}
- const m256 low4bits = set32x8(0xf);
-
- if (buf_end - buf <= 32) {
- return shuftiRevShort(mask_lo, mask_hi, buf, buf_end, low4bits);
- }
-
+ const m256 low4bits = set32x8(0xf);
+
+ if (buf_end - buf <= 32) {
+ return shuftiRevShort(mask_lo, mask_hi, buf, buf_end, low4bits);
+ }
+
const m256 zeroes = zeroes256();
const m256 wide_mask_lo = set2x128(mask_lo);
const m256 wide_mask_hi = set2x128(mask_hi);
@@ -630,8 +630,8 @@ const u8 *fwdBlock2(m256 mask1_lo, m256 mask1_hi, m256 mask2_lo, m256 mask2_hi,
DEBUG_PRINTF("buf %p\n", buf);
m256 chars_lo = GET_LO_4(chars);
m256 chars_hi = GET_HI_4(chars);
- m256 c_lo = pshufb_m256(mask1_lo, chars_lo);
- m256 c_hi = pshufb_m256(mask1_hi, chars_hi);
+ m256 c_lo = pshufb_m256(mask1_lo, chars_lo);
+ m256 c_hi = pshufb_m256(mask1_hi, chars_hi);
m256 t = or256(c_lo, c_hi);
#ifdef DEBUG
@@ -642,71 +642,71 @@ const u8 *fwdBlock2(m256 mask1_lo, m256 mask1_hi, m256 mask2_lo, m256 mask2_hi,
DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
#endif
- m256 c2_lo = pshufb_m256(mask2_lo, chars_lo);
- m256 c2_hi = pshufb_m256(mask2_hi, chars_hi);
- m256 t2 = or256(t, rshift128_m256(or256(c2_lo, c2_hi), 1));
+ m256 c2_lo = pshufb_m256(mask2_lo, chars_lo);
+ m256 c2_hi = pshufb_m256(mask2_hi, chars_hi);
+ m256 t2 = or256(t, rshift128_m256(or256(c2_lo, c2_hi), 1));
#ifdef DEBUG
DEBUG_PRINTF(" c2_lo: "); dumpMsk256(c2_lo); printf("\n");
DEBUG_PRINTF(" c2_hi: "); dumpMsk256(c2_hi); printf("\n");
DEBUG_PRINTF(" t2: "); dumpMsk256(t2); printf("\n");
#endif
- u32 z = movemask256(eq256(t2, ones));
+ u32 z = movemask256(eq256(t2, ones));
+
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *fwdBlockShort2(m256 mask1, m256 mask2, m128 chars, const u8 *buf,
+ const m256 low4bits) {
+ // do the hi and lo shuffles in the one avx register
+ m256 c = combine2x128(rshift64_m128(chars, 4), chars);
+ c = and256(c, low4bits);
+ m256 c_shuf1 = pshufb_m256(mask1, c);
+ m256 c_shuf2 = rshift128_m256(pshufb_m256(mask2, c), 1);
+ m256 t0 = or256(c_shuf1, c_shuf2);
+ m128 t = or128(movdq_hi(t0), cast256to128(t0));
+ // the upper 32-bits can't match
+ u32 z = 0xffff0000U | movemask128(eq128(t, ones128()));
+
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *shuftiDoubleShort(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo,
+ m128 mask2_hi, const u8 *buf, const u8 *buf_end) {
+ DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
+ const m256 low4bits = set32x8(0xf);
+ // run shufti over two overlapping 16-byte unaligned reads
+ const m256 mask1 = combine2x128(mask1_hi, mask1_lo);
+ const m256 mask2 = combine2x128(mask2_hi, mask2_lo);
+ m128 chars = loadu128(buf);
+ const u8 *rv = fwdBlockShort2(mask1, mask2, chars, buf, low4bits);
+ if (rv) {
+ return rv;
+ }
- return firstMatch(buf, z);
+ chars = loadu128(buf_end - 16);
+ rv = fwdBlockShort2(mask1, mask2, chars, buf_end - 16, low4bits);
+ if (rv) {
+ return rv;
+ }
+ return buf_end;
}
-static really_inline
-const u8 *fwdBlockShort2(m256 mask1, m256 mask2, m128 chars, const u8 *buf,
- const m256 low4bits) {
- // do the hi and lo shuffles in the one avx register
- m256 c = combine2x128(rshift64_m128(chars, 4), chars);
- c = and256(c, low4bits);
- m256 c_shuf1 = pshufb_m256(mask1, c);
- m256 c_shuf2 = rshift128_m256(pshufb_m256(mask2, c), 1);
- m256 t0 = or256(c_shuf1, c_shuf2);
- m128 t = or128(movdq_hi(t0), cast256to128(t0));
- // the upper 32-bits can't match
- u32 z = 0xffff0000U | movemask128(eq128(t, ones128()));
-
- return firstMatch(buf, z);
-}
-
-static really_inline
-const u8 *shuftiDoubleShort(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo,
- m128 mask2_hi, const u8 *buf, const u8 *buf_end) {
- DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
- const m256 low4bits = set32x8(0xf);
- // run shufti over two overlapping 16-byte unaligned reads
- const m256 mask1 = combine2x128(mask1_hi, mask1_lo);
- const m256 mask2 = combine2x128(mask2_hi, mask2_lo);
- m128 chars = loadu128(buf);
- const u8 *rv = fwdBlockShort2(mask1, mask2, chars, buf, low4bits);
- if (rv) {
- return rv;
- }
-
- chars = loadu128(buf_end - 16);
- rv = fwdBlockShort2(mask1, mask2, chars, buf_end - 16, low4bits);
- if (rv) {
- return rv;
- }
- return buf_end;
-}
-
/* takes 128 bit masks, but operates on 256 bits of data */
const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
m128 mask2_lo, m128 mask2_hi,
const u8 *buf, const u8 *buf_end) {
- /* we should always have at least 16 bytes */
- assert(buf_end - buf >= 16);
- DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
-
+ /* we should always have at least 16 bytes */
+ assert(buf_end - buf >= 16);
+ DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
+
if (buf_end - buf < 32) {
- return shuftiDoubleShort(mask1_lo, mask1_hi, mask2_lo, mask2_hi, buf,
- buf_end);
+ return shuftiDoubleShort(mask1_lo, mask1_hi, mask2_lo, mask2_hi, buf,
+ buf_end);
}
-
+
const m256 ones = ones256();
const m256 low4bits = set32x8(0xf);
const m256 wide_mask1_lo = set2x128(mask1_lo);
@@ -751,347 +751,347 @@ const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
return buf_end;
}
-#else // defined(HAVE_AVX512)
-
-#ifdef DEBUG
-DUMP_MSK(512)
-#endif
-
-static really_inline
-u64a block(m512 mask_lo, m512 mask_hi, m512 chars, const m512 low4bits,
- const m512 compare) {
- m512 c_lo = pshufb_m512(mask_lo, and512(chars, low4bits));
- m512 c_hi = pshufb_m512(mask_hi,
- rshift64_m512(andnot512(low4bits, chars), 4));
- m512 t = and512(c_lo, c_hi);
-
-#ifdef DEBUG
- DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
- DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
- DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
- DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
- DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
-#endif
-
- return eq512mask(t, compare);
-}
-static really_inline
-const u8 *firstMatch64(const u8 *buf, u64a z) {
- DEBUG_PRINTF("z 0x%016llx\n", z);
- if (unlikely(z != ~0ULL)) {
- u32 pos = ctz64(~z);
- DEBUG_PRINTF("match @ pos %u\n", pos);
- assert(pos < 64);
- return buf + pos;
- } else {
- return NULL; // no match
- }
-}
-
-static really_inline
-const u8 *fwdBlock512(m512 mask_lo, m512 mask_hi, m512 chars, const u8 *buf,
- const m512 low4bits, const m512 zeroes) {
- u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
-
- return firstMatch64(buf, z);
-}
-
-static really_inline
-const u8 *shortShufti512(m512 mask_lo, m512 mask_hi, const u8 *buf,
- const u8 *buf_end, const m512 low4bits,
- const m512 zeroes) {
- DEBUG_PRINTF("short shufti %p len %zu\n", buf, buf_end - buf);
- uintptr_t len = buf_end - buf;
- assert(len <= 64);
-
- // load mask
- u64a k = (~0ULL) >> (64 - len);
- DEBUG_PRINTF("load mask 0x%016llx\n", k);
-
- m512 chars = loadu_maskz_m512(k, buf);
-
- u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
-
- // reuse the load mask to indicate valid bytes
- return firstMatch64(buf, z | ~k);
-}
-
-/* takes 128 bit masks, but operates on 512 bits of data */
-const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
- const u8 *buf_end) {
- assert(buf && buf_end);
- assert(buf < buf_end);
- DEBUG_PRINTF("shufti %p len %zu\n", buf, buf_end - buf);
- DEBUG_PRINTF("b %s\n", buf);
-
- const m512 low4bits = set64x8(0xf);
- const m512 zeroes = zeroes512();
- const m512 wide_mask_lo = set4x128(mask_lo);
- const m512 wide_mask_hi = set4x128(mask_hi);
- const u8 *rv;
-
- // small cases.
- if (buf_end - buf <= 64) {
- rv = shortShufti512(wide_mask_lo, wide_mask_hi, buf, buf_end, low4bits,
- zeroes);
- return rv ? rv : buf_end;
- }
-
- assert(buf_end - buf >= 64);
-
- // Preconditioning: most of the time our buffer won't be aligned.
- if ((uintptr_t)buf % 64) {
- rv = shortShufti512(wide_mask_lo, wide_mask_hi, buf,
- ROUNDUP_PTR(buf, 64), low4bits, zeroes);
- if (rv) {
- return rv;
- }
- buf = ROUNDUP_PTR(buf, 64);
- }
-
- const u8 *last_block = ROUNDDOWN_PTR(buf_end, 64);
- while (buf < last_block) {
- m512 lchars = load512(buf);
- rv = fwdBlock512(wide_mask_lo, wide_mask_hi, lchars, buf, low4bits,
- zeroes);
- if (rv) {
- return rv;
- }
- buf += 64;
- }
-
- if (buf == buf_end) {
- goto done;
- }
-
- // Use an unaligned load to mop up the last 64 bytes and get an accurate
- // picture to buf_end.
- assert(buf <= buf_end && buf >= buf_end - 64);
- m512 chars = loadu512(buf_end - 64);
- rv = fwdBlock512(wide_mask_lo, wide_mask_hi, chars, buf_end - 64, low4bits,
- zeroes);
- if (rv) {
- return rv;
- }
-done:
- return buf_end;
-}
-
-static really_inline
-const u8 *lastMatch64(const u8 *buf, u64a z) {
- DEBUG_PRINTF("z 0x%016llx\n", z);
- if (unlikely(z != ~0ULL)) {
- u32 pos = clz64(~z);
- DEBUG_PRINTF("buf=%p, pos=%u\n", buf, pos);
- return buf + (63 - pos);
- } else {
- return NULL; // no match
- }
-}
-
-static really_inline
-const u8 *rshortShufti512(m512 mask_lo, m512 mask_hi, const u8 *buf,
- const u8 *buf_end, const m512 low4bits,
- const m512 zeroes) {
- DEBUG_PRINTF("short %p len %zu\n", buf, buf_end - buf);
- uintptr_t len = buf_end - buf;
- assert(len <= 64);
-
- // load mask
- u64a k = (~0ULL) >> (64 - len);
- DEBUG_PRINTF("load mask 0x%016llx\n", k);
-
- m512 chars = loadu_maskz_m512(k, buf);
-
- u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
-
- // reuse the load mask to indicate valid bytes
- return lastMatch64(buf, z | ~k);
-}
-
-static really_inline
-const u8 *revBlock512(m512 mask_lo, m512 mask_hi, m512 chars, const u8 *buf,
- const m512 low4bits, const m512 zeroes) {
- m512 c_lo = pshufb_m512(mask_lo, and512(chars, low4bits));
- m512 c_hi = pshufb_m512(mask_hi,
- rshift64_m512(andnot512(low4bits, chars), 4));
- m512 t = and512(c_lo, c_hi);
-
-#ifdef DEBUG
- DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
- DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
- DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
- DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
- DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
-#endif
-
- u64a z = eq512mask(t, zeroes);
- return lastMatch64(buf, z);
-}
-
-/* takes 128 bit masks, but operates on 512 bits of data */
-const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
- const u8 *buf_end) {
- DEBUG_PRINTF("buf %p buf_end %p\n", buf, buf_end);
- assert(buf && buf_end);
- assert(buf < buf_end);
-
- const m512 low4bits = set64x8(0xf);
- const m512 zeroes = zeroes512();
- const m512 wide_mask_lo = set4x128(mask_lo);
- const m512 wide_mask_hi = set4x128(mask_hi);
- const u8 *rv;
-
- if (buf_end - buf < 64) {
- rv = rshortShufti512(wide_mask_lo, wide_mask_hi, buf, buf_end, low4bits,
- zeroes);
- return rv ? rv : buf - 1;
- }
-
- if (ROUNDDOWN_PTR(buf_end, 64) != buf_end) {
- // peel off unaligned portion
- assert(buf_end - buf >= 64);
- DEBUG_PRINTF("start\n");
- rv = rshortShufti512(wide_mask_lo, wide_mask_hi,
- ROUNDDOWN_PTR(buf_end, 64), buf_end, low4bits,
- zeroes);
- if (rv) {
- return rv;
- }
- buf_end = ROUNDDOWN_PTR(buf_end, 64);
- }
-
- const u8 *last_block = ROUNDUP_PTR(buf, 64);
- while (buf_end > last_block) {
- buf_end -= 64;
- m512 lchars = load512(buf_end);
- rv = revBlock512(wide_mask_lo, wide_mask_hi, lchars, buf_end, low4bits,
- zeroes);
- if (rv) {
- return rv;
- }
- }
- if (buf_end == buf) {
- goto done;
- }
- // Use an unaligned load to mop up the last 64 bytes and get an accurate
- // picture to buf.
- m512 chars = loadu512(buf);
- rv = revBlock512(wide_mask_lo, wide_mask_hi, chars, buf, low4bits, zeroes);
- if (rv) {
- return rv;
- }
-done:
- return buf - 1;
-}
-
-static really_inline
-const u8 *fwdBlock2(m512 mask1_lo, m512 mask1_hi, m512 mask2_lo, m512 mask2_hi,
- m512 chars, const u8 *buf, const m512 low4bits,
- const m512 ones, __mmask64 k) {
- DEBUG_PRINTF("buf %p %.64s\n", buf, buf);
- m512 chars_lo = and512(chars, low4bits);
- m512 chars_hi = rshift64_m512(andnot512(low4bits, chars), 4);
- m512 c_lo = maskz_pshufb_m512(k, mask1_lo, chars_lo);
- m512 c_hi = maskz_pshufb_m512(k, mask1_hi, chars_hi);
- m512 t = or512(c_lo, c_hi);
-
-#ifdef DEBUG
- DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
- DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
- DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
- DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
- DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
-#endif
-
- m512 c2_lo = maskz_pshufb_m512(k, mask2_lo, chars_lo);
- m512 c2_hi = maskz_pshufb_m512(k, mask2_hi, chars_hi);
- m512 t2 = or512(t, rshift128_m512(or512(c2_lo, c2_hi), 1));
-
-#ifdef DEBUG
- DEBUG_PRINTF(" c2_lo: "); dumpMsk512(c2_lo); printf("\n");
- DEBUG_PRINTF(" c2_hi: "); dumpMsk512(c2_hi); printf("\n");
- DEBUG_PRINTF(" t2: "); dumpMsk512(t2); printf("\n");
-#endif
- u64a z = eq512mask(t2, ones);
-
- return firstMatch64(buf, z | ~k);
-}
-
-static really_inline
-const u8 *shortDoubleShufti512(m512 mask1_lo, m512 mask1_hi, m512 mask2_lo,
- m512 mask2_hi, const u8 *buf, const u8 *buf_end,
- const m512 low4bits, const m512 ones) {
- DEBUG_PRINTF("short %p len %zu\n", buf, buf_end - buf);
- uintptr_t len = buf_end - buf;
- assert(len <= 64);
-
- u64a k = (~0ULL) >> (64 - len);
- DEBUG_PRINTF("load mask 0x%016llx\n", k);
-
- m512 chars = loadu_mask_m512(ones, k, buf);
-
- const u8 *rv = fwdBlock2(mask1_lo, mask1_hi, mask2_lo, mask2_hi, chars, buf,
- low4bits, ones, k);
-
- return rv;
-}
-
-/* takes 128 bit masks, but operates on 512 bits of data */
-const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
- m128 mask2_lo, m128 mask2_hi,
- const u8 *buf, const u8 *buf_end) {
- /* we should always have at least 16 bytes */
- assert(buf_end - buf >= 16);
- DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
-
- const m512 ones = ones512();
- const m512 low4bits = set64x8(0xf);
- const m512 wide_mask1_lo = set4x128(mask1_lo);
- const m512 wide_mask1_hi = set4x128(mask1_hi);
- const m512 wide_mask2_lo = set4x128(mask2_lo);
- const m512 wide_mask2_hi = set4x128(mask2_hi);
- const u8 *rv;
-
- if (buf_end - buf <= 64) {
- rv = shortDoubleShufti512(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
- wide_mask2_hi, buf, buf_end, low4bits, ones);
- DEBUG_PRINTF("rv %p\n", rv);
- return rv ? rv : buf_end;
- }
-
- // Preconditioning: most of the time our buffer won't be aligned.
- if ((uintptr_t)buf % 64) {
- rv = shortDoubleShufti512(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
- wide_mask2_hi, buf, ROUNDUP_PTR(buf, 64),
- low4bits, ones);
- if (rv) {
- return rv;
- }
-
- buf = ROUNDUP_PTR(buf, 64);
- }
-
- const u8 *last_block = buf_end - 64;
- while (buf < last_block) {
- m512 lchars = load512(buf);
- rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
- wide_mask2_hi, lchars, buf, low4bits, ones, ~0);
- if (rv) {
- return rv;
- }
- buf += 64;
- }
-
- // Use an unaligned load to mop up the last 64 bytes and get an accurate
- // picture to buf_end.
- m512 chars = loadu512(buf_end - 64);
- rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo, wide_mask2_hi,
- chars, buf_end - 64, low4bits, ones, ~0);
- if (rv) {
- return rv;
- }
-
- return buf_end;
-}
-#endif
+#else // defined(HAVE_AVX512)
+
+#ifdef DEBUG
+DUMP_MSK(512)
+#endif
+
+static really_inline
+u64a block(m512 mask_lo, m512 mask_hi, m512 chars, const m512 low4bits,
+ const m512 compare) {
+ m512 c_lo = pshufb_m512(mask_lo, and512(chars, low4bits));
+ m512 c_hi = pshufb_m512(mask_hi,
+ rshift64_m512(andnot512(low4bits, chars), 4));
+ m512 t = and512(c_lo, c_hi);
+
+#ifdef DEBUG
+ DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
+ DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
+ DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
+ DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
+ DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
+#endif
+
+ return eq512mask(t, compare);
+}
+static really_inline
+const u8 *firstMatch64(const u8 *buf, u64a z) {
+ DEBUG_PRINTF("z 0x%016llx\n", z);
+ if (unlikely(z != ~0ULL)) {
+ u32 pos = ctz64(~z);
+ DEBUG_PRINTF("match @ pos %u\n", pos);
+ assert(pos < 64);
+ return buf + pos;
+ } else {
+ return NULL; // no match
+ }
+}
+
+static really_inline
+const u8 *fwdBlock512(m512 mask_lo, m512 mask_hi, m512 chars, const u8 *buf,
+ const m512 low4bits, const m512 zeroes) {
+ u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
+
+ return firstMatch64(buf, z);
+}
+
+static really_inline
+const u8 *shortShufti512(m512 mask_lo, m512 mask_hi, const u8 *buf,
+ const u8 *buf_end, const m512 low4bits,
+ const m512 zeroes) {
+ DEBUG_PRINTF("short shufti %p len %zu\n", buf, buf_end - buf);
+ uintptr_t len = buf_end - buf;
+ assert(len <= 64);
+
+ // load mask
+ u64a k = (~0ULL) >> (64 - len);
+ DEBUG_PRINTF("load mask 0x%016llx\n", k);
+
+ m512 chars = loadu_maskz_m512(k, buf);
+
+ u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
+
+ // reuse the load mask to indicate valid bytes
+ return firstMatch64(buf, z | ~k);
+}
+
+/* takes 128 bit masks, but operates on 512 bits of data */
+const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
+ const u8 *buf_end) {
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+ DEBUG_PRINTF("shufti %p len %zu\n", buf, buf_end - buf);
+ DEBUG_PRINTF("b %s\n", buf);
+
+ const m512 low4bits = set64x8(0xf);
+ const m512 zeroes = zeroes512();
+ const m512 wide_mask_lo = set4x128(mask_lo);
+ const m512 wide_mask_hi = set4x128(mask_hi);
+ const u8 *rv;
+
+ // small cases.
+ if (buf_end - buf <= 64) {
+ rv = shortShufti512(wide_mask_lo, wide_mask_hi, buf, buf_end, low4bits,
+ zeroes);
+ return rv ? rv : buf_end;
+ }
+
+ assert(buf_end - buf >= 64);
+
+ // Preconditioning: most of the time our buffer won't be aligned.
+ if ((uintptr_t)buf % 64) {
+ rv = shortShufti512(wide_mask_lo, wide_mask_hi, buf,
+ ROUNDUP_PTR(buf, 64), low4bits, zeroes);
+ if (rv) {
+ return rv;
+ }
+ buf = ROUNDUP_PTR(buf, 64);
+ }
+
+ const u8 *last_block = ROUNDDOWN_PTR(buf_end, 64);
+ while (buf < last_block) {
+ m512 lchars = load512(buf);
+ rv = fwdBlock512(wide_mask_lo, wide_mask_hi, lchars, buf, low4bits,
+ zeroes);
+ if (rv) {
+ return rv;
+ }
+ buf += 64;
+ }
+
+ if (buf == buf_end) {
+ goto done;
+ }
+
+ // Use an unaligned load to mop up the last 64 bytes and get an accurate
+ // picture to buf_end.
+ assert(buf <= buf_end && buf >= buf_end - 64);
+ m512 chars = loadu512(buf_end - 64);
+ rv = fwdBlock512(wide_mask_lo, wide_mask_hi, chars, buf_end - 64, low4bits,
+ zeroes);
+ if (rv) {
+ return rv;
+ }
+done:
+ return buf_end;
+}
+
+static really_inline
+const u8 *lastMatch64(const u8 *buf, u64a z) {
+ DEBUG_PRINTF("z 0x%016llx\n", z);
+ if (unlikely(z != ~0ULL)) {
+ u32 pos = clz64(~z);
+ DEBUG_PRINTF("buf=%p, pos=%u\n", buf, pos);
+ return buf + (63 - pos);
+ } else {
+ return NULL; // no match
+ }
+}
+
+static really_inline
+const u8 *rshortShufti512(m512 mask_lo, m512 mask_hi, const u8 *buf,
+ const u8 *buf_end, const m512 low4bits,
+ const m512 zeroes) {
+ DEBUG_PRINTF("short %p len %zu\n", buf, buf_end - buf);
+ uintptr_t len = buf_end - buf;
+ assert(len <= 64);
+
+ // load mask
+ u64a k = (~0ULL) >> (64 - len);
+ DEBUG_PRINTF("load mask 0x%016llx\n", k);
+
+ m512 chars = loadu_maskz_m512(k, buf);
+
+ u64a z = block(mask_lo, mask_hi, chars, low4bits, zeroes);
+
+ // reuse the load mask to indicate valid bytes
+ return lastMatch64(buf, z | ~k);
+}
+
+static really_inline
+const u8 *revBlock512(m512 mask_lo, m512 mask_hi, m512 chars, const u8 *buf,
+ const m512 low4bits, const m512 zeroes) {
+ m512 c_lo = pshufb_m512(mask_lo, and512(chars, low4bits));
+ m512 c_hi = pshufb_m512(mask_hi,
+ rshift64_m512(andnot512(low4bits, chars), 4));
+ m512 t = and512(c_lo, c_hi);
+
+#ifdef DEBUG
+ DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
+ DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
+ DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
+ DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
+ DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
+#endif
+
+ u64a z = eq512mask(t, zeroes);
+ return lastMatch64(buf, z);
+}
+
+/* takes 128 bit masks, but operates on 512 bits of data */
+const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
+ const u8 *buf_end) {
+ DEBUG_PRINTF("buf %p buf_end %p\n", buf, buf_end);
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+
+ const m512 low4bits = set64x8(0xf);
+ const m512 zeroes = zeroes512();
+ const m512 wide_mask_lo = set4x128(mask_lo);
+ const m512 wide_mask_hi = set4x128(mask_hi);
+ const u8 *rv;
+
+ if (buf_end - buf < 64) {
+ rv = rshortShufti512(wide_mask_lo, wide_mask_hi, buf, buf_end, low4bits,
+ zeroes);
+ return rv ? rv : buf - 1;
+ }
+
+ if (ROUNDDOWN_PTR(buf_end, 64) != buf_end) {
+ // peel off unaligned portion
+ assert(buf_end - buf >= 64);
+ DEBUG_PRINTF("start\n");
+ rv = rshortShufti512(wide_mask_lo, wide_mask_hi,
+ ROUNDDOWN_PTR(buf_end, 64), buf_end, low4bits,
+ zeroes);
+ if (rv) {
+ return rv;
+ }
+ buf_end = ROUNDDOWN_PTR(buf_end, 64);
+ }
+
+ const u8 *last_block = ROUNDUP_PTR(buf, 64);
+ while (buf_end > last_block) {
+ buf_end -= 64;
+ m512 lchars = load512(buf_end);
+ rv = revBlock512(wide_mask_lo, wide_mask_hi, lchars, buf_end, low4bits,
+ zeroes);
+ if (rv) {
+ return rv;
+ }
+ }
+ if (buf_end == buf) {
+ goto done;
+ }
+ // Use an unaligned load to mop up the last 64 bytes and get an accurate
+ // picture to buf.
+ m512 chars = loadu512(buf);
+ rv = revBlock512(wide_mask_lo, wide_mask_hi, chars, buf, low4bits, zeroes);
+ if (rv) {
+ return rv;
+ }
+done:
+ return buf - 1;
+}
+
+static really_inline
+const u8 *fwdBlock2(m512 mask1_lo, m512 mask1_hi, m512 mask2_lo, m512 mask2_hi,
+ m512 chars, const u8 *buf, const m512 low4bits,
+ const m512 ones, __mmask64 k) {
+ DEBUG_PRINTF("buf %p %.64s\n", buf, buf);
+ m512 chars_lo = and512(chars, low4bits);
+ m512 chars_hi = rshift64_m512(andnot512(low4bits, chars), 4);
+ m512 c_lo = maskz_pshufb_m512(k, mask1_lo, chars_lo);
+ m512 c_hi = maskz_pshufb_m512(k, mask1_hi, chars_hi);
+ m512 t = or512(c_lo, c_hi);
+
+#ifdef DEBUG
+ DEBUG_PRINTF(" chars: "); dumpMsk512AsChars(chars); printf("\n");
+ DEBUG_PRINTF(" char: "); dumpMsk512(chars); printf("\n");
+ DEBUG_PRINTF(" c_lo: "); dumpMsk512(c_lo); printf("\n");
+ DEBUG_PRINTF(" c_hi: "); dumpMsk512(c_hi); printf("\n");
+ DEBUG_PRINTF(" t: "); dumpMsk512(t); printf("\n");
+#endif
+
+ m512 c2_lo = maskz_pshufb_m512(k, mask2_lo, chars_lo);
+ m512 c2_hi = maskz_pshufb_m512(k, mask2_hi, chars_hi);
+ m512 t2 = or512(t, rshift128_m512(or512(c2_lo, c2_hi), 1));
+
+#ifdef DEBUG
+ DEBUG_PRINTF(" c2_lo: "); dumpMsk512(c2_lo); printf("\n");
+ DEBUG_PRINTF(" c2_hi: "); dumpMsk512(c2_hi); printf("\n");
+ DEBUG_PRINTF(" t2: "); dumpMsk512(t2); printf("\n");
+#endif
+ u64a z = eq512mask(t2, ones);
+
+ return firstMatch64(buf, z | ~k);
+}
+
+static really_inline
+const u8 *shortDoubleShufti512(m512 mask1_lo, m512 mask1_hi, m512 mask2_lo,
+ m512 mask2_hi, const u8 *buf, const u8 *buf_end,
+ const m512 low4bits, const m512 ones) {
+ DEBUG_PRINTF("short %p len %zu\n", buf, buf_end - buf);
+ uintptr_t len = buf_end - buf;
+ assert(len <= 64);
+
+ u64a k = (~0ULL) >> (64 - len);
+ DEBUG_PRINTF("load mask 0x%016llx\n", k);
+
+ m512 chars = loadu_mask_m512(ones, k, buf);
+
+ const u8 *rv = fwdBlock2(mask1_lo, mask1_hi, mask2_lo, mask2_hi, chars, buf,
+ low4bits, ones, k);
+
+ return rv;
+}
+
+/* takes 128 bit masks, but operates on 512 bits of data */
+const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
+ m128 mask2_lo, m128 mask2_hi,
+ const u8 *buf, const u8 *buf_end) {
+ /* we should always have at least 16 bytes */
+ assert(buf_end - buf >= 16);
+ DEBUG_PRINTF("buf %p len %zu\n", buf, buf_end - buf);
+
+ const m512 ones = ones512();
+ const m512 low4bits = set64x8(0xf);
+ const m512 wide_mask1_lo = set4x128(mask1_lo);
+ const m512 wide_mask1_hi = set4x128(mask1_hi);
+ const m512 wide_mask2_lo = set4x128(mask2_lo);
+ const m512 wide_mask2_hi = set4x128(mask2_hi);
+ const u8 *rv;
+
+ if (buf_end - buf <= 64) {
+ rv = shortDoubleShufti512(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
+ wide_mask2_hi, buf, buf_end, low4bits, ones);
+ DEBUG_PRINTF("rv %p\n", rv);
+ return rv ? rv : buf_end;
+ }
+
+ // Preconditioning: most of the time our buffer won't be aligned.
+ if ((uintptr_t)buf % 64) {
+ rv = shortDoubleShufti512(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
+ wide_mask2_hi, buf, ROUNDUP_PTR(buf, 64),
+ low4bits, ones);
+ if (rv) {
+ return rv;
+ }
+
+ buf = ROUNDUP_PTR(buf, 64);
+ }
+
+ const u8 *last_block = buf_end - 64;
+ while (buf < last_block) {
+ m512 lchars = load512(buf);
+ rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo,
+ wide_mask2_hi, lchars, buf, low4bits, ones, ~0);
+ if (rv) {
+ return rv;
+ }
+ buf += 64;
+ }
+
+ // Use an unaligned load to mop up the last 64 bytes and get an accurate
+ // picture to buf_end.
+ m512 chars = loadu512(buf_end - 64);
+ rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo, wide_mask2_hi,
+ chars, buf_end - 64, low4bits, ones, ~0);
+ if (rv) {
+ return rv;
+ }
+
+ return buf_end;
+}
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/shufticompile.cpp b/contrib/libs/hyperscan/src/nfa/shufticompile.cpp
index 48d2aa4ea9c..f712ef94a49 100644
--- a/contrib/libs/hyperscan/src/nfa/shufticompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/shufticompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,8 +32,8 @@
#include "shufticompile.h"
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/container.h"
+#include "util/flat_containers.h"
#include <array>
#include <cassert>
@@ -51,7 +51,7 @@ namespace ue2 {
*
* Note: always able to construct masks for 8 or fewer characters.
*/
-int shuftiBuildMasks(const CharReach &c, u8 *lo, u8 *hi) {
+int shuftiBuildMasks(const CharReach &c, u8 *lo, u8 *hi) {
/* Things could be packed much more optimally, but this should be able to
* handle any set of characters entirely in the lower half. */
@@ -108,33 +108,33 @@ int shuftiBuildMasks(const CharReach &c, u8 *lo, u8 *hi) {
return bit_index;
}
-static
-array<u16, 4> or_array(array<u16, 4> a, const array<u16, 4> &b) {
- a[0] |= b[0];
- a[1] |= b[1];
- a[2] |= b[2];
- a[3] |= b[3];
-
- return a;
-}
-
-
-#define MAX_BUCKETS 8
-static
-void set_buckets_from_mask(u16 nibble_mask, u32 bucket,
- array<u8, 16> &byte_mask) {
- assert(bucket < MAX_BUCKETS);
-
- u32 mask = nibble_mask;
- while (mask) {
- u32 n = findAndClearLSB_32(&mask);
- byte_mask[n] &= ~(1 << bucket);
- }
-}
-
-bool shuftiBuildDoubleMasks(const CharReach &onechar,
+static
+array<u16, 4> or_array(array<u16, 4> a, const array<u16, 4> &b) {
+ a[0] |= b[0];
+ a[1] |= b[1];
+ a[2] |= b[2];
+ a[3] |= b[3];
+
+ return a;
+}
+
+
+#define MAX_BUCKETS 8
+static
+void set_buckets_from_mask(u16 nibble_mask, u32 bucket,
+ array<u8, 16> &byte_mask) {
+ assert(bucket < MAX_BUCKETS);
+
+ u32 mask = nibble_mask;
+ while (mask) {
+ u32 n = findAndClearLSB_32(&mask);
+ byte_mask[n] &= ~(1 << bucket);
+ }
+}
+
+bool shuftiBuildDoubleMasks(const CharReach &onechar,
const flat_set<pair<u8, u8>> &twochar,
- u8 *lo1, u8 *hi1, u8 *lo2, u8 *hi2) {
+ u8 *lo1, u8 *hi1, u8 *lo2, u8 *hi2) {
DEBUG_PRINTF("unibytes %zu dibytes %zu\n", onechar.size(),
twochar.size());
array<u8, 16> lo1_a;
@@ -148,69 +148,69 @@ bool shuftiBuildDoubleMasks(const CharReach &onechar,
hi2_a.fill(0xff);
// two-byte literals
- vector<array<u16, 4>> nibble_masks;
- for (const auto &p : twochar) {
- DEBUG_PRINTF("%02hhx %02hhx\n", p.first, p.second);
- u16 a_lo = 1U << (p.first & 0xf);
- u16 a_hi = 1U << (p.first >> 4);
- u16 b_lo = 1U << (p.second & 0xf);
- u16 b_hi = 1U << (p.second >> 4);
- nibble_masks.push_back({{a_lo, a_hi, b_lo, b_hi}});
+ vector<array<u16, 4>> nibble_masks;
+ for (const auto &p : twochar) {
+ DEBUG_PRINTF("%02hhx %02hhx\n", p.first, p.second);
+ u16 a_lo = 1U << (p.first & 0xf);
+ u16 a_hi = 1U << (p.first >> 4);
+ u16 b_lo = 1U << (p.second & 0xf);
+ u16 b_hi = 1U << (p.second >> 4);
+ nibble_masks.push_back({{a_lo, a_hi, b_lo, b_hi}});
}
// one-byte literals (second byte is a wildcard)
for (size_t it = onechar.find_first(); it != CharReach::npos;
- it = onechar.find_next(it)) {
- DEBUG_PRINTF("%02hhx\n", (u8)it);
- u16 a_lo = 1U << (it & 0xf);
- u16 a_hi = 1U << (it >> 4);
- u16 wildcard = 0xffff;
- nibble_masks.push_back({{a_lo, a_hi, wildcard, wildcard}});
- }
-
- // try to merge strings into shared buckets
- for (u32 i = 0; i < 4; i++) {
- map<array<u16, 4>, array<u16, 4>> new_masks;
- for (const auto &a : nibble_masks) {
- auto key = a;
- key[i] = 0;
- if (!contains(new_masks, key)) {
- new_masks[key] = a;
- } else {
- new_masks[key] = or_array(new_masks[key], a);
- }
+ it = onechar.find_next(it)) {
+ DEBUG_PRINTF("%02hhx\n", (u8)it);
+ u16 a_lo = 1U << (it & 0xf);
+ u16 a_hi = 1U << (it >> 4);
+ u16 wildcard = 0xffff;
+ nibble_masks.push_back({{a_lo, a_hi, wildcard, wildcard}});
+ }
+
+ // try to merge strings into shared buckets
+ for (u32 i = 0; i < 4; i++) {
+ map<array<u16, 4>, array<u16, 4>> new_masks;
+ for (const auto &a : nibble_masks) {
+ auto key = a;
+ key[i] = 0;
+ if (!contains(new_masks, key)) {
+ new_masks[key] = a;
+ } else {
+ new_masks[key] = or_array(new_masks[key], a);
+ }
}
- nibble_masks.clear();
- for (const auto &e : new_masks) {
- nibble_masks.push_back(e.second);
- }
+ nibble_masks.clear();
+ for (const auto &e : new_masks) {
+ nibble_masks.push_back(e.second);
+ }
+ }
+
+ if (nibble_masks.size() > MAX_BUCKETS) {
+ DEBUG_PRINTF("too many buckets needed (%zu)\n", nibble_masks.size());
+ return false;
+ }
+
+ u32 i = 0;
+ for (const auto &a : nibble_masks) {
+ set_buckets_from_mask(a[0], i, lo1_a);
+ set_buckets_from_mask(a[1], i, hi1_a);
+ set_buckets_from_mask(a[2], i, lo2_a);
+ set_buckets_from_mask(a[3], i, hi2_a);
+ i++;
}
- if (nibble_masks.size() > MAX_BUCKETS) {
- DEBUG_PRINTF("too many buckets needed (%zu)\n", nibble_masks.size());
- return false;
- }
-
- u32 i = 0;
- for (const auto &a : nibble_masks) {
- set_buckets_from_mask(a[0], i, lo1_a);
- set_buckets_from_mask(a[1], i, hi1_a);
- set_buckets_from_mask(a[2], i, lo2_a);
- set_buckets_from_mask(a[3], i, hi2_a);
- i++;
- }
-
memcpy(lo1, lo1_a.data(), sizeof(m128));
memcpy(lo2, lo2_a.data(), sizeof(m128));
memcpy(hi1, hi1_a.data(), sizeof(m128));
memcpy(hi2, hi2_a.data(), sizeof(m128));
- return true;
+ return true;
}
#ifdef DUMP_SUPPORT
-CharReach shufti2cr(const u8 *lo, const u8 *hi) {
+CharReach shufti2cr(const u8 *lo, const u8 *hi) {
CharReach cr;
for (u32 i = 0; i < 256; i++) {
if (lo[(u8)i & 0xf] & hi[(u8)i >> 4]) {
diff --git a/contrib/libs/hyperscan/src/nfa/shufticompile.h b/contrib/libs/hyperscan/src/nfa/shufticompile.h
index 771d298939c..59b9c38dff9 100644
--- a/contrib/libs/hyperscan/src/nfa/shufticompile.h
+++ b/contrib/libs/hyperscan/src/nfa/shufticompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <utility>
@@ -48,15 +48,15 @@ namespace ue2 {
*
* Note: always able to construct masks for 8 or fewer characters.
*/
-int shuftiBuildMasks(const CharReach &chars, u8 *lo, u8 *hi);
+int shuftiBuildMasks(const CharReach &chars, u8 *lo, u8 *hi);
-/** \brief Double-byte variant
- *
- * Returns false if we are unable to build the masks (too many buckets required)
- */
-bool shuftiBuildDoubleMasks(const CharReach &onechar,
+/** \brief Double-byte variant
+ *
+ * Returns false if we are unable to build the masks (too many buckets required)
+ */
+bool shuftiBuildDoubleMasks(const CharReach &onechar,
const flat_set<std::pair<u8, u8>> &twochar,
- u8 *lo1, u8 *hi1, u8 *lo2, u8 *hi2);
+ u8 *lo1, u8 *hi1, u8 *lo2, u8 *hi2);
#ifdef DUMP_SUPPORT
@@ -64,7 +64,7 @@ bool shuftiBuildDoubleMasks(const CharReach &onechar,
* \brief Dump code: returns a CharReach with the reach that would match this
* shufti.
*/
-CharReach shufti2cr(const u8 *lo, const u8 *hi);
+CharReach shufti2cr(const u8 *lo, const u8 *hi);
#endif // DUMP_SUPPORT
diff --git a/contrib/libs/hyperscan/src/nfa/tamarama.c b/contrib/libs/hyperscan/src/nfa/tamarama.c
index 8a2f633e095..43480f06506 100644
--- a/contrib/libs/hyperscan/src/nfa/tamarama.c
+++ b/contrib/libs/hyperscan/src/nfa/tamarama.c
@@ -1,441 +1,441 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- \brief Tamarama: container engine for exclusive engines, runtime code.
-*/
-#include "config.h"
-
-#include "tamarama.h"
-
-#include "tamarama_internal.h"
-#include "nfa_api.h"
-#include "nfa_api_queue.h"
-#include "nfa_api_util.h"
-#include "nfa_internal.h"
-#include "scratch.h"
-#include "util/partial_store.h"
-
-static really_inline
-u32 getSubOffset(const struct Tamarama *t, u32 num) {
- DEBUG_PRINTF("subengine:%u\n", num);
- assert(num < t->numSubEngines);
- const u32 *sub =
- (const u32 *)((const char *)t + sizeof(struct Tamarama) +
- t->numSubEngines * sizeof(u32));
- assert(ISALIGNED(sub));
- return sub[num];
-}
-
-static
-const struct NFA *getSubEngine(const struct Tamarama *t,
- const u32 activeIdx) {
- const u32 offset = getSubOffset(t, activeIdx);
- DEBUG_PRINTF("activeIdx:%u offsets:%u\n", activeIdx, offset);
- const char *base = (const char *)t;
- return (const struct NFA *)(base + offset);
-}
-
-static
-void storeActiveIdx(const struct Tamarama *t, char *state,
- const u32 idx) {
- assert(idx <= t->numSubEngines);
- partial_store_u32(state, idx, t->activeIdxSize);
-}
-
-static
-u32 loadActiveIdx(const char *state,
- const u32 activeIdxSize) {
- return partial_load_u32(state, activeIdxSize);
-}
-
-static really_inline
-void copyQueueProperties(const struct mq *q1, struct mq *q2,
- const u32 activeIdxSize) {
- q2->state = q1->state;
- q2->streamState = q1->streamState + activeIdxSize;
- q2->offset = q1->offset;
- q2->buffer = q1->buffer;
- q2->length = q1->length;
- q2->history = q1->history;
- q2->hlength = q1->hlength;
- q2->cb = q1->cb;
- q2->context = q1->context;
- q2->scratch = q1->scratch;
- q2->report_current = q1->report_current;
-}
-
-static
-void copyQueueItems(const struct Tamarama *t, const struct NFA *sub,
- struct mq *q1, struct mq *q2, const u32 activeIdx) {
- const u32 *baseTop = (const u32 *)((const char *)t +
- sizeof(struct Tamarama));
-
- u32 lower = baseTop[activeIdx];
- u32 upper = activeIdx == t->numSubEngines - 1 ?
- ~0U : baseTop[activeIdx + 1];
- u32 event_base = isMultiTopType(sub->type) ? MQE_TOP_FIRST : MQE_TOP;
- while (q1->cur < q1->end) {
- u32 type = q1->items[q1->cur].type;
- s64a loc = q1->items[q1->cur].location;
- DEBUG_PRINTF("type:%u lower:%u upper:%u\n", type, lower, upper);
- if (type >= lower && type < upper) {
- u32 event = event_base;
- if (event == MQE_TOP_FIRST) {
- event += type - lower;
- }
- pushQueue(q2, event, loc);
- } else {
- pushQueueNoMerge(q2, MQE_END, loc);
- break;
- }
- q1->cur++;
- }
-}
-
-static
-void copyQueue(const struct Tamarama *t, const struct NFA *sub,
- struct mq *q1, struct mq *q2, const u32 activeIdx) {
- copyQueueProperties(q1, q2, t->activeIdxSize);
-
- // copy MQE_START item
- u32 cur = q1->cur++;
- q2->cur = cur;
- q2->items[cur] = q1->items[cur];
- q2->end = cur + 1;
-
- copyQueueItems(t, sub, q1, q2, activeIdx);
- // restore cur index of the main queue
- q1->cur = cur;
-}
-
-static
-u32 findEngineForTop(const u32 *baseTop, const u32 cur,
- const u32 numSubEngines) {
- u32 i;
- for (i = 0; i < numSubEngines; ++i) {
- DEBUG_PRINTF("cur:%u base:%u\n", cur, baseTop[i]);
- if (cur >= baseTop[i] &&
- (i == numSubEngines - 1 || cur < baseTop[i + 1])) {
- break;
- }
- }
- return i;
-}
-
-static
-void initSubQueue(const struct Tamarama *t, struct mq *q1,
- struct mq *q2, const u32 lastActiveIdx,
- const u32 activeIdx) {
- // Push events to the new queue
- const struct NFA *sub = getSubEngine(t, activeIdx);
- assert(!isContainerType(sub->type));
- q2->nfa = sub;
-
- // Reinitialize state if the last active subengine is different
- // from current one
- if (lastActiveIdx == t->numSubEngines ||
- lastActiveIdx != activeIdx) {
- nfaQueueInitState(q2->nfa, q2);
- }
-
- copyQueueItems(t, sub, q1, q2, activeIdx);
- if (q1->items[q1->cur].type == MQE_END) {
- q1->cur++;
- }
- DEBUG_PRINTF("update lastIdx:%u\n", activeIdx);
- storeActiveIdx(t, q1->streamState, activeIdx);
-}
-
-static
-void updateQueues(const struct Tamarama *t, struct mq *q1, struct mq *q2) {
- q2->cur = q2->end = 0;
- copyQueueProperties(q1, q2, t->activeIdxSize);
-
- const u32 numSubEngines = t->numSubEngines;
- u32 lastActiveIdx = loadActiveIdx(q1->streamState,
- t->activeIdxSize);
-#ifdef DEBUG
- DEBUG_PRINTF("external queue\n");
- debugQueue(q1);
-#endif
-
- // Push MQE_START event to the subqueue
- s64a loc = q1->items[q1->cur].location;
- pushQueueAt(q2, 0, MQE_START, loc);
- char hasStart = 0;
- if (q1->items[q1->cur].type == MQE_START) {
- hasStart = 1;
- q1->cur++;
- }
-
- u32 activeIdx = lastActiveIdx;
- // If we have top events in the main queue, update current active id
- if (q1->cur < q1->end - 1) {
- const u32 *baseTop = (const u32 *)((const char *)t +
- sizeof(struct Tamarama));
- u32 curTop = q1->items[q1->cur].type;
- activeIdx = findEngineForTop(baseTop, curTop, numSubEngines);
- }
-
- assert(activeIdx < numSubEngines);
- DEBUG_PRINTF("last id:%u, current id:%u, num of subengines:%u\n",
- lastActiveIdx, activeIdx, numSubEngines);
- // Handle unfinished last alive subengine
- if (lastActiveIdx != activeIdx &&
- lastActiveIdx != numSubEngines && hasStart) {
- loc = q1->items[q1->cur].location;
- pushQueueNoMerge(q2, MQE_END, loc);
- q2->nfa = getSubEngine(t, lastActiveIdx);
- return;
- }
-
- initSubQueue(t, q1, q2, lastActiveIdx, activeIdx);
- DEBUG_PRINTF("finish queues\n");
-}
-
-// After processing subqueue items for subengines, we need to copy back
-// remaining items in subqueue if there are any to Tamarama main queue
-static
-void copyBack(const struct Tamarama *t, struct mq *q, struct mq *q1) {
- DEBUG_PRINTF("copy back %u, %u\n", q1->cur, q1->end);
- q->report_current = q1->report_current;
- if (q->cur >= q->end && q1->cur >= q1->end) {
- return;
- }
-
- const u32 *baseTop = (const u32 *)((const char *)t +
- sizeof(struct Tamarama));
- const u32 lastIdx = loadActiveIdx(q->streamState,
- t->activeIdxSize);
- u32 base = 0, event_base = 0;
- if (lastIdx != t->numSubEngines) {
- base = baseTop[lastIdx];
- const struct NFA *sub = getSubEngine(t, lastIdx);
- event_base = isMultiTopType(sub->type) ? MQE_TOP_FIRST : MQE_TOP;
- }
-
- u32 numItems = q1->end > q1->cur + 1 ? q1->end - q1->cur - 1 : 1;
- // Also need to copy MQE_END if the main queue is empty
- if (q->cur == q->end) {
- assert(q->cur > 1 && q1->items[q1->end - 1].type == MQE_END);
- q->items[--q->cur] = q1->items[q1->end - 1];
- }
- u32 cur = q->cur - numItems;
- q->items[cur] = q1->items[q1->cur++];
- q->items[cur].type = MQE_START;
- q->cur = cur++;
- for (u32 i = 0; i < numItems - 1; ++i) {
- assert(q1->cur < q1->end);
- u32 type = q1->items[q1->cur].type;
- if (type > MQE_END) {
- q1->items[q1->cur].type = type - event_base + base;
- }
- q->items[cur++] = q1->items[q1->cur++];
- }
-
-#ifdef DEBUG
- DEBUG_PRINTF("external queue\n");
- debugQueue(q);
-#endif
-}
-
-char nfaExecTamarama_testEOD(const struct NFA *n, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return MO_CONTINUE_MATCHING;
- }
-
- const struct NFA *sub = getSubEngine(t, activeIdx);
- if (nfaAcceptsEod(sub)) {
- assert(!isContainerType(sub->type));
- const char *subStreamState = streamState + t->activeIdxSize;
- return nfaCheckFinalState(sub, state, subStreamState, offset, callback,
- context);
- }
-
- return MO_CONTINUE_MATCHING;
-}
-
-char nfaExecTamarama_QR(const struct NFA *n, struct mq *q, ReportID report) {
- DEBUG_PRINTF("exec rose\n");
- struct mq q1;
- q1.cur = q1.end = 0;
- char rv = 0;
- const struct Tamarama *t = getImplNfa(n);
- while (q->cur < q->end) {
- updateQueues(t, q, &q1);
- }
-
- if (q1.cur < q1.end) {
- rv = nfaQueueExecRose(q1.nfa, &q1, report);
- }
-
- DEBUG_PRINTF("exec rose rv:%u\n", rv);
- return rv;
-}
-
-char nfaExecTamarama_reportCurrent(const struct NFA *n, struct mq *q) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return 1;
- }
-
- const struct NFA *sub = getSubEngine(t, activeIdx);
- struct mq q1;
- copyQueue(t, sub, q, &q1, activeIdx);
- return nfaReportCurrentMatches(sub, &q1);
-}
-
-char nfaExecTamarama_inAccept(const struct NFA *n, ReportID report,
- struct mq *q) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return 0;
- }
- const struct NFA *sub = getSubEngine(t, activeIdx);
-
- struct mq q1;
- copyQueue(t, sub, q, &q1, activeIdx);
- return nfaInAcceptState(sub, report, &q1);
-}
-
-char nfaExecTamarama_inAnyAccept(const struct NFA *n, struct mq *q) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return 0;
- }
- const struct NFA *sub = getSubEngine(t, activeIdx);
-
- struct mq q1;
- copyQueue(t, sub, q, &q1, activeIdx);
- return nfaInAnyAcceptState(sub, &q1);
-}
-
-char nfaExecTamarama_queueInitState(const struct NFA *n, struct mq *q) {
- DEBUG_PRINTF("init state\n");
- const struct Tamarama *t = getImplNfa(n);
- char *ptr = q->streamState;
- // Use activeIdxSize as a sentinel value and initialize the state to
- // an invalid engine as nothing has been triggered yet
- storeActiveIdx(t, ptr, t->numSubEngines);
- return 0;
-}
-
-char nfaExecTamarama_queueCompressState(const struct NFA *n, const struct mq *q,
- s64a loc) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return 0;
- }
-
- const struct NFA *sub = getSubEngine(t, activeIdx);
-
- struct mq q1;
- copyQueueProperties(q, &q1, t->activeIdxSize);
- return nfaQueueCompressState(sub, &q1, loc);
-}
-
-char nfaExecTamarama_expandState(const struct NFA *n, void *dest,
- const void *src, u64a offset, u8 key) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(src, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return 0;
- }
-
- const struct NFA *sub = getSubEngine(t, activeIdx);
-
- const char *subStreamState = (const char *)src + t->activeIdxSize;
- return nfaExpandState(sub, dest, subStreamState, offset, key);
-}
-
-enum nfa_zombie_status nfaExecTamarama_zombie_status(const struct NFA *n,
- struct mq *q, s64a loc) {
- const struct Tamarama *t = getImplNfa(n);
- u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
- if (activeIdx == t->numSubEngines) {
- return NFA_ZOMBIE_NO;
- }
- const struct NFA *sub = getSubEngine(t, activeIdx);
-
- struct mq q1;
- copyQueue(t, sub, q, &q1, activeIdx);
- return nfaGetZombieStatus(sub, &q1, loc);
-}
-
-char nfaExecTamarama_Q(const struct NFA *n, struct mq *q, s64a end) {
- DEBUG_PRINTF("exec\n");
- struct mq q1;
- char rv = MO_ALIVE;
- char copy = 0;
- const struct Tamarama *t = getImplNfa(n);
- while (q->cur < q->end && q_cur_loc(q) <= end) {
- updateQueues(t, q, &q1);
- rv = nfaQueueExec_raw(q1.nfa, &q1, end);
- q->report_current = q1.report_current;
- copy = 1;
- if (can_stop_matching(q->scratch)) {
- break;
- }
- }
- if (copy) {
- copyBack(t, q, &q1);
- }
- return rv;
-}
-
-char nfaExecTamarama_Q2(const struct NFA *n, struct mq *q, s64a end) {
- DEBUG_PRINTF("exec to match\n");
- struct mq q1;
- char rv = 0;
- char copy = 0;
- const struct Tamarama *t = getImplNfa(n);
- while (q->cur < q->end && q_cur_loc(q) <= end &&
- rv != MO_MATCHES_PENDING) {
- updateQueues(t, q, &q1);
- rv = nfaQueueExec2_raw(q1.nfa, &q1, end);
- q->report_current = q1.report_current;
- copy = 1;
- if (can_stop_matching(q->scratch)) {
- break;
- }
- }
- if (copy) {
- copyBack(t, q, &q1);
- }
- return rv;
-}
-
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ \brief Tamarama: container engine for exclusive engines, runtime code.
+*/
+#include "config.h"
+
+#include "tamarama.h"
+
+#include "tamarama_internal.h"
+#include "nfa_api.h"
+#include "nfa_api_queue.h"
+#include "nfa_api_util.h"
+#include "nfa_internal.h"
+#include "scratch.h"
+#include "util/partial_store.h"
+
+static really_inline
+u32 getSubOffset(const struct Tamarama *t, u32 num) {
+ DEBUG_PRINTF("subengine:%u\n", num);
+ assert(num < t->numSubEngines);
+ const u32 *sub =
+ (const u32 *)((const char *)t + sizeof(struct Tamarama) +
+ t->numSubEngines * sizeof(u32));
+ assert(ISALIGNED(sub));
+ return sub[num];
+}
+
+static
+const struct NFA *getSubEngine(const struct Tamarama *t,
+ const u32 activeIdx) {
+ const u32 offset = getSubOffset(t, activeIdx);
+ DEBUG_PRINTF("activeIdx:%u offsets:%u\n", activeIdx, offset);
+ const char *base = (const char *)t;
+ return (const struct NFA *)(base + offset);
+}
+
+static
+void storeActiveIdx(const struct Tamarama *t, char *state,
+ const u32 idx) {
+ assert(idx <= t->numSubEngines);
+ partial_store_u32(state, idx, t->activeIdxSize);
+}
+
+static
+u32 loadActiveIdx(const char *state,
+ const u32 activeIdxSize) {
+ return partial_load_u32(state, activeIdxSize);
+}
+
+static really_inline
+void copyQueueProperties(const struct mq *q1, struct mq *q2,
+ const u32 activeIdxSize) {
+ q2->state = q1->state;
+ q2->streamState = q1->streamState + activeIdxSize;
+ q2->offset = q1->offset;
+ q2->buffer = q1->buffer;
+ q2->length = q1->length;
+ q2->history = q1->history;
+ q2->hlength = q1->hlength;
+ q2->cb = q1->cb;
+ q2->context = q1->context;
+ q2->scratch = q1->scratch;
+ q2->report_current = q1->report_current;
+}
+
+static
+void copyQueueItems(const struct Tamarama *t, const struct NFA *sub,
+ struct mq *q1, struct mq *q2, const u32 activeIdx) {
+ const u32 *baseTop = (const u32 *)((const char *)t +
+ sizeof(struct Tamarama));
+
+ u32 lower = baseTop[activeIdx];
+ u32 upper = activeIdx == t->numSubEngines - 1 ?
+ ~0U : baseTop[activeIdx + 1];
+ u32 event_base = isMultiTopType(sub->type) ? MQE_TOP_FIRST : MQE_TOP;
+ while (q1->cur < q1->end) {
+ u32 type = q1->items[q1->cur].type;
+ s64a loc = q1->items[q1->cur].location;
+ DEBUG_PRINTF("type:%u lower:%u upper:%u\n", type, lower, upper);
+ if (type >= lower && type < upper) {
+ u32 event = event_base;
+ if (event == MQE_TOP_FIRST) {
+ event += type - lower;
+ }
+ pushQueue(q2, event, loc);
+ } else {
+ pushQueueNoMerge(q2, MQE_END, loc);
+ break;
+ }
+ q1->cur++;
+ }
+}
+
+static
+void copyQueue(const struct Tamarama *t, const struct NFA *sub,
+ struct mq *q1, struct mq *q2, const u32 activeIdx) {
+ copyQueueProperties(q1, q2, t->activeIdxSize);
+
+ // copy MQE_START item
+ u32 cur = q1->cur++;
+ q2->cur = cur;
+ q2->items[cur] = q1->items[cur];
+ q2->end = cur + 1;
+
+ copyQueueItems(t, sub, q1, q2, activeIdx);
+ // restore cur index of the main queue
+ q1->cur = cur;
+}
+
+static
+u32 findEngineForTop(const u32 *baseTop, const u32 cur,
+ const u32 numSubEngines) {
+ u32 i;
+ for (i = 0; i < numSubEngines; ++i) {
+ DEBUG_PRINTF("cur:%u base:%u\n", cur, baseTop[i]);
+ if (cur >= baseTop[i] &&
+ (i == numSubEngines - 1 || cur < baseTop[i + 1])) {
+ break;
+ }
+ }
+ return i;
+}
+
+static
+void initSubQueue(const struct Tamarama *t, struct mq *q1,
+ struct mq *q2, const u32 lastActiveIdx,
+ const u32 activeIdx) {
+ // Push events to the new queue
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+ assert(!isContainerType(sub->type));
+ q2->nfa = sub;
+
+ // Reinitialize state if the last active subengine is different
+ // from current one
+ if (lastActiveIdx == t->numSubEngines ||
+ lastActiveIdx != activeIdx) {
+ nfaQueueInitState(q2->nfa, q2);
+ }
+
+ copyQueueItems(t, sub, q1, q2, activeIdx);
+ if (q1->items[q1->cur].type == MQE_END) {
+ q1->cur++;
+ }
+ DEBUG_PRINTF("update lastIdx:%u\n", activeIdx);
+ storeActiveIdx(t, q1->streamState, activeIdx);
+}
+
+static
+void updateQueues(const struct Tamarama *t, struct mq *q1, struct mq *q2) {
+ q2->cur = q2->end = 0;
+ copyQueueProperties(q1, q2, t->activeIdxSize);
+
+ const u32 numSubEngines = t->numSubEngines;
+ u32 lastActiveIdx = loadActiveIdx(q1->streamState,
+ t->activeIdxSize);
+#ifdef DEBUG
+ DEBUG_PRINTF("external queue\n");
+ debugQueue(q1);
+#endif
+
+ // Push MQE_START event to the subqueue
+ s64a loc = q1->items[q1->cur].location;
+ pushQueueAt(q2, 0, MQE_START, loc);
+ char hasStart = 0;
+ if (q1->items[q1->cur].type == MQE_START) {
+ hasStart = 1;
+ q1->cur++;
+ }
+
+ u32 activeIdx = lastActiveIdx;
+ // If we have top events in the main queue, update current active id
+ if (q1->cur < q1->end - 1) {
+ const u32 *baseTop = (const u32 *)((const char *)t +
+ sizeof(struct Tamarama));
+ u32 curTop = q1->items[q1->cur].type;
+ activeIdx = findEngineForTop(baseTop, curTop, numSubEngines);
+ }
+
+ assert(activeIdx < numSubEngines);
+ DEBUG_PRINTF("last id:%u, current id:%u, num of subengines:%u\n",
+ lastActiveIdx, activeIdx, numSubEngines);
+ // Handle unfinished last alive subengine
+ if (lastActiveIdx != activeIdx &&
+ lastActiveIdx != numSubEngines && hasStart) {
+ loc = q1->items[q1->cur].location;
+ pushQueueNoMerge(q2, MQE_END, loc);
+ q2->nfa = getSubEngine(t, lastActiveIdx);
+ return;
+ }
+
+ initSubQueue(t, q1, q2, lastActiveIdx, activeIdx);
+ DEBUG_PRINTF("finish queues\n");
+}
+
+// After processing subqueue items for subengines, we need to copy back
+// remaining items in subqueue if there are any to Tamarama main queue
+static
+void copyBack(const struct Tamarama *t, struct mq *q, struct mq *q1) {
+ DEBUG_PRINTF("copy back %u, %u\n", q1->cur, q1->end);
+ q->report_current = q1->report_current;
+ if (q->cur >= q->end && q1->cur >= q1->end) {
+ return;
+ }
+
+ const u32 *baseTop = (const u32 *)((const char *)t +
+ sizeof(struct Tamarama));
+ const u32 lastIdx = loadActiveIdx(q->streamState,
+ t->activeIdxSize);
+ u32 base = 0, event_base = 0;
+ if (lastIdx != t->numSubEngines) {
+ base = baseTop[lastIdx];
+ const struct NFA *sub = getSubEngine(t, lastIdx);
+ event_base = isMultiTopType(sub->type) ? MQE_TOP_FIRST : MQE_TOP;
+ }
+
+ u32 numItems = q1->end > q1->cur + 1 ? q1->end - q1->cur - 1 : 1;
+ // Also need to copy MQE_END if the main queue is empty
+ if (q->cur == q->end) {
+ assert(q->cur > 1 && q1->items[q1->end - 1].type == MQE_END);
+ q->items[--q->cur] = q1->items[q1->end - 1];
+ }
+ u32 cur = q->cur - numItems;
+ q->items[cur] = q1->items[q1->cur++];
+ q->items[cur].type = MQE_START;
+ q->cur = cur++;
+ for (u32 i = 0; i < numItems - 1; ++i) {
+ assert(q1->cur < q1->end);
+ u32 type = q1->items[q1->cur].type;
+ if (type > MQE_END) {
+ q1->items[q1->cur].type = type - event_base + base;
+ }
+ q->items[cur++] = q1->items[q1->cur++];
+ }
+
+#ifdef DEBUG
+ DEBUG_PRINTF("external queue\n");
+ debugQueue(q);
+#endif
+}
+
+char nfaExecTamarama_testEOD(const struct NFA *n, const char *state,
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return MO_CONTINUE_MATCHING;
+ }
+
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+ if (nfaAcceptsEod(sub)) {
+ assert(!isContainerType(sub->type));
+ const char *subStreamState = streamState + t->activeIdxSize;
+ return nfaCheckFinalState(sub, state, subStreamState, offset, callback,
+ context);
+ }
+
+ return MO_CONTINUE_MATCHING;
+}
+
+char nfaExecTamarama_QR(const struct NFA *n, struct mq *q, ReportID report) {
+ DEBUG_PRINTF("exec rose\n");
+ struct mq q1;
+ q1.cur = q1.end = 0;
+ char rv = 0;
+ const struct Tamarama *t = getImplNfa(n);
+ while (q->cur < q->end) {
+ updateQueues(t, q, &q1);
+ }
+
+ if (q1.cur < q1.end) {
+ rv = nfaQueueExecRose(q1.nfa, &q1, report);
+ }
+
+ DEBUG_PRINTF("exec rose rv:%u\n", rv);
+ return rv;
+}
+
+char nfaExecTamarama_reportCurrent(const struct NFA *n, struct mq *q) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return 1;
+ }
+
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+ struct mq q1;
+ copyQueue(t, sub, q, &q1, activeIdx);
+ return nfaReportCurrentMatches(sub, &q1);
+}
+
+char nfaExecTamarama_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return 0;
+ }
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+
+ struct mq q1;
+ copyQueue(t, sub, q, &q1, activeIdx);
+ return nfaInAcceptState(sub, report, &q1);
+}
+
+char nfaExecTamarama_inAnyAccept(const struct NFA *n, struct mq *q) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return 0;
+ }
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+
+ struct mq q1;
+ copyQueue(t, sub, q, &q1, activeIdx);
+ return nfaInAnyAcceptState(sub, &q1);
+}
+
+char nfaExecTamarama_queueInitState(const struct NFA *n, struct mq *q) {
+ DEBUG_PRINTF("init state\n");
+ const struct Tamarama *t = getImplNfa(n);
+ char *ptr = q->streamState;
+ // Use activeIdxSize as a sentinel value and initialize the state to
+ // an invalid engine as nothing has been triggered yet
+ storeActiveIdx(t, ptr, t->numSubEngines);
+ return 0;
+}
+
+char nfaExecTamarama_queueCompressState(const struct NFA *n, const struct mq *q,
+ s64a loc) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return 0;
+ }
+
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+
+ struct mq q1;
+ copyQueueProperties(q, &q1, t->activeIdxSize);
+ return nfaQueueCompressState(sub, &q1, loc);
+}
+
+char nfaExecTamarama_expandState(const struct NFA *n, void *dest,
+ const void *src, u64a offset, u8 key) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(src, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return 0;
+ }
+
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+
+ const char *subStreamState = (const char *)src + t->activeIdxSize;
+ return nfaExpandState(sub, dest, subStreamState, offset, key);
+}
+
+enum nfa_zombie_status nfaExecTamarama_zombie_status(const struct NFA *n,
+ struct mq *q, s64a loc) {
+ const struct Tamarama *t = getImplNfa(n);
+ u32 activeIdx = loadActiveIdx(q->streamState, t->activeIdxSize);
+ if (activeIdx == t->numSubEngines) {
+ return NFA_ZOMBIE_NO;
+ }
+ const struct NFA *sub = getSubEngine(t, activeIdx);
+
+ struct mq q1;
+ copyQueue(t, sub, q, &q1, activeIdx);
+ return nfaGetZombieStatus(sub, &q1, loc);
+}
+
+char nfaExecTamarama_Q(const struct NFA *n, struct mq *q, s64a end) {
+ DEBUG_PRINTF("exec\n");
+ struct mq q1;
+ char rv = MO_ALIVE;
+ char copy = 0;
+ const struct Tamarama *t = getImplNfa(n);
+ while (q->cur < q->end && q_cur_loc(q) <= end) {
+ updateQueues(t, q, &q1);
+ rv = nfaQueueExec_raw(q1.nfa, &q1, end);
+ q->report_current = q1.report_current;
+ copy = 1;
+ if (can_stop_matching(q->scratch)) {
+ break;
+ }
+ }
+ if (copy) {
+ copyBack(t, q, &q1);
+ }
+ return rv;
+}
+
+char nfaExecTamarama_Q2(const struct NFA *n, struct mq *q, s64a end) {
+ DEBUG_PRINTF("exec to match\n");
+ struct mq q1;
+ char rv = 0;
+ char copy = 0;
+ const struct Tamarama *t = getImplNfa(n);
+ while (q->cur < q->end && q_cur_loc(q) <= end &&
+ rv != MO_MATCHES_PENDING) {
+ updateQueues(t, q, &q1);
+ rv = nfaQueueExec2_raw(q1.nfa, &q1, end);
+ q->report_current = q1.report_current;
+ copy = 1;
+ if (can_stop_matching(q->scratch)) {
+ break;
+ }
+ }
+ if (copy) {
+ copyBack(t, q, &q1);
+ }
+ return rv;
+}
+
diff --git a/contrib/libs/hyperscan/src/nfa/tamarama.h b/contrib/libs/hyperscan/src/nfa/tamarama.h
index b4fba549fd1..3b52d8de73b 100644
--- a/contrib/libs/hyperscan/src/nfa/tamarama.h
+++ b/contrib/libs/hyperscan/src/nfa/tamarama.h
@@ -1,70 +1,70 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef TAMARAMA_H
-#define TAMARAMA_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include "callback.h"
-#include "ue2common.h"
-
-struct mq;
-struct NFA;
-struct hs_scratch;
-
-char nfaExecTamarama_testEOD(const struct NFA *n, const char *state,
- const char *streamState, u64a offset,
- NfaCallback callback, void *context);
-char nfaExecTamarama_QR(const struct NFA *n, struct mq *q, ReportID report);
-char nfaExecTamarama_reportCurrent(const struct NFA *n, struct mq *q);
-char nfaExecTamarama_inAccept(const struct NFA *n, ReportID report,
- struct mq *q);
-char nfaExecTamarama_inAnyAccept(const struct NFA *n, struct mq *q);
-char nfaExecTamarama_queueInitState(const struct NFA *n, struct mq *q);
-char nfaExecTamarama_queueCompressState(const struct NFA *n, const struct mq *q,
- s64a loc);
-char nfaExecTamarama_expandState(const struct NFA *n, void *dest,
- const void *src, u64a offset, u8 key);
-enum nfa_zombie_status nfaExecTamarama_zombie_status(const struct NFA *n,
- struct mq *q, s64a loc);
-char nfaExecTamarama_Q(const struct NFA *nfa, struct mq *q, s64a end);
-char nfaExecTamarama_Q2(const struct NFA *nfa, struct mq *q, s64a end);
-
-// only used by outfix and miracles, no implementation for tamarama
-#define nfaExecTamarama_initCompressedState NFA_API_NO_IMPL
-#define nfaExecTamarama_B_Reverse NFA_API_NO_IMPL
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef TAMARAMA_H
+#define TAMARAMA_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "callback.h"
+#include "ue2common.h"
+
+struct mq;
+struct NFA;
+struct hs_scratch;
+
+char nfaExecTamarama_testEOD(const struct NFA *n, const char *state,
+ const char *streamState, u64a offset,
+ NfaCallback callback, void *context);
+char nfaExecTamarama_QR(const struct NFA *n, struct mq *q, ReportID report);
+char nfaExecTamarama_reportCurrent(const struct NFA *n, struct mq *q);
+char nfaExecTamarama_inAccept(const struct NFA *n, ReportID report,
+ struct mq *q);
+char nfaExecTamarama_inAnyAccept(const struct NFA *n, struct mq *q);
+char nfaExecTamarama_queueInitState(const struct NFA *n, struct mq *q);
+char nfaExecTamarama_queueCompressState(const struct NFA *n, const struct mq *q,
+ s64a loc);
+char nfaExecTamarama_expandState(const struct NFA *n, void *dest,
+ const void *src, u64a offset, u8 key);
+enum nfa_zombie_status nfaExecTamarama_zombie_status(const struct NFA *n,
+ struct mq *q, s64a loc);
+char nfaExecTamarama_Q(const struct NFA *nfa, struct mq *q, s64a end);
+char nfaExecTamarama_Q2(const struct NFA *nfa, struct mq *q, s64a end);
+
+// only used by outfix and miracles, no implementation for tamarama
+#define nfaExecTamarama_initCompressedState NFA_API_NO_IMPL
+#define nfaExecTamarama_B_Reverse NFA_API_NO_IMPL
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/tamarama_internal.h b/contrib/libs/hyperscan/src/nfa/tamarama_internal.h
index 1e4bd48dbb5..5cdc70d4001 100644
--- a/contrib/libs/hyperscan/src/nfa/tamarama_internal.h
+++ b/contrib/libs/hyperscan/src/nfa/tamarama_internal.h
@@ -1,105 +1,105 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- *\brief Tamarama: container engine for exclusive engines,
- * data structures.
- */
-
-/* Tamarama bytecode layout:
- * * |-----|
- * * | | struct NFA
- * * |-----|
- * * | | struct Tamarama
- * * | |
- * * |-----|
- * * | | top remapping table:
- * * | | stores top base for each subengine.
- * * | | old_top = remapped_top - top_base;
- * * | | The size of table is equal to the number of subengines.
- * * ...
- * * | |
- * * |-----|
- * * | | offsets from the start of struct Tamarama to subengines --\
- * * ... |
- * * | | -----------\ |
- * * |-----| | |
- * * ||--| | subengine 1 (struct NFA + rest of subengine) <--/ |
- * * || | | |
- * * ||--| | |
- * * || | | |
- * * || | | |
- * * ||--| | |
- * * | | |
- * * ||--| | subengine 2 (struct NFA + rest of subengine) <-------/
- * * || | |
- * * ||--| |
- * * || | |
- * * || | |
- * * ||--| |
- * * | |
- * * ...
- * * | |
- * * |-----| total size of tamarama
- * *
- * * Tamarama stream state:
- * *
- * * |---|
- * * | | active subengine id
- * * |---|
- * * | | common pool of stream state for each engine
- * * | |
- * * | |
- * * ...
- * * | |
- * * | |
- * * |---|
- * *
- * * Tamarama scratch space:
- * *
- * * |---|
- * * | | common pool of scratch for each engine
- * * | |
- * * | |
- * * ...
- * * | |
- * * | |
- * * |---|
- * */
-
-#ifndef NFA_TAMARAMA_INTERNAL_H
-#define NFA_TAMARAMA_INTERNAL_H
-
-#include "ue2common.h"
-
-struct ALIGN_AVX_DIRECTIVE Tamarama {
- u32 numSubEngines;
- u8 activeIdxSize;
-};
-
-#endif // NFA_TAMARAMA_INTERNAL_H
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ *\brief Tamarama: container engine for exclusive engines,
+ * data structures.
+ */
+
+/* Tamarama bytecode layout:
+ * * |-----|
+ * * | | struct NFA
+ * * |-----|
+ * * | | struct Tamarama
+ * * | |
+ * * |-----|
+ * * | | top remapping table:
+ * * | | stores top base for each subengine.
+ * * | | old_top = remapped_top - top_base;
+ * * | | The size of table is equal to the number of subengines.
+ * * ...
+ * * | |
+ * * |-----|
+ * * | | offsets from the start of struct Tamarama to subengines --\
+ * * ... |
+ * * | | -----------\ |
+ * * |-----| | |
+ * * ||--| | subengine 1 (struct NFA + rest of subengine) <--/ |
+ * * || | | |
+ * * ||--| | |
+ * * || | | |
+ * * || | | |
+ * * ||--| | |
+ * * | | |
+ * * ||--| | subengine 2 (struct NFA + rest of subengine) <-------/
+ * * || | |
+ * * ||--| |
+ * * || | |
+ * * || | |
+ * * ||--| |
+ * * | |
+ * * ...
+ * * | |
+ * * |-----| total size of tamarama
+ * *
+ * * Tamarama stream state:
+ * *
+ * * |---|
+ * * | | active subengine id
+ * * |---|
+ * * | | common pool of stream state for each engine
+ * * | |
+ * * | |
+ * * ...
+ * * | |
+ * * | |
+ * * |---|
+ * *
+ * * Tamarama scratch space:
+ * *
+ * * |---|
+ * * | | common pool of scratch for each engine
+ * * | |
+ * * | |
+ * * ...
+ * * | |
+ * * | |
+ * * |---|
+ * */
+
+#ifndef NFA_TAMARAMA_INTERNAL_H
+#define NFA_TAMARAMA_INTERNAL_H
+
+#include "ue2common.h"
+
+struct ALIGN_AVX_DIRECTIVE Tamarama {
+ u32 numSubEngines;
+ u8 activeIdxSize;
+};
+
+#endif // NFA_TAMARAMA_INTERNAL_H
diff --git a/contrib/libs/hyperscan/src/nfa/tamaramacompile.cpp b/contrib/libs/hyperscan/src/nfa/tamaramacompile.cpp
index 5892f527825..1a6e8beff93 100644
--- a/contrib/libs/hyperscan/src/nfa/tamaramacompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/tamaramacompile.cpp
@@ -1,176 +1,176 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Tamarama: container engine for exclusive engines, compiler code.
- */
-
-#include "config.h"
-
-#include "tamaramacompile.h"
-
-#include "tamarama_internal.h"
-#include "nfa_internal.h"
-#include "nfa_api_queue.h"
-#include "repeatcompile.h"
-#include "util/container.h"
-#include "util/verify_types.h"
-
-using namespace std;
-
-namespace ue2 {
-
-static
-void remapTops(const TamaInfo &tamaInfo,
- vector<u32> &top_base,
- map<pair<const NFA *, u32>, u32> &out_top_remap) {
- u32 i = 0;
- u32 cur = 0;
- for (const auto &sub : tamaInfo.subengines) {
- u32 base = cur;
- top_base.push_back(base + MQE_TOP_FIRST);
- DEBUG_PRINTF("subengine:%u\n", i);
- for (const auto &t : tamaInfo.tops[i++]) {
- cur = base + t;
- DEBUG_PRINTF("top remapping %u:%u\n", t ,cur);
- out_top_remap.emplace(make_pair(sub, t), cur++);
- }
- }
-}
-
-/**
- * update stream state and scratch state sizes and copy in
- * subengines in Tamarama.
- */
-static
-void copyInSubnfas(const char *base_offset, NFA &nfa,
- const TamaInfo &tamaInfo, u32 *offsets,
- char *sub_nfa_offset, const u32 activeIdxSize) {
- u32 maxStreamStateSize = 0;
- u32 maxScratchStateSize = 0;
- sub_nfa_offset = ROUNDUP_PTR(sub_nfa_offset, 64);
- bool infinite_max_width = false;
- for (auto &sub : tamaInfo.subengines) {
- u32 streamStateSize = verify_u32(sub->streamStateSize);
- u32 scratchStateSize = verify_u32(sub->scratchStateSize);
- maxStreamStateSize = max(maxStreamStateSize, streamStateSize);
- maxScratchStateSize = max(maxScratchStateSize, scratchStateSize);
- sub->queueIndex = nfa.queueIndex;
-
- memcpy(sub_nfa_offset, sub, sub->length);
- *offsets = verify_u32(sub_nfa_offset - base_offset);
- DEBUG_PRINTF("type:%u offsets:%u\n", sub->type, *offsets);
- ++offsets;
- sub_nfa_offset += ROUNDUP_CL(sub->length);
-
- // update nfa properties
- nfa.flags |= sub->flags;
- if (!sub->maxWidth) {
- infinite_max_width = true;
- } else if (!infinite_max_width) {
- nfa.maxWidth = max(nfa.maxWidth, sub->maxWidth);
- }
- }
-
- if (infinite_max_width) {
- nfa.maxWidth = 0;
- }
- nfa.maxBiAnchoredWidth = 0;
- nfa.streamStateSize = activeIdxSize + maxStreamStateSize;
- nfa.scratchStateSize = maxScratchStateSize;
-}
-
-/**
- * Take in a collection of exclusive sub engines and produces a tamarama, also
- * returns via out_top_remap, a mapping indicating how tops in the subengines in
- * relate to the tamarama's tops.
- */
-bytecode_ptr<NFA>
-buildTamarama(const TamaInfo &tamaInfo, const u32 queue,
- map<pair<const NFA *, u32>, u32> &out_top_remap) {
- vector<u32> top_base;
- remapTops(tamaInfo, top_base, out_top_remap);
-
- size_t subSize = tamaInfo.subengines.size();
- DEBUG_PRINTF("subSize:%zu\n", subSize);
- size_t total_size =
- sizeof(NFA) + // initial NFA structure
- sizeof(Tamarama) + // Tamarama structure
- sizeof(u32) * subSize + // base top event value for subengines,
- // used for top remapping at runtime
- sizeof(u32) * subSize + 64; // offsets to subengines in bytecode and
- // padding for subengines
-
- for (const auto &sub : tamaInfo.subengines) {
- total_size += ROUNDUP_CL(sub->length);
- }
-
- // use subSize as a sentinel value for no active subengines,
- // so add one to subSize here
- u32 activeIdxSize = calcPackedBytes(subSize + 1);
- auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
- nfa->type = verify_u8(TAMARAMA_NFA);
- nfa->length = verify_u32(total_size);
- nfa->queueIndex = queue;
-
- char *ptr = (char *)nfa.get() + sizeof(NFA);
- char *base_offset = ptr;
- Tamarama *t = (Tamarama *)ptr;
- t->numSubEngines = verify_u32(subSize);
- t->activeIdxSize = verify_u8(activeIdxSize);
-
- ptr += sizeof(Tamarama);
- copy_bytes(ptr, top_base);
- ptr += byte_length(top_base);
-
- u32 *offsets = (u32 *)ptr;
- char *sub_nfa_offset = ptr + sizeof(u32) * subSize;
- copyInSubnfas(base_offset, *nfa, tamaInfo, offsets, sub_nfa_offset,
- activeIdxSize);
- assert((size_t)(sub_nfa_offset - (char *)nfa.get()) <= total_size);
- return nfa;
-}
-
-set<ReportID> all_reports(const TamaProto &proto) {
- return proto.reports;
-}
-
-void TamaInfo::add(NFA *sub, const set<u32> &top) {
- assert(subengines.size() < max_occupancy);
- subengines.push_back(sub);
- tops.push_back(top);
-}
-
-void TamaProto::add(const NFA *n, const u32 id, const u32 top,
- const map<pair<const NFA *, u32>, u32> &out_top_remap) {
- top_remap.emplace(make_pair(id, top), out_top_remap.at(make_pair(n, top)));
-}
-
-} // namespace ue2
-
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Tamarama: container engine for exclusive engines, compiler code.
+ */
+
+#include "config.h"
+
+#include "tamaramacompile.h"
+
+#include "tamarama_internal.h"
+#include "nfa_internal.h"
+#include "nfa_api_queue.h"
+#include "repeatcompile.h"
+#include "util/container.h"
+#include "util/verify_types.h"
+
+using namespace std;
+
+namespace ue2 {
+
+static
+void remapTops(const TamaInfo &tamaInfo,
+ vector<u32> &top_base,
+ map<pair<const NFA *, u32>, u32> &out_top_remap) {
+ u32 i = 0;
+ u32 cur = 0;
+ for (const auto &sub : tamaInfo.subengines) {
+ u32 base = cur;
+ top_base.push_back(base + MQE_TOP_FIRST);
+ DEBUG_PRINTF("subengine:%u\n", i);
+ for (const auto &t : tamaInfo.tops[i++]) {
+ cur = base + t;
+ DEBUG_PRINTF("top remapping %u:%u\n", t ,cur);
+ out_top_remap.emplace(make_pair(sub, t), cur++);
+ }
+ }
+}
+
+/**
+ * update stream state and scratch state sizes and copy in
+ * subengines in Tamarama.
+ */
+static
+void copyInSubnfas(const char *base_offset, NFA &nfa,
+ const TamaInfo &tamaInfo, u32 *offsets,
+ char *sub_nfa_offset, const u32 activeIdxSize) {
+ u32 maxStreamStateSize = 0;
+ u32 maxScratchStateSize = 0;
+ sub_nfa_offset = ROUNDUP_PTR(sub_nfa_offset, 64);
+ bool infinite_max_width = false;
+ for (auto &sub : tamaInfo.subengines) {
+ u32 streamStateSize = verify_u32(sub->streamStateSize);
+ u32 scratchStateSize = verify_u32(sub->scratchStateSize);
+ maxStreamStateSize = max(maxStreamStateSize, streamStateSize);
+ maxScratchStateSize = max(maxScratchStateSize, scratchStateSize);
+ sub->queueIndex = nfa.queueIndex;
+
+ memcpy(sub_nfa_offset, sub, sub->length);
+ *offsets = verify_u32(sub_nfa_offset - base_offset);
+ DEBUG_PRINTF("type:%u offsets:%u\n", sub->type, *offsets);
+ ++offsets;
+ sub_nfa_offset += ROUNDUP_CL(sub->length);
+
+ // update nfa properties
+ nfa.flags |= sub->flags;
+ if (!sub->maxWidth) {
+ infinite_max_width = true;
+ } else if (!infinite_max_width) {
+ nfa.maxWidth = max(nfa.maxWidth, sub->maxWidth);
+ }
+ }
+
+ if (infinite_max_width) {
+ nfa.maxWidth = 0;
+ }
+ nfa.maxBiAnchoredWidth = 0;
+ nfa.streamStateSize = activeIdxSize + maxStreamStateSize;
+ nfa.scratchStateSize = maxScratchStateSize;
+}
+
+/**
+ * Take in a collection of exclusive sub engines and produces a tamarama, also
+ * returns via out_top_remap, a mapping indicating how tops in the subengines in
+ * relate to the tamarama's tops.
+ */
+bytecode_ptr<NFA>
+buildTamarama(const TamaInfo &tamaInfo, const u32 queue,
+ map<pair<const NFA *, u32>, u32> &out_top_remap) {
+ vector<u32> top_base;
+ remapTops(tamaInfo, top_base, out_top_remap);
+
+ size_t subSize = tamaInfo.subengines.size();
+ DEBUG_PRINTF("subSize:%zu\n", subSize);
+ size_t total_size =
+ sizeof(NFA) + // initial NFA structure
+ sizeof(Tamarama) + // Tamarama structure
+ sizeof(u32) * subSize + // base top event value for subengines,
+ // used for top remapping at runtime
+ sizeof(u32) * subSize + 64; // offsets to subengines in bytecode and
+ // padding for subengines
+
+ for (const auto &sub : tamaInfo.subengines) {
+ total_size += ROUNDUP_CL(sub->length);
+ }
+
+ // use subSize as a sentinel value for no active subengines,
+ // so add one to subSize here
+ u32 activeIdxSize = calcPackedBytes(subSize + 1);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(total_size);
+ nfa->type = verify_u8(TAMARAMA_NFA);
+ nfa->length = verify_u32(total_size);
+ nfa->queueIndex = queue;
+
+ char *ptr = (char *)nfa.get() + sizeof(NFA);
+ char *base_offset = ptr;
+ Tamarama *t = (Tamarama *)ptr;
+ t->numSubEngines = verify_u32(subSize);
+ t->activeIdxSize = verify_u8(activeIdxSize);
+
+ ptr += sizeof(Tamarama);
+ copy_bytes(ptr, top_base);
+ ptr += byte_length(top_base);
+
+ u32 *offsets = (u32 *)ptr;
+ char *sub_nfa_offset = ptr + sizeof(u32) * subSize;
+ copyInSubnfas(base_offset, *nfa, tamaInfo, offsets, sub_nfa_offset,
+ activeIdxSize);
+ assert((size_t)(sub_nfa_offset - (char *)nfa.get()) <= total_size);
+ return nfa;
+}
+
+set<ReportID> all_reports(const TamaProto &proto) {
+ return proto.reports;
+}
+
+void TamaInfo::add(NFA *sub, const set<u32> &top) {
+ assert(subengines.size() < max_occupancy);
+ subengines.push_back(sub);
+ tops.push_back(top);
+}
+
+void TamaProto::add(const NFA *n, const u32 id, const u32 top,
+ const map<pair<const NFA *, u32>, u32> &out_top_remap) {
+ top_remap.emplace(make_pair(id, top), out_top_remap.at(make_pair(n, top)));
+}
+
+} // namespace ue2
+
diff --git a/contrib/libs/hyperscan/src/nfa/tamaramacompile.h b/contrib/libs/hyperscan/src/nfa/tamaramacompile.h
index ce97d0adcd3..7fcea3ec85a 100644
--- a/contrib/libs/hyperscan/src/nfa/tamaramacompile.h
+++ b/contrib/libs/hyperscan/src/nfa/tamaramacompile.h
@@ -1,96 +1,96 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Tamarama: container engine for exclusive engines, compiler code.
- */
-
-#ifndef NFA_TAMARAMACOMPILE_H
-#define NFA_TAMARAMACOMPILE_H
-
-#include "ue2common.h"
-#include "util/bytecode_ptr.h"
-
-#include <map>
-#include <set>
-#include <vector>
-
-struct NFA;
-
-namespace ue2 {
-
-/**
- * \brief A TamaProto that contains top remapping and reports info.
- */
-struct TamaProto {
- void add(const NFA *n, const u32 id, const u32 top,
- const std::map<std::pair<const NFA *, u32>, u32> &out_top_remap);
- /** Top remapping between <vertex id, top value> and
- ** remapped top value. */
- std::map<std::pair<u32, u32>, u32> top_remap;
-
- /** All the reports in subengines */
- std::set<ReportID> reports;
-};
-
-/**
- * \brief Construction info for a Tamarama engine:
- * contains at least two subengines.
- *
- * A TamaInfo is converted into a single NFA, with each top triggering a
- * subengine. A TamaInfo can contain at most TamaInfo::max_occupancy
- * subengines.
- */
-struct TamaInfo {
- static constexpr size_t max_occupancy = 65536; // arbitrary limit
-
- /** \brief Add a new subengine. */
- void add(NFA *sub, const std::set<u32> &top);
-
- /** \brief All the subengines */
- std::vector<NFA *> subengines;
-
- /** \brief Tops of subengines */
- std::vector<std::set<u32>> tops;
-};
-
-std::set<ReportID> all_reports(const TamaProto &proto);
-
-/**
- * Take in a collection of exclusive subengines and produces a tamarama, also
- * returns via out_top_remap, a mapping indicating how tops in the subengines in
- * relate to the tamarama's tops.
- */
-bytecode_ptr<NFA>
-buildTamarama(const TamaInfo &tamaInfo, const u32 queue,
- std::map<std::pair<const NFA *, u32>, u32> &out_top_remap);
-
-} // namespace ue2
-
-#endif // NFA_TAMARAMACOMPILE_H
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Tamarama: container engine for exclusive engines, compiler code.
+ */
+
+#ifndef NFA_TAMARAMACOMPILE_H
+#define NFA_TAMARAMACOMPILE_H
+
+#include "ue2common.h"
+#include "util/bytecode_ptr.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+struct NFA;
+
+namespace ue2 {
+
+/**
+ * \brief A TamaProto that contains top remapping and reports info.
+ */
+struct TamaProto {
+ void add(const NFA *n, const u32 id, const u32 top,
+ const std::map<std::pair<const NFA *, u32>, u32> &out_top_remap);
+ /** Top remapping between <vertex id, top value> and
+ ** remapped top value. */
+ std::map<std::pair<u32, u32>, u32> top_remap;
+
+ /** All the reports in subengines */
+ std::set<ReportID> reports;
+};
+
+/**
+ * \brief Construction info for a Tamarama engine:
+ * contains at least two subengines.
+ *
+ * A TamaInfo is converted into a single NFA, with each top triggering a
+ * subengine. A TamaInfo can contain at most TamaInfo::max_occupancy
+ * subengines.
+ */
+struct TamaInfo {
+ static constexpr size_t max_occupancy = 65536; // arbitrary limit
+
+ /** \brief Add a new subengine. */
+ void add(NFA *sub, const std::set<u32> &top);
+
+ /** \brief All the subengines */
+ std::vector<NFA *> subengines;
+
+ /** \brief Tops of subengines */
+ std::vector<std::set<u32>> tops;
+};
+
+std::set<ReportID> all_reports(const TamaProto &proto);
+
+/**
+ * Take in a collection of exclusive subengines and produces a tamarama, also
+ * returns via out_top_remap, a mapping indicating how tops in the subengines in
+ * relate to the tamarama's tops.
+ */
+bytecode_ptr<NFA>
+buildTamarama(const TamaInfo &tamaInfo, const u32 queue,
+ std::map<std::pair<const NFA *, u32>, u32> &out_top_remap);
+
+} // namespace ue2
+
+#endif // NFA_TAMARAMACOMPILE_H
diff --git a/contrib/libs/hyperscan/src/nfa/truffle.c b/contrib/libs/hyperscan/src/nfa/truffle.c
index 86a5bff446b..be6b312cf27 100644
--- a/contrib/libs/hyperscan/src/nfa/truffle.c
+++ b/contrib/libs/hyperscan/src/nfa/truffle.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,29 +33,29 @@
#include "ue2common.h"
#include "truffle.h"
-#include "util/arch.h"
+#include "util/arch.h"
#include "util/bitutils.h"
#include "util/simd_utils.h"
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
static really_inline
-const u8 *lastMatch(const u8 *buf, u32 z) {
+const u8 *lastMatch(const u8 *buf, u32 z) {
if (unlikely(z != 0xffff)) {
- u32 pos = clz32(~z & 0xffff);
- assert(pos >= 16 && pos < 32);
- return buf + (31 - pos);
+ u32 pos = clz32(~z & 0xffff);
+ assert(pos >= 16 && pos < 32);
+ return buf + (31 - pos);
}
return NULL; // no match
}
static really_inline
-const u8 *firstMatch(const u8 *buf, u32 z) {
+const u8 *firstMatch(const u8 *buf, u32 z) {
if (unlikely(z != 0xffff)) {
- u32 pos = ctz32(~z & 0xffff);
- assert(pos < 16);
- return buf + pos;
+ u32 pos = ctz32(~z & 0xffff);
+ assert(pos < 16);
+ return buf + pos;
}
return NULL; // no match
@@ -68,11 +68,11 @@ u32 block(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset, m128 v) {
m128 shuf_mask_hi = _mm_set1_epi64x(0x8040201008040201);
// and now do the real work
- m128 shuf1 = pshufb_m128(shuf_mask_lo_highclear, v);
+ m128 shuf1 = pshufb_m128(shuf_mask_lo_highclear, v);
m128 t1 = xor128(v, highconst);
- m128 shuf2 = pshufb_m128(shuf_mask_lo_highset, t1);
- m128 t2 = andnot128(highconst, rshift64_m128(v, 4));
- m128 shuf3 = pshufb_m128(shuf_mask_hi, t2);
+ m128 shuf2 = pshufb_m128(shuf_mask_lo_highset, t1);
+ m128 t2 = andnot128(highconst, rshift64_m128(v, 4));
+ m128 shuf3 = pshufb_m128(shuf_mask_hi, t2);
m128 tmp = and128(or128(shuf1, shuf2), shuf3);
m128 tmp2 = eq128(tmp, zeroes128());
u32 z = movemask128(tmp2);
@@ -91,8 +91,8 @@ const u8 *truffleMini(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
// can't be these bytes in z
- u32 mask = (0xffff >> (16 - len)) ^ 0xffff;
- const u8 *rv = firstMatch(buf, z | mask);
+ u32 mask = (0xffff >> (16 - len)) ^ 0xffff;
+ const u8 *rv = firstMatch(buf, z | mask);
if (rv) {
return rv;
@@ -101,23 +101,23 @@ const u8 *truffleMini(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
}
}
-static really_inline
-const u8 *fwdBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
- m128 v, const u8 *buf) {
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return firstMatch(buf, z);
-}
-
-static really_inline
-const u8 *revBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
- m128 v, const u8 *buf) {
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return lastMatch(buf, z);
-}
-
+static really_inline
+const u8 *fwdBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
+ m128 v, const u8 *buf) {
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *revBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
+ m128 v, const u8 *buf) {
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return lastMatch(buf, z);
+}
+
const u8 *truffleExec(m128 shuf_mask_lo_highclear,
- m128 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
+ m128 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
DEBUG_PRINTF("len %zu\n", buf_end - buf);
assert(buf && buf_end);
@@ -166,15 +166,15 @@ const u8 *truffleExec(m128 shuf_mask_lo_highclear,
static
const u8 *truffleRevMini(m128 shuf_mask_lo_highclear,
- m128 shuf_mask_lo_highset, const u8 *buf,
- const u8 *buf_end) {
+ m128 shuf_mask_lo_highset, const u8 *buf,
+ const u8 *buf_end) {
uintptr_t len = buf_end - buf;
assert(len < 16);
m128 chars = zeroes128();
memcpy(&chars, buf, len);
- u32 mask = (0xffff >> (16 - len)) ^ 0xffff;
+ u32 mask = (0xffff >> (16 - len)) ^ 0xffff;
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
const u8 *rv = lastMatch(buf, z | mask);
@@ -231,378 +231,378 @@ const u8 *rtruffleExec(m128 shuf_mask_lo_highclear,
return buf - 1;
}
-#elif !defined(HAVE_AVX512)
-
-// AVX2
-
-static really_inline
-const u8 *lastMatch(const u8 *buf, u32 z) {
- if (unlikely(z != 0xffffffff)) {
- u32 pos = clz32(~z);
- assert(pos < 32);
- return buf + (31 - pos);
- }
-
- return NULL; // no match
-}
-
-static really_inline
-const u8 *firstMatch(const u8 *buf, u32 z) {
- if (unlikely(z != 0xffffffff)) {
- u32 pos = ctz32(~z);
- assert(pos < 32);
- return buf + pos;
- }
-
- return NULL; // no match
-}
-
-static really_inline
-u32 block(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset, m256 v) {
-
- m256 highconst = _mm256_set1_epi8(0x80);
- m256 shuf_mask_hi = _mm256_set1_epi64x(0x8040201008040201);
-
- // and now do the real work
- m256 shuf1 = pshufb_m256(shuf_mask_lo_highclear, v);
- m256 t1 = xor256(v, highconst);
- m256 shuf2 = pshufb_m256(shuf_mask_lo_highset, t1);
- m256 t2 = andnot256(highconst, rshift64_m256(v, 4));
- m256 shuf3 = pshufb_m256(shuf_mask_hi, t2);
- m256 tmp = and256(or256(shuf1, shuf2), shuf3);
- m256 tmp2 = eq256(tmp, zeroes256());
- u32 z = movemask256(tmp2);
-
- return z;
-}
-
-static
-const u8 *truffleMini(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- uintptr_t len = buf_end - buf;
- assert(len < 32);
-
- m256 chars = zeroes256();
- memcpy(&chars, buf, len);
-
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
- // can't be these bytes in z
- u32 mask = (0xffffffff >> (32 - len)) ^ 0xffffffff;
- const u8 *rv = firstMatch(buf, z | mask);
-
- if (rv) {
- return rv;
- } else {
- return buf_end;
- }
-}
-
-static really_inline
-const u8 *fwdBlock(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
- m256 v, const u8 *buf) {
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return firstMatch(buf, z);
-}
-
-static really_inline
-const u8 *revBlock(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
- m256 v, const u8 *buf) {
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return lastMatch(buf, z);
-}
-
-const u8 *truffleExec(m128 shuf_mask_lo_highclear,
- m128 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- DEBUG_PRINTF("len %zu\n", buf_end - buf);
- const m256 wide_clear = set2x128(shuf_mask_lo_highclear);
- const m256 wide_set = set2x128(shuf_mask_lo_highset);
-
- assert(buf && buf_end);
- assert(buf < buf_end);
- const u8 *rv;
-
- if (buf_end - buf < 32) {
- return truffleMini(wide_clear, wide_set, buf, buf_end);
- }
-
- size_t min = (size_t)buf % 32;
- assert(buf_end - buf >= 32);
-
- // Preconditioning: most of the time our buffer won't be aligned.
- m256 chars = loadu256(buf);
- rv = fwdBlock(wide_clear, wide_set, chars, buf);
- if (rv) {
- return rv;
- }
- buf += (32 - min);
-
- const u8 *last_block = buf_end - 32;
- while (buf < last_block) {
- m256 lchars = load256(buf);
- rv = fwdBlock(wide_clear, wide_set, lchars, buf);
- if (rv) {
- return rv;
- }
- buf += 32;
- }
-
- // Use an unaligned load to mop up the last 32 bytes and get an accurate
- // picture to buf_end.
- assert(buf <= buf_end && buf >= buf_end - 32);
- chars = loadu256(buf_end - 32);
- rv = fwdBlock(wide_clear, wide_set, chars, buf_end - 32);
- if (rv) {
- return rv;
- }
- return buf_end;
-}
-
-static
-const u8 *truffleRevMini(m256 shuf_mask_lo_highclear,
- m256 shuf_mask_lo_highset, const u8 *buf,
- const u8 *buf_end) {
- uintptr_t len = buf_end - buf;
- assert(len < 32);
-
- m256 chars = zeroes256();
- memcpy(&chars, buf, len);
-
- u32 mask = (0xffffffff >> (32 - len)) ^ 0xffffffff;
- u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
- const u8 *rv = lastMatch(buf, z | mask);
-
- if (rv) {
- return rv;
- }
- return buf - 1;
-}
-
-
-const u8 *rtruffleExec(m128 shuf_mask_lo_highclear,
- m128 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- const m256 wide_clear = set2x128(shuf_mask_lo_highclear);
- const m256 wide_set = set2x128(shuf_mask_lo_highset);
- assert(buf && buf_end);
- assert(buf < buf_end);
- const u8 *rv;
-
- DEBUG_PRINTF("len %zu\n", buf_end - buf);
-
- if (buf_end - buf < 32) {
- return truffleRevMini(wide_clear, wide_set, buf, buf_end);
- }
-
- assert(buf_end - buf >= 32);
-
- // Preconditioning: most of the time our buffer won't be aligned.
- m256 chars = loadu256(buf_end - 32);
- rv = revBlock(wide_clear, wide_set, chars,
- buf_end - 32);
- if (rv) {
- return rv;
- }
- buf_end = (const u8 *)((size_t)buf_end & ~((size_t)0x1f));
-
- const u8 *last_block = buf + 32;
- while (buf_end > last_block) {
- buf_end -= 32;
- m256 lchars = load256(buf_end);
- rv = revBlock(wide_clear, wide_set, lchars, buf_end);
- if (rv) {
- return rv;
- }
- }
-
- // Use an unaligned load to mop up the last 32 bytes and get an accurate
- // picture to buf_end.
- chars = loadu256(buf);
- rv = revBlock(wide_clear, wide_set, chars, buf);
- if (rv) {
- return rv;
- }
- return buf - 1;
-}
-
-#else // AVX512
-
-static really_inline
-const u8 *lastMatch(const u8 *buf, u64a z) {
- if (unlikely(z != ~0ULL)) {
- u64a pos = clz64(~z);
- assert(pos < 64);
- return buf + (63 - pos);
- }
-
- return NULL; // no match
-}
-
-static really_inline
-const u8 *firstMatch(const u8 *buf, u64a z) {
- if (unlikely(z != ~0ULL)) {
- u64a pos = ctz64(~z);
- assert(pos < 64);
- DEBUG_PRINTF("pos %llu\n", pos);
- return buf + pos;
- }
-
- return NULL; // no match
-}
-
-static really_inline
-u64a block(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset, m512 v) {
- m512 highconst = set64x8(0x80);
- m512 shuf_mask_hi = set8x64(0x8040201008040201);
-
- // and now do the real work
- m512 shuf1 = pshufb_m512(shuf_mask_lo_highclear, v);
- m512 t1 = xor512(v, highconst);
- m512 shuf2 = pshufb_m512(shuf_mask_lo_highset, t1);
- m512 t2 = andnot512(highconst, rshift64_m512(v, 4));
- m512 shuf3 = pshufb_m512(shuf_mask_hi, t2);
- m512 tmp = and512(or512(shuf1, shuf2), shuf3);
- u64a z = eq512mask(tmp, zeroes512());
-
- return z;
-}
-
-static really_inline
-const u8 *truffleMini(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- uintptr_t len = buf_end - buf;
- assert(len <= 64);
-
- __mmask64 mask = (~0ULL) >> (64 - len);
-
- m512 chars = loadu_maskz_m512(mask, buf);
-
- u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
-
- const u8 *rv = firstMatch(buf, z | ~mask);
-
- return rv;
-}
-
-static really_inline
-const u8 *fwdBlock(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
- m512 v, const u8 *buf) {
- u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return firstMatch(buf, z);
-}
-
-static really_inline
-const u8 *revBlock(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
- m512 v, const u8 *buf) {
- u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
- return lastMatch(buf, z);
-}
-
-const u8 *truffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- DEBUG_PRINTF("len %zu\n", buf_end - buf);
- const m512 wide_clear = set4x128(shuf_mask_lo_highclear);
- const m512 wide_set = set4x128(shuf_mask_lo_highset);
-
- assert(buf && buf_end);
- assert(buf < buf_end);
- const u8 *rv;
-
- if (buf_end - buf <= 64) {
- rv = truffleMini(wide_clear, wide_set, buf, buf_end);
- return rv ? rv : buf_end;
- }
-
- assert(buf_end - buf >= 64);
- if ((uintptr_t)buf % 64) {
- // Preconditioning: most of the time our buffer won't be aligned.
- rv = truffleMini(wide_clear, wide_set, buf, ROUNDUP_PTR(buf, 64));
- if (rv) {
- return rv;
- }
- buf = ROUNDUP_PTR(buf, 64);
- }
- const u8 *last_block = buf_end - 64;
- while (buf < last_block) {
- m512 lchars = load512(buf);
- rv = fwdBlock(wide_clear, wide_set, lchars, buf);
- if (rv) {
- return rv;
- }
- buf += 64;
- }
-
- // Use an unaligned load to mop up the last 64 bytes and get an accurate
- // picture to buf_end.
- assert(buf <= buf_end && buf >= buf_end - 64);
- m512 chars = loadu512(buf_end - 64);
- rv = fwdBlock(wide_clear, wide_set, chars, buf_end - 64);
- if (rv) {
- return rv;
- }
- return buf_end;
-}
-
-static really_inline
-const u8 *truffleRevMini(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- uintptr_t len = buf_end - buf;
- assert(len < 64);
-
- __mmask64 mask = (~0ULL) >> (64 - len);
- m512 chars = loadu_maskz_m512(mask, buf);
- u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
- DEBUG_PRINTF("mask 0x%016llx z 0x%016llx\n", mask, z);
- const u8 *rv = lastMatch(buf, z | ~mask);
-
- if (rv) {
- return rv;
- }
- return buf - 1;
-}
-
-const u8 *rtruffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
- const u8 *buf, const u8 *buf_end) {
- const m512 wide_clear = set4x128(shuf_mask_lo_highclear);
- const m512 wide_set = set4x128(shuf_mask_lo_highset);
- assert(buf && buf_end);
- assert(buf < buf_end);
- const u8 *rv;
-
- DEBUG_PRINTF("len %zu\n", buf_end - buf);
-
- if (buf_end - buf < 64) {
- return truffleRevMini(wide_clear, wide_set, buf, buf_end);
- }
-
- assert(buf_end - buf >= 64);
-
- // Preconditioning: most of the time our buffer won't be aligned.
- m512 chars = loadu512(buf_end - 64);
- rv = revBlock(wide_clear, wide_set, chars, buf_end - 64);
- if (rv) {
- return rv;
- }
- buf_end = (const u8 *)ROUNDDOWN_N((uintptr_t)buf_end, 64);
-
- const u8 *last_block = buf + 64;
- while (buf_end > last_block) {
- buf_end -= 64;
- m512 lchars = load512(buf_end);
- rv = revBlock(wide_clear, wide_set, lchars, buf_end);
- if (rv) {
- return rv;
- }
- }
-
- // Use an unaligned load to mop up the last 64 bytes and get an accurate
- // picture to buf_end.
- chars = loadu512(buf);
- rv = revBlock(wide_clear, wide_set, chars, buf);
- if (rv) {
- return rv;
- }
- return buf - 1;
-}
-
-#endif
+#elif !defined(HAVE_AVX512)
+
+// AVX2
+
+static really_inline
+const u8 *lastMatch(const u8 *buf, u32 z) {
+ if (unlikely(z != 0xffffffff)) {
+ u32 pos = clz32(~z);
+ assert(pos < 32);
+ return buf + (31 - pos);
+ }
+
+ return NULL; // no match
+}
+
+static really_inline
+const u8 *firstMatch(const u8 *buf, u32 z) {
+ if (unlikely(z != 0xffffffff)) {
+ u32 pos = ctz32(~z);
+ assert(pos < 32);
+ return buf + pos;
+ }
+
+ return NULL; // no match
+}
+
+static really_inline
+u32 block(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset, m256 v) {
+
+ m256 highconst = _mm256_set1_epi8(0x80);
+ m256 shuf_mask_hi = _mm256_set1_epi64x(0x8040201008040201);
+
+ // and now do the real work
+ m256 shuf1 = pshufb_m256(shuf_mask_lo_highclear, v);
+ m256 t1 = xor256(v, highconst);
+ m256 shuf2 = pshufb_m256(shuf_mask_lo_highset, t1);
+ m256 t2 = andnot256(highconst, rshift64_m256(v, 4));
+ m256 shuf3 = pshufb_m256(shuf_mask_hi, t2);
+ m256 tmp = and256(or256(shuf1, shuf2), shuf3);
+ m256 tmp2 = eq256(tmp, zeroes256());
+ u32 z = movemask256(tmp2);
+
+ return z;
+}
+
+static
+const u8 *truffleMini(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ uintptr_t len = buf_end - buf;
+ assert(len < 32);
+
+ m256 chars = zeroes256();
+ memcpy(&chars, buf, len);
+
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
+ // can't be these bytes in z
+ u32 mask = (0xffffffff >> (32 - len)) ^ 0xffffffff;
+ const u8 *rv = firstMatch(buf, z | mask);
+
+ if (rv) {
+ return rv;
+ } else {
+ return buf_end;
+ }
+}
+
+static really_inline
+const u8 *fwdBlock(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
+ m256 v, const u8 *buf) {
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *revBlock(m256 shuf_mask_lo_highclear, m256 shuf_mask_lo_highset,
+ m256 v, const u8 *buf) {
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return lastMatch(buf, z);
+}
+
+const u8 *truffleExec(m128 shuf_mask_lo_highclear,
+ m128 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ DEBUG_PRINTF("len %zu\n", buf_end - buf);
+ const m256 wide_clear = set2x128(shuf_mask_lo_highclear);
+ const m256 wide_set = set2x128(shuf_mask_lo_highset);
+
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+ const u8 *rv;
+
+ if (buf_end - buf < 32) {
+ return truffleMini(wide_clear, wide_set, buf, buf_end);
+ }
+
+ size_t min = (size_t)buf % 32;
+ assert(buf_end - buf >= 32);
+
+ // Preconditioning: most of the time our buffer won't be aligned.
+ m256 chars = loadu256(buf);
+ rv = fwdBlock(wide_clear, wide_set, chars, buf);
+ if (rv) {
+ return rv;
+ }
+ buf += (32 - min);
+
+ const u8 *last_block = buf_end - 32;
+ while (buf < last_block) {
+ m256 lchars = load256(buf);
+ rv = fwdBlock(wide_clear, wide_set, lchars, buf);
+ if (rv) {
+ return rv;
+ }
+ buf += 32;
+ }
+
+ // Use an unaligned load to mop up the last 32 bytes and get an accurate
+ // picture to buf_end.
+ assert(buf <= buf_end && buf >= buf_end - 32);
+ chars = loadu256(buf_end - 32);
+ rv = fwdBlock(wide_clear, wide_set, chars, buf_end - 32);
+ if (rv) {
+ return rv;
+ }
+ return buf_end;
+}
+
+static
+const u8 *truffleRevMini(m256 shuf_mask_lo_highclear,
+ m256 shuf_mask_lo_highset, const u8 *buf,
+ const u8 *buf_end) {
+ uintptr_t len = buf_end - buf;
+ assert(len < 32);
+
+ m256 chars = zeroes256();
+ memcpy(&chars, buf, len);
+
+ u32 mask = (0xffffffff >> (32 - len)) ^ 0xffffffff;
+ u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
+ const u8 *rv = lastMatch(buf, z | mask);
+
+ if (rv) {
+ return rv;
+ }
+ return buf - 1;
+}
+
+
+const u8 *rtruffleExec(m128 shuf_mask_lo_highclear,
+ m128 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ const m256 wide_clear = set2x128(shuf_mask_lo_highclear);
+ const m256 wide_set = set2x128(shuf_mask_lo_highset);
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+ const u8 *rv;
+
+ DEBUG_PRINTF("len %zu\n", buf_end - buf);
+
+ if (buf_end - buf < 32) {
+ return truffleRevMini(wide_clear, wide_set, buf, buf_end);
+ }
+
+ assert(buf_end - buf >= 32);
+
+ // Preconditioning: most of the time our buffer won't be aligned.
+ m256 chars = loadu256(buf_end - 32);
+ rv = revBlock(wide_clear, wide_set, chars,
+ buf_end - 32);
+ if (rv) {
+ return rv;
+ }
+ buf_end = (const u8 *)((size_t)buf_end & ~((size_t)0x1f));
+
+ const u8 *last_block = buf + 32;
+ while (buf_end > last_block) {
+ buf_end -= 32;
+ m256 lchars = load256(buf_end);
+ rv = revBlock(wide_clear, wide_set, lchars, buf_end);
+ if (rv) {
+ return rv;
+ }
+ }
+
+ // Use an unaligned load to mop up the last 32 bytes and get an accurate
+ // picture to buf_end.
+ chars = loadu256(buf);
+ rv = revBlock(wide_clear, wide_set, chars, buf);
+ if (rv) {
+ return rv;
+ }
+ return buf - 1;
+}
+
+#else // AVX512
+
+static really_inline
+const u8 *lastMatch(const u8 *buf, u64a z) {
+ if (unlikely(z != ~0ULL)) {
+ u64a pos = clz64(~z);
+ assert(pos < 64);
+ return buf + (63 - pos);
+ }
+
+ return NULL; // no match
+}
+
+static really_inline
+const u8 *firstMatch(const u8 *buf, u64a z) {
+ if (unlikely(z != ~0ULL)) {
+ u64a pos = ctz64(~z);
+ assert(pos < 64);
+ DEBUG_PRINTF("pos %llu\n", pos);
+ return buf + pos;
+ }
+
+ return NULL; // no match
+}
+
+static really_inline
+u64a block(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset, m512 v) {
+ m512 highconst = set64x8(0x80);
+ m512 shuf_mask_hi = set8x64(0x8040201008040201);
+
+ // and now do the real work
+ m512 shuf1 = pshufb_m512(shuf_mask_lo_highclear, v);
+ m512 t1 = xor512(v, highconst);
+ m512 shuf2 = pshufb_m512(shuf_mask_lo_highset, t1);
+ m512 t2 = andnot512(highconst, rshift64_m512(v, 4));
+ m512 shuf3 = pshufb_m512(shuf_mask_hi, t2);
+ m512 tmp = and512(or512(shuf1, shuf2), shuf3);
+ u64a z = eq512mask(tmp, zeroes512());
+
+ return z;
+}
+
+static really_inline
+const u8 *truffleMini(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ uintptr_t len = buf_end - buf;
+ assert(len <= 64);
+
+ __mmask64 mask = (~0ULL) >> (64 - len);
+
+ m512 chars = loadu_maskz_m512(mask, buf);
+
+ u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
+
+ const u8 *rv = firstMatch(buf, z | ~mask);
+
+ return rv;
+}
+
+static really_inline
+const u8 *fwdBlock(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
+ m512 v, const u8 *buf) {
+ u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return firstMatch(buf, z);
+}
+
+static really_inline
+const u8 *revBlock(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
+ m512 v, const u8 *buf) {
+ u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
+ return lastMatch(buf, z);
+}
+
+const u8 *truffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ DEBUG_PRINTF("len %zu\n", buf_end - buf);
+ const m512 wide_clear = set4x128(shuf_mask_lo_highclear);
+ const m512 wide_set = set4x128(shuf_mask_lo_highset);
+
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+ const u8 *rv;
+
+ if (buf_end - buf <= 64) {
+ rv = truffleMini(wide_clear, wide_set, buf, buf_end);
+ return rv ? rv : buf_end;
+ }
+
+ assert(buf_end - buf >= 64);
+ if ((uintptr_t)buf % 64) {
+ // Preconditioning: most of the time our buffer won't be aligned.
+ rv = truffleMini(wide_clear, wide_set, buf, ROUNDUP_PTR(buf, 64));
+ if (rv) {
+ return rv;
+ }
+ buf = ROUNDUP_PTR(buf, 64);
+ }
+ const u8 *last_block = buf_end - 64;
+ while (buf < last_block) {
+ m512 lchars = load512(buf);
+ rv = fwdBlock(wide_clear, wide_set, lchars, buf);
+ if (rv) {
+ return rv;
+ }
+ buf += 64;
+ }
+
+ // Use an unaligned load to mop up the last 64 bytes and get an accurate
+ // picture to buf_end.
+ assert(buf <= buf_end && buf >= buf_end - 64);
+ m512 chars = loadu512(buf_end - 64);
+ rv = fwdBlock(wide_clear, wide_set, chars, buf_end - 64);
+ if (rv) {
+ return rv;
+ }
+ return buf_end;
+}
+
+static really_inline
+const u8 *truffleRevMini(m512 shuf_mask_lo_highclear, m512 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ uintptr_t len = buf_end - buf;
+ assert(len < 64);
+
+ __mmask64 mask = (~0ULL) >> (64 - len);
+ m512 chars = loadu_maskz_m512(mask, buf);
+ u64a z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
+ DEBUG_PRINTF("mask 0x%016llx z 0x%016llx\n", mask, z);
+ const u8 *rv = lastMatch(buf, z | ~mask);
+
+ if (rv) {
+ return rv;
+ }
+ return buf - 1;
+}
+
+const u8 *rtruffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
+ const u8 *buf, const u8 *buf_end) {
+ const m512 wide_clear = set4x128(shuf_mask_lo_highclear);
+ const m512 wide_set = set4x128(shuf_mask_lo_highset);
+ assert(buf && buf_end);
+ assert(buf < buf_end);
+ const u8 *rv;
+
+ DEBUG_PRINTF("len %zu\n", buf_end - buf);
+
+ if (buf_end - buf < 64) {
+ return truffleRevMini(wide_clear, wide_set, buf, buf_end);
+ }
+
+ assert(buf_end - buf >= 64);
+
+ // Preconditioning: most of the time our buffer won't be aligned.
+ m512 chars = loadu512(buf_end - 64);
+ rv = revBlock(wide_clear, wide_set, chars, buf_end - 64);
+ if (rv) {
+ return rv;
+ }
+ buf_end = (const u8 *)ROUNDDOWN_N((uintptr_t)buf_end, 64);
+
+ const u8 *last_block = buf + 64;
+ while (buf_end > last_block) {
+ buf_end -= 64;
+ m512 lchars = load512(buf_end);
+ rv = revBlock(wide_clear, wide_set, lchars, buf_end);
+ if (rv) {
+ return rv;
+ }
+ }
+
+ // Use an unaligned load to mop up the last 64 bytes and get an accurate
+ // picture to buf_end.
+ chars = loadu512(buf);
+ rv = revBlock(wide_clear, wide_set, chars, buf);
+ if (rv) {
+ return rv;
+ }
+ return buf - 1;
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/nfa/truffle.h b/contrib/libs/hyperscan/src/nfa/truffle.h
index 24ece2a9f58..f67227ad1ef 100644
--- a/contrib/libs/hyperscan/src/nfa/truffle.h
+++ b/contrib/libs/hyperscan/src/nfa/truffle.h
@@ -26,17 +26,17 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/** \file
- * \brief Truffle: fully general character class acceleration.
- *
- * Utilises the SSSE3 pshufb or AVX2 vpshufb shuffle instructions
- */
-
+/** \file
+ * \brief Truffle: fully general character class acceleration.
+ *
+ * Utilises the SSSE3 pshufb or AVX2 vpshufb shuffle instructions
+ */
+
#ifndef TRUFFLE_H
#define TRUFFLE_H
-
+
#include "util/simd_types.h"
-
+
#ifdef __cplusplus
extern "C"
{
diff --git a/contrib/libs/hyperscan/src/nfa/trufflecompile.cpp b/contrib/libs/hyperscan/src/nfa/trufflecompile.cpp
index 29fc503ce55..f19de0ee04a 100644
--- a/contrib/libs/hyperscan/src/nfa/trufflecompile.cpp
+++ b/contrib/libs/hyperscan/src/nfa/trufflecompile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,16 +32,16 @@
* truffle is always able to represent an entire character class, providing a
* backstop to other acceleration engines.
*/
-
+
#include "trufflecompile.h"
-
+
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/dump_mask.h"
+#include "util/dump_mask.h"
#include "util/simd_types.h"
-#include <cstring>
-
+#include <cstring>
+
using namespace std;
namespace ue2 {
@@ -56,15 +56,15 @@ namespace ue2 {
* bits 456 is the bit that is set at that offset.
*/
-void truffleBuildMasks(const CharReach &cr, u8 *shuf_mask_lo_highclear,
- u8 *shuf_mask_lo_highset) {
- memset(shuf_mask_lo_highset, 0, sizeof(m128));
- memset(shuf_mask_lo_highclear, 0, sizeof(m128));
+void truffleBuildMasks(const CharReach &cr, u8 *shuf_mask_lo_highclear,
+ u8 *shuf_mask_lo_highset) {
+ memset(shuf_mask_lo_highset, 0, sizeof(m128));
+ memset(shuf_mask_lo_highclear, 0, sizeof(m128));
for (size_t v = cr.find_first(); v != CharReach::npos;
v = cr.find_next(v)) {
DEBUG_PRINTF("adding 0x%02x to %s\n", (u8)v, (v & 0x80) ? "highset" : "highclear");
- u8 *change_mask = (v & 0x80) ? shuf_mask_lo_highset : shuf_mask_lo_highclear;
+ u8 *change_mask = (v & 0x80) ? shuf_mask_lo_highset : shuf_mask_lo_highclear;
u8 low_nibble = v & 0xf;
u8 bits_456 = (v & 0x70) >> 4;
change_mask[low_nibble] |= 1 << bits_456;
@@ -74,16 +74,16 @@ void truffleBuildMasks(const CharReach &cr, u8 *shuf_mask_lo_highclear,
/*
* Reconstruct the charclass that the truffle masks represent
*/
-CharReach truffle2cr(const u8 *highclear, const u8 *highset) {
+CharReach truffle2cr(const u8 *highclear, const u8 *highset) {
CharReach cr;
for (u8 i = 0; i < 16; i++) {
- u32 bits_456 = highclear[i];
+ u32 bits_456 = highclear[i];
while (bits_456) {
u32 pos = findAndClearLSB_32(&bits_456);
assert(pos < 8);
cr.set(pos << 4 | i);
}
- bits_456 = highset[i];
+ bits_456 = highset[i];
while (bits_456) {
u32 pos = findAndClearLSB_32(&bits_456);
assert(pos < 8);
diff --git a/contrib/libs/hyperscan/src/nfa/trufflecompile.h b/contrib/libs/hyperscan/src/nfa/trufflecompile.h
index fa983508ec8..14b314f3914 100644
--- a/contrib/libs/hyperscan/src/nfa/trufflecompile.h
+++ b/contrib/libs/hyperscan/src/nfa/trufflecompile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,8 +34,8 @@
namespace ue2 {
-void truffleBuildMasks(const CharReach &cr, u8 *mask1, u8 *mask2);
-CharReach truffle2cr(const u8 *lo_in, const u8 *hi_in);
+void truffleBuildMasks(const CharReach &cr, u8 *mask1, u8 *mask2);
+CharReach truffle2cr(const u8 *lo_in, const u8 *hi_in);
}
diff --git a/contrib/libs/hyperscan/src/nfa/vermicelli.h b/contrib/libs/hyperscan/src/nfa/vermicelli.h
index 82a241dcf30..ed797d83f9e 100644
--- a/contrib/libs/hyperscan/src/nfa/vermicelli.h
+++ b/contrib/libs/hyperscan/src/nfa/vermicelli.h
@@ -87,7 +87,7 @@ const u8 *vermicelliExec(char c, char nocase, const u8 *buf,
}
buf += VERM_BOUNDARY - min;
- assert(buf < buf_end);
+ assert(buf < buf_end);
}
// Aligned loops from here on in
@@ -153,7 +153,7 @@ const u8 *nvermicelliExec(char c, char nocase, const u8 *buf,
}
buf += VERM_BOUNDARY - min;
- assert(buf < buf_end);
+ assert(buf < buf_end);
}
// Aligned loops from here on in
@@ -214,49 +214,49 @@ const u8 *vermicelliDoubleExec(char c1, char c2, char nocase, const u8 *buf,
}
buf += VERM_BOUNDARY - min;
- assert(buf < buf_end);
- }
-
- // Aligned loops from here on in
- const u8 *ptr = nocase ? dvermSearchAlignedNocase(chars1, chars2, c1, c2,
- buf, buf_end)
- : dvermSearchAligned(chars1, chars2, c1, c2, buf,
- buf_end);
- if (ptr) {
- return ptr;
- }
-
- // Tidy up the mess at the end
- ptr = nocase ? dvermPreconditionNocase(chars1, chars2,
- buf_end - VERM_BOUNDARY)
- : dvermPrecondition(chars1, chars2, buf_end - VERM_BOUNDARY);
-
- if (ptr) {
- return ptr;
- }
-
- /* check for partial match at end */
- u8 mask = nocase ? CASE_CLEAR : 0xff;
- if ((buf_end[-1] & mask) == (u8)c1) {
- DEBUG_PRINTF("partial!!!\n");
- return buf_end - 1;
- }
-
- return buf_end;
-}
-
-static really_inline
-const u8 *vermicelliDoubleMaskedExec(char c1, char c2, char m1, char m2,
- const u8 *buf, const u8 *buf_end) {
- DEBUG_PRINTF("double verm scan (\\x%02hhx&\\x%02hhx)(\\x%02hhx&\\x%02hhx) "
- "over %zu bytes\n", c1, m1, c2, m2, (size_t)(buf_end - buf));
- assert(buf < buf_end);
-
- VERM_TYPE chars1 = VERM_SET_FN(c1);
- VERM_TYPE chars2 = VERM_SET_FN(c2);
- VERM_TYPE mask1 = VERM_SET_FN(m1);
- VERM_TYPE mask2 = VERM_SET_FN(m2);
-
+ assert(buf < buf_end);
+ }
+
+ // Aligned loops from here on in
+ const u8 *ptr = nocase ? dvermSearchAlignedNocase(chars1, chars2, c1, c2,
+ buf, buf_end)
+ : dvermSearchAligned(chars1, chars2, c1, c2, buf,
+ buf_end);
+ if (ptr) {
+ return ptr;
+ }
+
+ // Tidy up the mess at the end
+ ptr = nocase ? dvermPreconditionNocase(chars1, chars2,
+ buf_end - VERM_BOUNDARY)
+ : dvermPrecondition(chars1, chars2, buf_end - VERM_BOUNDARY);
+
+ if (ptr) {
+ return ptr;
+ }
+
+ /* check for partial match at end */
+ u8 mask = nocase ? CASE_CLEAR : 0xff;
+ if ((buf_end[-1] & mask) == (u8)c1) {
+ DEBUG_PRINTF("partial!!!\n");
+ return buf_end - 1;
+ }
+
+ return buf_end;
+}
+
+static really_inline
+const u8 *vermicelliDoubleMaskedExec(char c1, char c2, char m1, char m2,
+ const u8 *buf, const u8 *buf_end) {
+ DEBUG_PRINTF("double verm scan (\\x%02hhx&\\x%02hhx)(\\x%02hhx&\\x%02hhx) "
+ "over %zu bytes\n", c1, m1, c2, m2, (size_t)(buf_end - buf));
+ assert(buf < buf_end);
+
+ VERM_TYPE chars1 = VERM_SET_FN(c1);
+ VERM_TYPE chars2 = VERM_SET_FN(c2);
+ VERM_TYPE mask1 = VERM_SET_FN(m1);
+ VERM_TYPE mask2 = VERM_SET_FN(m2);
+
#ifdef HAVE_AVX512
if (buf_end - buf <= VERM_BOUNDARY) {
const u8 *ptr = dvermMiniMasked(chars1, chars2, mask1, mask2, buf,
@@ -277,42 +277,42 @@ const u8 *vermicelliDoubleMaskedExec(char c1, char c2, char m1, char m2,
assert((buf_end - buf) >= VERM_BOUNDARY);
uintptr_t min = (uintptr_t)buf % VERM_BOUNDARY;
- if (min) {
- // Input isn't aligned, so we need to run one iteration with an
- // unaligned load, then skip buf forward to the next aligned address.
- // There's some small overlap here, but we don't mind scanning it twice
- // if we can do it quickly, do we?
- const u8 *p = dvermPreconditionMasked(chars1, chars2, mask1, mask2, buf);
- if (p) {
- return p;
+ if (min) {
+ // Input isn't aligned, so we need to run one iteration with an
+ // unaligned load, then skip buf forward to the next aligned address.
+ // There's some small overlap here, but we don't mind scanning it twice
+ // if we can do it quickly, do we?
+ const u8 *p = dvermPreconditionMasked(chars1, chars2, mask1, mask2, buf);
+ if (p) {
+ return p;
}
-
- buf += VERM_BOUNDARY - min;
- assert(buf < buf_end);
+
+ buf += VERM_BOUNDARY - min;
+ assert(buf < buf_end);
}
// Aligned loops from here on in
- const u8 *ptr = dvermSearchAlignedMasked(chars1, chars2, mask1, mask2, c1,
- c2, m1, m2, buf, buf_end);
- if (ptr) {
- return ptr;
+ const u8 *ptr = dvermSearchAlignedMasked(chars1, chars2, mask1, mask2, c1,
+ c2, m1, m2, buf, buf_end);
+ if (ptr) {
+ return ptr;
+ }
+
+ // Tidy up the mess at the end
+ ptr = dvermPreconditionMasked(chars1, chars2, mask1, mask2,
+ buf_end - VERM_BOUNDARY);
+
+ if (ptr) {
+ return ptr;
}
-
- // Tidy up the mess at the end
- ptr = dvermPreconditionMasked(chars1, chars2, mask1, mask2,
- buf_end - VERM_BOUNDARY);
-
- if (ptr) {
- return ptr;
- }
-
- /* check for partial match at end */
- if ((buf_end[-1] & m1) == (u8)c1) {
+
+ /* check for partial match at end */
+ if ((buf_end[-1] & m1) == (u8)c1) {
DEBUG_PRINTF("partial!!!\n");
- return buf_end - 1;
- }
-
- return buf_end;
+ return buf_end - 1;
+ }
+
+ return buf_end;
}
// Reverse vermicelli scan. Provides exact semantics and returns (buf - 1) if
diff --git a/contrib/libs/hyperscan/src/nfa/vermicelli_sse.h b/contrib/libs/hyperscan/src/nfa/vermicelli_sse.h
index 70dc1f4d008..3307486cff2 100644
--- a/contrib/libs/hyperscan/src/nfa/vermicelli_sse.h
+++ b/contrib/libs/hyperscan/src/nfa/vermicelli_sse.h
@@ -140,7 +140,7 @@ const u8 *dvermSearchAligned(m128 chars1, m128 chars2, u8 c1, u8 c2,
for (; buf + 16 < buf_end; buf += 16) {
m128 data = load128(buf);
u32 z = movemask128(and128(eq128(chars1, data),
- rshiftbyte_m128(eq128(chars2, data), 1)));
+ rshiftbyte_m128(eq128(chars2, data), 1)));
if (buf[15] == c1 && buf[16] == c2) {
z |= (1 << 15);
}
@@ -149,8 +149,8 @@ const u8 *dvermSearchAligned(m128 chars1, m128 chars2, u8 c1, u8 c2,
return buf + pos;
}
}
-
- return NULL;
+
+ return NULL;
}
static really_inline
@@ -163,7 +163,7 @@ const u8 *dvermSearchAlignedNocase(m128 chars1, m128 chars2, u8 c1, u8 c2,
m128 data = load128(buf);
m128 v = and128(casemask, data);
u32 z = movemask128(and128(eq128(chars1, v),
- rshiftbyte_m128(eq128(chars2, v), 1)));
+ rshiftbyte_m128(eq128(chars2, v), 1)));
if ((buf[15] & CASE_CLEAR) == c1 && (buf[16] & CASE_CLEAR) == c2) {
z |= (1 << 15);
}
@@ -172,40 +172,40 @@ const u8 *dvermSearchAlignedNocase(m128 chars1, m128 chars2, u8 c1, u8 c2,
return buf + pos;
}
}
-
- return NULL;
-}
-
-static really_inline
-const u8 *dvermSearchAlignedMasked(m128 chars1, m128 chars2,
- m128 mask1, m128 mask2, u8 c1, u8 c2, u8 m1,
- u8 m2, const u8 *buf, const u8 *buf_end) {
- assert((size_t)buf % 16 == 0);
-
- for (; buf + 16 < buf_end; buf += 16) {
- m128 data = load128(buf);
- m128 v1 = eq128(chars1, and128(data, mask1));
- m128 v2 = eq128(chars2, and128(data, mask2));
- u32 z = movemask128(and128(v1, rshiftbyte_m128(v2, 1)));
-
- if ((buf[15] & m1) == c1 && (buf[16] & m2) == c2) {
- z |= (1 << 15);
- }
- if (unlikely(z)) {
- u32 pos = ctz32(z);
- return buf + pos;
- }
- }
-
- return NULL;
-}
-
+
+ return NULL;
+}
+
+static really_inline
+const u8 *dvermSearchAlignedMasked(m128 chars1, m128 chars2,
+ m128 mask1, m128 mask2, u8 c1, u8 c2, u8 m1,
+ u8 m2, const u8 *buf, const u8 *buf_end) {
+ assert((size_t)buf % 16 == 0);
+
+ for (; buf + 16 < buf_end; buf += 16) {
+ m128 data = load128(buf);
+ m128 v1 = eq128(chars1, and128(data, mask1));
+ m128 v2 = eq128(chars2, and128(data, mask2));
+ u32 z = movemask128(and128(v1, rshiftbyte_m128(v2, 1)));
+
+ if ((buf[15] & m1) == c1 && (buf[16] & m2) == c2) {
+ z |= (1 << 15);
+ }
+ if (unlikely(z)) {
+ u32 pos = ctz32(z);
+ return buf + pos;
+ }
+ }
+
+ return NULL;
+}
+
// returns NULL if not found
static really_inline
const u8 *dvermPrecondition(m128 chars1, m128 chars2, const u8 *buf) {
m128 data = loadu128(buf); // unaligned
u32 z = movemask128(and128(eq128(chars1, data),
- rshiftbyte_m128(eq128(chars2, data), 1)));
+ rshiftbyte_m128(eq128(chars2, data), 1)));
/* no fixup of the boundary required - the aligned run will pick it up */
if (unlikely(z)) {
@@ -223,7 +223,24 @@ const u8 *dvermPreconditionNocase(m128 chars1, m128 chars2, const u8 *buf) {
m128 data = loadu128(buf); // unaligned
m128 v = and128(casemask, data);
u32 z = movemask128(and128(eq128(chars1, v),
- rshiftbyte_m128(eq128(chars2, v), 1)));
+ rshiftbyte_m128(eq128(chars2, v), 1)));
+
+ /* no fixup of the boundary required - the aligned run will pick it up */
+ if (unlikely(z)) {
+ u32 pos = ctz32(z);
+ return buf + pos;
+ }
+ return NULL;
+}
+
+// returns NULL if not found
+static really_inline
+const u8 *dvermPreconditionMasked(m128 chars1, m128 chars2,
+ m128 mask1, m128 mask2, const u8 *buf) {
+ m128 data = loadu128(buf); // unaligned
+ m128 v1 = eq128(chars1, and128(data, mask1));
+ m128 v2 = eq128(chars2, and128(data, mask2));
+ u32 z = movemask128(and128(v1, rshiftbyte_m128(v2, 1)));
/* no fixup of the boundary required - the aligned run will pick it up */
if (unlikely(z)) {
@@ -233,24 +250,7 @@ const u8 *dvermPreconditionNocase(m128 chars1, m128 chars2, const u8 *buf) {
return NULL;
}
-// returns NULL if not found
static really_inline
-const u8 *dvermPreconditionMasked(m128 chars1, m128 chars2,
- m128 mask1, m128 mask2, const u8 *buf) {
- m128 data = loadu128(buf); // unaligned
- m128 v1 = eq128(chars1, and128(data, mask1));
- m128 v2 = eq128(chars2, and128(data, mask2));
- u32 z = movemask128(and128(v1, rshiftbyte_m128(v2, 1)));
-
- /* no fixup of the boundary required - the aligned run will pick it up */
- if (unlikely(z)) {
- u32 pos = ctz32(z);
- return buf + pos;
- }
- return NULL;
-}
-
-static really_inline
const u8 *lastMatchOffset(const u8 *buf_end, u32 z) {
assert(z);
return buf_end - 16 + 31 - clz32(z);
@@ -329,7 +329,7 @@ const u8 *rdvermSearchAligned(m128 chars1, m128 chars2, u8 c1, u8 c2,
for (; buf + 16 < buf_end; buf_end -= 16) {
m128 data = load128(buf_end - 16);
u32 z = movemask128(and128(eq128(chars2, data),
- lshiftbyte_m128(eq128(chars1, data), 1)));
+ lshiftbyte_m128(eq128(chars1, data), 1)));
if (buf_end[-17] == c1 && buf_end[-16] == c2) {
z |= 1;
}
@@ -350,7 +350,7 @@ const u8 *rdvermSearchAlignedNocase(m128 chars1, m128 chars2, u8 c1, u8 c2,
m128 data = load128(buf_end - 16);
m128 v = and128(casemask, data);
u32 z = movemask128(and128(eq128(chars2, v),
- lshiftbyte_m128(eq128(chars1, v), 1)));
+ lshiftbyte_m128(eq128(chars1, v), 1)));
if ((buf_end[-17] & CASE_CLEAR) == c1
&& (buf_end[-16] & CASE_CLEAR) == c2) {
z |= 1;
@@ -367,7 +367,7 @@ static really_inline
const u8 *rdvermPrecondition(m128 chars1, m128 chars2, const u8 *buf) {
m128 data = loadu128(buf);
u32 z = movemask128(and128(eq128(chars2, data),
- lshiftbyte_m128(eq128(chars1, data), 1)));
+ lshiftbyte_m128(eq128(chars1, data), 1)));
/* no fixup of the boundary required - the aligned run will pick it up */
if (unlikely(z)) {
@@ -385,7 +385,7 @@ const u8 *rdvermPreconditionNocase(m128 chars1, m128 chars2, const u8 *buf) {
m128 data = loadu128(buf);
m128 v = and128(casemask, data);
u32 z = movemask128(and128(eq128(chars2, v),
- lshiftbyte_m128(eq128(chars1, v), 1)));
+ lshiftbyte_m128(eq128(chars1, v), 1)));
/* no fixup of the boundary required - the aligned run will pick it up */
if (unlikely(z)) {
return lastMatchOffset(buf + 16, z);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng.cpp b/contrib/libs/hyperscan/src/nfagraph/ng.cpp
index 2d987102af0..8dccf9863d4 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng.cpp
@@ -27,10 +27,10 @@
*/
/** \file
- * \brief NG and graph handling.
+ * \brief NG and graph handling.
*/
-#include "ng.h"
-
+#include "ng.h"
+
#include "grey.h"
#include "ng_anchored_acyclic.h"
#include "ng_anchored_dots.h"
@@ -42,7 +42,7 @@
#include "ng_equivalence.h"
#include "ng_extparam.h"
#include "ng_fixed_width.h"
-#include "ng_fuzzy.h"
+#include "ng_fuzzy.h"
#include "ng_haig.h"
#include "ng_literal_component.h"
#include "ng_literal_decorated.h"
@@ -58,14 +58,14 @@
#include "ng_small_literal_set.h"
#include "ng_som.h"
#include "ng_vacuous.h"
-#include "ng_violet.h"
+#include "ng_violet.h"
#include "ng_utf8.h"
#include "ng_util.h"
#include "ng_width.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "nfa/goughcompile.h"
-#include "rose/rose_build.h"
+#include "rose/rose_build.h"
#include "smallwrite/smallwrite_build.h"
#include "util/compile_error.h"
#include "util/container.h"
@@ -78,15 +78,15 @@ using namespace std;
namespace ue2 {
-NG::NG(const CompileContext &in_cc, size_t num_patterns,
- unsigned in_somPrecision)
+NG::NG(const CompileContext &in_cc, size_t num_patterns,
+ unsigned in_somPrecision)
: maxSomRevHistoryAvailable(in_cc.grey.somMaxRevNfaLength),
minWidth(depth::infinity()),
rm(in_cc.grey),
ssm(in_somPrecision),
cc(in_cc),
- smwr(makeSmallWriteBuilder(num_patterns, rm, cc)),
- rose(makeRoseBuilder(rm, ssm, *smwr, cc, boundary)) {
+ smwr(makeSmallWriteBuilder(num_patterns, rm, cc)),
+ rose(makeRoseBuilder(rm, ssm, *smwr, cc, boundary)) {
}
NG::~NG() {
@@ -102,16 +102,16 @@ NG::~NG() {
* \throw CompileError if SOM cannot be supported for the component.
*/
static
-bool addComponentSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
+bool addComponentSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
const som_type som, const u32 comp_id) {
DEBUG_PRINTF("doing som\n");
- dumpComponent(g, "03_presom", expr.index, comp_id, ng.cc.grey);
+ dumpComponent(g, "03_presom", expr.index, comp_id, ng.cc.grey);
assert(hasCorrectlyNumberedVertices(g));
- assert(allMatchStatesHaveReports(g));
+ assert(allMatchStatesHaveReports(g));
// First, we try the "SOM chain" support in ng_som.cpp.
- sombe_rv rv = doSom(ng, g, expr, comp_id, som);
+ sombe_rv rv = doSom(ng, g, expr, comp_id, som);
if (rv == SOMBE_HANDLED_INTERNAL) {
return false;
} else if (rv == SOMBE_HANDLED_ALL) {
@@ -120,7 +120,7 @@ bool addComponentSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
assert(rv == SOMBE_FAIL);
/* Next, Sombe style approaches */
- rv = doSomWithHaig(ng, g, expr, comp_id, som);
+ rv = doSomWithHaig(ng, g, expr, comp_id, som);
if (rv == SOMBE_HANDLED_INTERNAL) {
return false;
} else if (rv == SOMBE_HANDLED_ALL) {
@@ -134,8 +134,8 @@ bool addComponentSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
vector<vector<CharReach> > triggers; /* empty for outfix */
assert(g.kind == NFA_OUTFIX);
- dumpComponent(g, "haig", expr.index, comp_id, ng.cc.grey);
- makeReportsSomPass(ng.rm, g);
+ dumpComponent(g, "haig", expr.index, comp_id, ng.cc.grey);
+ makeReportsSomPass(ng.rm, g);
auto haig = attemptToBuildHaig(g, som, ng.ssm.somPrecision(), triggers,
ng.cc.grey);
if (haig) {
@@ -147,7 +147,7 @@ bool addComponentSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
/* Our various strategies for supporting SOM for this pattern have failed.
* Provide a generic pattern not supported/too large return value as it is
* unclear what the meaning of a specific SOM error would be */
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
assert(0); // unreachable
return false;
@@ -173,7 +173,7 @@ void reduceGraph(NGHolder &g, som_type som, bool utf8,
changed |= removeEdgeRedundancy(g, som, cc);
changed |= reduceGraphEquivalences(g, cc);
changed |= removeRedundancy(g, som);
- changed |= removeCyclicPathRedundancy(g);
+ changed |= removeCyclicPathRedundancy(g);
if (!changed) {
DEBUG_PRINTF("graph unchanged after pass %u, stopping\n", pass);
break;
@@ -202,35 +202,35 @@ void reduceGraph(NGHolder &g, som_type som, bool utf8,
}
static
-bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
- const som_type som, const u32 comp_id) {
+bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
+ const som_type som, const u32 comp_id) {
const CompileContext &cc = ng.cc;
- assert(hasCorrectlyNumberedVertices(g));
+ assert(hasCorrectlyNumberedVertices(g));
DEBUG_PRINTF("expr=%u, comp=%u: %zu vertices, %zu edges\n",
- expr.index, comp_id, num_vertices(g), num_edges(g));
+ expr.index, comp_id, num_vertices(g), num_edges(g));
- dumpComponent(g, "01_begin", expr.index, comp_id, ng.cc.grey);
+ dumpComponent(g, "01_begin", expr.index, comp_id, ng.cc.grey);
+
+ assert(allMatchStatesHaveReports(g));
- assert(allMatchStatesHaveReports(g));
+ reduceExtendedParams(g, ng.rm, som);
+ reduceGraph(g, som, expr.utf8, cc);
- reduceExtendedParams(g, ng.rm, som);
- reduceGraph(g, som, expr.utf8, cc);
+ dumpComponent(g, "02_reduced", expr.index, comp_id, ng.cc.grey);
- dumpComponent(g, "02_reduced", expr.index, comp_id, ng.cc.grey);
-
// There may be redundant regions that we can remove
if (cc.grey.performGraphSimplification) {
removeRegionRedundancy(g, som);
}
- // We might be done at this point: if we've run out of vertices, we can
- // stop processing.
- if (num_vertices(g) == N_SPECIALS) {
- DEBUG_PRINTF("all vertices claimed\n");
- return true;
- }
-
+ // We might be done at this point: if we've run out of vertices, we can
+ // stop processing.
+ if (num_vertices(g) == N_SPECIALS) {
+ DEBUG_PRINTF("all vertices claimed\n");
+ return true;
+ }
+
// "Short Exhaustible Passthrough" patterns always become outfixes.
if (!som && isSEP(g, ng.rm, cc.grey)) {
DEBUG_PRINTF("graph is SEP\n");
@@ -241,13 +241,13 @@ bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
// Start Of Match handling.
if (som) {
- if (addComponentSom(ng, g, expr, som, comp_id)) {
+ if (addComponentSom(ng, g, expr, som, comp_id)) {
return true;
}
}
- assert(allMatchStatesHaveReports(g));
-
+ assert(allMatchStatesHaveReports(g));
+
if (splitOffAnchoredAcyclic(*ng.rose, g, cc)) {
return true;
}
@@ -261,11 +261,11 @@ bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
return true;
}
- if (doViolet(*ng.rose, g, expr.prefilter, false, ng.rm, cc)) {
+ if (doViolet(*ng.rose, g, expr.prefilter, false, ng.rm, cc)) {
return true;
}
- if (splitOffPuffs(*ng.rose, ng.rm, g, expr.prefilter, cc)) {
+ if (splitOffPuffs(*ng.rose, ng.rm, g, expr.prefilter, cc)) {
return true;
}
@@ -278,7 +278,7 @@ bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
return true;
}
- if (doViolet(*ng.rose, g, expr.prefilter, true, ng.rm, cc)) {
+ if (doViolet(*ng.rose, g, expr.prefilter, true, ng.rm, cc)) {
return true;
}
@@ -293,7 +293,7 @@ bool addComponent(NG &ng, NGHolder &g, const ExpressionInfo &expr,
// Returns true if all components have been added.
static
-bool processComponents(NG &ng, ExpressionInfo &expr,
+bool processComponents(NG &ng, ExpressionInfo &expr,
deque<unique_ptr<NGHolder>> &g_comp,
const som_type som) {
const u32 num_components = g_comp.size();
@@ -303,7 +303,7 @@ bool processComponents(NG &ng, ExpressionInfo &expr,
if (!g_comp[i]) {
continue;
}
- if (addComponent(ng, *g_comp[i], expr, som, i)) {
+ if (addComponent(ng, *g_comp[i], expr, som, i)) {
g_comp[i].reset();
continue;
}
@@ -323,70 +323,70 @@ bool processComponents(NG &ng, ExpressionInfo &expr,
return false;
}
-bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
- assert(g_ptr);
- NGHolder &g = *g_ptr;
-
+bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
+ assert(g_ptr);
+ NGHolder &g = *g_ptr;
+
// remove reports that aren't on vertices connected to accept.
- clearReports(g);
+ clearReports(g);
- som_type som = expr.som;
- if (som && isVacuous(g)) {
- throw CompileError(expr.index, "Start of match is not "
+ som_type som = expr.som;
+ if (som && isVacuous(g)) {
+ throw CompileError(expr.index, "Start of match is not "
"currently supported for patterns which match an "
"empty buffer.");
}
- dumpDotWrapper(g, expr, "01_initial", cc.grey);
- assert(allMatchStatesHaveReports(g));
+ dumpDotWrapper(g, expr, "01_initial", cc.grey);
+ assert(allMatchStatesHaveReports(g));
/* ensure utf8 starts at cp boundary */
- ensureCodePointStart(rm, g, expr);
-
- if (can_never_match(g)) {
- throw CompileError(expr.index, "Pattern can never match.");
- }
-
- bool hamming = expr.hamm_distance > 0;
- u32 e_dist = hamming ? expr.hamm_distance : expr.edit_distance;
-
- DEBUG_PRINTF("edit distance = %u hamming = %s\n", e_dist, hamming ? "true" : "false");
-
- // validate graph's suitability for fuzzing before resolving asserts
- validate_fuzzy_compile(g, e_dist, hamming, expr.utf8, cc.grey);
-
- resolveAsserts(rm, g, expr);
- dumpDotWrapper(g, expr, "02_post_assert_resolve", cc.grey);
- assert(allMatchStatesHaveReports(g));
-
- make_fuzzy(g, e_dist, hamming, cc.grey);
- dumpDotWrapper(g, expr, "02a_post_fuzz", cc.grey);
-
- pruneUseless(g);
- pruneEmptyVertices(g);
-
- if (can_never_match(g)) {
- throw CompileError(expr.index, "Pattern can never match.");
- }
-
- optimiseVirtualStarts(g); /* good for som */
-
- propagateExtendedParams(g, expr, rm);
- reduceExtendedParams(g, rm, som);
-
- // We may have removed all the edges to accept, in which case this
- // expression cannot match.
- if (can_never_match(g)) {
- throw CompileError(expr.index, "Extended parameter constraints can not "
- "be satisfied for any match from this "
- "expression.");
- }
-
- if (any_of_in(all_reports(g), [&](ReportID id) {
- return rm.getReport(id).minLength;
- })) {
- // We have at least one report with a minimum length constraint, which
- // we currently use SOM to satisfy.
+ ensureCodePointStart(rm, g, expr);
+
+ if (can_never_match(g)) {
+ throw CompileError(expr.index, "Pattern can never match.");
+ }
+
+ bool hamming = expr.hamm_distance > 0;
+ u32 e_dist = hamming ? expr.hamm_distance : expr.edit_distance;
+
+ DEBUG_PRINTF("edit distance = %u hamming = %s\n", e_dist, hamming ? "true" : "false");
+
+ // validate graph's suitability for fuzzing before resolving asserts
+ validate_fuzzy_compile(g, e_dist, hamming, expr.utf8, cc.grey);
+
+ resolveAsserts(rm, g, expr);
+ dumpDotWrapper(g, expr, "02_post_assert_resolve", cc.grey);
+ assert(allMatchStatesHaveReports(g));
+
+ make_fuzzy(g, e_dist, hamming, cc.grey);
+ dumpDotWrapper(g, expr, "02a_post_fuzz", cc.grey);
+
+ pruneUseless(g);
+ pruneEmptyVertices(g);
+
+ if (can_never_match(g)) {
+ throw CompileError(expr.index, "Pattern can never match.");
+ }
+
+ optimiseVirtualStarts(g); /* good for som */
+
+ propagateExtendedParams(g, expr, rm);
+ reduceExtendedParams(g, rm, som);
+
+ // We may have removed all the edges to accept, in which case this
+ // expression cannot match.
+ if (can_never_match(g)) {
+ throw CompileError(expr.index, "Extended parameter constraints can not "
+ "be satisfied for any match from this "
+ "expression.");
+ }
+
+ if (any_of_in(all_reports(g), [&](ReportID id) {
+ return rm.getReport(id).minLength;
+ })) {
+ // We have at least one report with a minimum length constraint, which
+ // we currently use SOM to satisfy.
som = SOM_LEFT;
ssm.somPrecision(8);
}
@@ -398,104 +398,104 @@ bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
// first, we can perform graph work that can be done on an individual
// expression basis.
- if (expr.utf8) {
- relaxForbiddenUtf8(g, expr);
+ if (expr.utf8) {
+ relaxForbiddenUtf8(g, expr);
}
- if (all_of_in(all_reports(g), [&](ReportID id) {
- const auto &report = rm.getReport(id);
- return report.ekey != INVALID_EKEY && !report.minLength &&
- !report.minOffset;
- })) {
+ if (all_of_in(all_reports(g), [&](ReportID id) {
+ const auto &report = rm.getReport(id);
+ return report.ekey != INVALID_EKEY && !report.minLength &&
+ !report.minOffset;
+ })) {
// In highlander mode: if we don't have constraints on our reports that
// may prevent us accepting our first match (i.e. extended params) we
// can prune the other out-edges of all vertices connected to accept.
- // TODO: shift the report checking down into pruneHighlanderAccepts()
- // to allow us to handle the parts we can in mixed cases.
- pruneHighlanderAccepts(g, rm);
+ // TODO: shift the report checking down into pruneHighlanderAccepts()
+ // to allow us to handle the parts we can in mixed cases.
+ pruneHighlanderAccepts(g, rm);
}
- dumpDotWrapper(g, expr, "02b_fairly_early", cc.grey);
+ dumpDotWrapper(g, expr, "02b_fairly_early", cc.grey);
// If we're a vacuous pattern, we can handle this early.
- if (splitOffVacuous(boundary, rm, g, expr)) {
+ if (splitOffVacuous(boundary, rm, g, expr)) {
DEBUG_PRINTF("split off vacuous\n");
}
// We might be done at this point: if we've run out of vertices, we can
// stop processing.
- if (num_vertices(g) == N_SPECIALS) {
+ if (num_vertices(g) == N_SPECIALS) {
DEBUG_PRINTF("all vertices claimed by vacuous handling\n");
return true;
}
// Now that vacuous edges have been removed, update the min width exclusive
// of boundary reports.
- minWidth = min(minWidth, findMinWidth(g));
+ minWidth = min(minWidth, findMinWidth(g));
// Add the pattern to the small write builder.
- smwr->add(g, expr);
+ smwr->add(g, expr);
if (!som) {
- removeSiblingsOfStartDotStar(g);
+ removeSiblingsOfStartDotStar(g);
}
- dumpDotWrapper(g, expr, "03_early", cc.grey);
+ dumpDotWrapper(g, expr, "03_early", cc.grey);
+
+ // Perform a reduction pass to merge sibling character classes together.
+ if (cc.grey.performGraphSimplification) {
+ removeRedundancy(g, som);
+ prunePathsRedundantWithSuccessorOfCyclics(g, som);
+ }
+
+ dumpDotWrapper(g, expr, "04_reduced", cc.grey);
- // Perform a reduction pass to merge sibling character classes together.
- if (cc.grey.performGraphSimplification) {
- removeRedundancy(g, som);
- prunePathsRedundantWithSuccessorOfCyclics(g, som);
- }
-
- dumpDotWrapper(g, expr, "04_reduced", cc.grey);
-
// If we've got some literals that span the graph from start to accept, we
// can split them off into Rose from here.
if (!som) {
- if (splitOffLiterals(*this, g)) {
+ if (splitOffLiterals(*this, g)) {
DEBUG_PRINTF("some vertices claimed by literals\n");
}
}
// We might be done at this point: if we've run out of vertices, we can
// stop processing.
- if (num_vertices(g) == N_SPECIALS) {
+ if (num_vertices(g) == N_SPECIALS) {
DEBUG_PRINTF("all vertices claimed before calc components\n");
return true;
}
- // Split the graph into a set of connected components and process those.
- // Note: this invalidates g_ptr.
+ // Split the graph into a set of connected components and process those.
+ // Note: this invalidates g_ptr.
- auto g_comp = calcComponents(std::move(g_ptr), cc.grey);
+ auto g_comp = calcComponents(std::move(g_ptr), cc.grey);
assert(!g_comp.empty());
if (!som) {
- for (auto &gc : g_comp) {
- assert(gc);
- reformLeadingDots(*gc);
+ for (auto &gc : g_comp) {
+ assert(gc);
+ reformLeadingDots(*gc);
}
- recalcComponents(g_comp, cc.grey);
+ recalcComponents(g_comp, cc.grey);
}
- if (processComponents(*this, expr, g_comp, som)) {
+ if (processComponents(*this, expr, g_comp, som)) {
return true;
}
// If we're in prefiltering mode, we can run the prefilter reductions and
// have another shot at accepting the graph.
- if (cc.grey.prefilterReductions && expr.prefilter) {
- for (auto &gc : g_comp) {
- if (!gc) {
+ if (cc.grey.prefilterReductions && expr.prefilter) {
+ for (auto &gc : g_comp) {
+ if (!gc) {
continue;
}
- prefilterReductions(*gc, cc);
+ prefilterReductions(*gc, cc);
}
- if (processComponents(*this, expr, g_comp, som)) {
+ if (processComponents(*this, expr, g_comp, som)) {
return true;
}
}
@@ -505,7 +505,7 @@ bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
if (g_comp[i]) {
DEBUG_PRINTF("could not compile component %u with %zu vertices\n",
i, num_vertices(*g_comp[i]));
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
}
@@ -514,60 +514,60 @@ bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
}
/** \brief Used from SOM mode to add an arbitrary NGHolder as an engine. */
-bool NG::addHolder(NGHolder &g) {
- DEBUG_PRINTF("adding holder of %zu states\n", num_vertices(g));
- assert(allMatchStatesHaveReports(g));
- assert(hasCorrectlyNumberedVertices(g));
+bool NG::addHolder(NGHolder &g) {
+ DEBUG_PRINTF("adding holder of %zu states\n", num_vertices(g));
+ assert(allMatchStatesHaveReports(g));
+ assert(hasCorrectlyNumberedVertices(g));
/* We don't update the global minWidth here as we care about the min width
* of the whole pattern - not a just a prefix of it. */
bool prefilter = false;
- //dumpDotComp(comp, g, *this, 20, "prefix_init");
+ //dumpDotComp(comp, g, *this, 20, "prefix_init");
som_type som = SOM_NONE; /* the prefixes created by the SOM code do not
themselves track som */
bool utf8 = false; // handling done earlier
- reduceGraph(g, som, utf8, cc);
+ reduceGraph(g, som, utf8, cc);
// There may be redundant regions that we can remove
if (cc.grey.performGraphSimplification) {
- removeRegionRedundancy(g, som);
+ removeRegionRedundancy(g, som);
}
// "Short Exhaustible Passthrough" patterns always become outfixes.
- if (isSEP(g, rm, cc.grey)) {
+ if (isSEP(g, rm, cc.grey)) {
DEBUG_PRINTF("graph is SEP\n");
- if (rose->addOutfix(g)) {
+ if (rose->addOutfix(g)) {
return true;
}
}
- if (splitOffAnchoredAcyclic(*rose, g, cc)) {
+ if (splitOffAnchoredAcyclic(*rose, g, cc)) {
return true;
}
- if (handleSmallLiteralSets(*rose, g, cc)
- || handleFixedWidth(*rose, g, cc.grey)) {
+ if (handleSmallLiteralSets(*rose, g, cc)
+ || handleFixedWidth(*rose, g, cc.grey)) {
return true;
}
- if (handleDecoratedLiterals(*rose, g, cc)) {
+ if (handleDecoratedLiterals(*rose, g, cc)) {
return true;
}
- if (doViolet(*rose, g, prefilter, false, rm, cc)) {
+ if (doViolet(*rose, g, prefilter, false, rm, cc)) {
return true;
}
- if (splitOffPuffs(*rose, rm, g, prefilter, cc)) {
+ if (splitOffPuffs(*rose, rm, g, prefilter, cc)) {
return true;
}
- if (doViolet(*rose, g, prefilter, true, rm, cc)) {
+ if (doViolet(*rose, g, prefilter, true, rm, cc)) {
return true;
}
DEBUG_PRINTF("trying for outfix\n");
- if (rose->addOutfix(g)) {
+ if (rose->addOutfix(g)) {
DEBUG_PRINTF("ok\n");
return true;
}
@@ -617,8 +617,8 @@ bool NG::addLiteral(const ue2_literal &literal, u32 expr_index,
minWidth = min(minWidth, depth(literal.length()));
- /* inform small write handler about this literal */
- smwr->add(literal, id);
+ /* inform small write handler about this literal */
+ smwr->add(literal, id);
return true;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng.h b/contrib/libs/hyperscan/src/nfagraph/ng.h
index d7f46bddcff..a5a9077d4f5 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng.h
@@ -27,7 +27,7 @@
*/
/** \file
- * \brief NG declaration.
+ * \brief NG declaration.
*/
#ifndef NG_H
@@ -42,7 +42,7 @@
#include "util/compile_context.h"
#include "util/depth.h"
#include "util/graph.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include "util/report_manager.h"
#include <deque>
@@ -56,26 +56,26 @@ namespace ue2 {
struct CompileContext;
struct ue2_literal;
-class ExpressionInfo;
+class ExpressionInfo;
class RoseBuild;
class SmallWriteBuild;
-class NG : noncopyable {
+class NG : noncopyable {
public:
- NG(const CompileContext &in_cc, size_t num_patterns,
- unsigned in_somPrecision);
+ NG(const CompileContext &in_cc, size_t num_patterns,
+ unsigned in_somPrecision);
~NG();
/** \brief Consumes a pattern, returns false or throws a CompileError
* exception if the graph cannot be consumed. */
- bool addGraph(ExpressionInfo &expr, std::unique_ptr<NGHolder> g_ptr);
+ bool addGraph(ExpressionInfo &expr, std::unique_ptr<NGHolder> g_ptr);
/** \brief Consumes a graph, cut-down version of addGraph for use by SOM
* processing. */
bool addHolder(NGHolder &h);
- /** \brief Adds a literal to Rose, used by literal shortcut passes (instead
- * of using \ref addGraph) */
+ /** \brief Adds a literal to Rose, used by literal shortcut passes (instead
+ * of using \ref addGraph) */
bool addLiteral(const ue2_literal &lit, u32 expr_index, u32 external_report,
bool highlander, som_type som, bool quiet);
@@ -94,7 +94,7 @@ public:
BoundaryReports boundary;
const CompileContext cc;
- const std::unique_ptr<SmallWriteBuild> smwr; //!< SmallWrite builder.
+ const std::unique_ptr<SmallWriteBuild> smwr; //!< SmallWrite builder.
const std::unique_ptr<RoseBuild> rose; //!< Rose builder.
};
@@ -102,8 +102,8 @@ public:
*
* Shared with the small write compiler.
*/
-void reduceGraph(NGHolder &g, som_type som, bool utf8,
- const CompileContext &cc);
+void reduceGraph(NGHolder &g, som_type som, bool utf8,
+ const CompileContext &cc);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_anchored_dots.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_anchored_dots.cpp
index 11d6861d690..9a13376d193 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_anchored_dots.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_anchored_dots.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -119,7 +119,7 @@ NFAVertex findReformable(const NGHolder &g, const set<NFAVertex> &starts,
}
if (dotq.empty()) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
const DotInfo &dot = dotq.top();
@@ -165,10 +165,10 @@ void reformAnchoredRepeatsComponent(NGHolder &g,
return;
}
- NFAVertex dotV = NGHolder::null_vertex();
+ NFAVertex dotV = NGHolder::null_vertex();
set<NFAVertex> otherV;
dotV = findReformable(g, compAnchoredStarts, otherV);
- if (dotV == NGHolder::null_vertex()) {
+ if (dotV == NGHolder::null_vertex()) {
DEBUG_PRINTF("no candidate reformable dot found.\n");
return;
}
@@ -202,13 +202,13 @@ void reformAnchoredRepeatsComponent(NGHolder &g,
}
if (!isStartNode(dotV, g.start, g, true)) {
- DEBUG_PRINTF("fleeing: vertex %zu has other preds\n", g[dotV].index);
+ DEBUG_PRINTF("fleeing: vertex %zu has other preds\n", g[dotV].index);
return;
}
/* get bounds */
depth min;
- depth max(1);
+ depth max(1);
if (selfLoop) {
// A self-loop indicates that this is a '.+' or '.*'
@@ -229,9 +229,9 @@ void reformAnchoredRepeatsComponent(NGHolder &g,
}
}
- min = depth(0);
+ min = depth(0);
} else {
- min = depth(1);
+ min = depth(1);
}
*startBegin = min;
@@ -249,7 +249,7 @@ void reformAnchoredRepeatsComponent(NGHolder &g,
remove_edge(g.start, v, g);
}
- DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index);
+ DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index);
clear_vertex(dotV, g);
dead.insert(dotV);
compAnchoredStarts.erase(dotV);
@@ -268,10 +268,10 @@ void reformUnanchoredRepeatsComponent(NGHolder &g,
}
while (true) {
- NFAVertex dotV = NGHolder::null_vertex();
+ NFAVertex dotV = NGHolder::null_vertex();
set<NFAVertex> otherV;
dotV = findReformable(g, compUnanchoredStarts, otherV);
- if (dotV == NGHolder::null_vertex()) {
+ if (dotV == NGHolder::null_vertex()) {
DEBUG_PRINTF("no candidate reformable dot found.\n");
return;
}
@@ -313,21 +313,21 @@ void reformUnanchoredRepeatsComponent(NGHolder &g,
}
// A self-loop indicates that this is a '.+' or '.*'
- DEBUG_PRINTF("self-loop detected on %zu\n", g[dotV].index);
+ DEBUG_PRINTF("self-loop detected on %zu\n", g[dotV].index);
*startEnd = depth::infinity();
remove_edge(dotV, dotV, g);
return;
}
if (!isStartNode(dotV, g.startDs, g, true)) {
- DEBUG_PRINTF("fleeing: vertex %zu has other preds\n",
- g[dotV].index);
+ DEBUG_PRINTF("fleeing: vertex %zu has other preds\n",
+ g[dotV].index);
return;
}
/* get bounds */
- depth min(1);
- depth max(1);
+ depth min(1);
+ depth max(1);
if (selfLoop) {
// A self-loop indicates that this is a '.+' or '.*'
@@ -349,7 +349,7 @@ void reformUnanchoredRepeatsComponent(NGHolder &g,
DEBUG_PRINTF("min greater than one, skipping\n");
return;
}
- min = depth(0);
+ min = depth(0);
}
*startBegin += min;
@@ -363,14 +363,14 @@ void reformUnanchoredRepeatsComponent(NGHolder &g,
compUnanchoredStarts.clear();
for (auto t : adjacent_vertices_range(dotV, g)) {
if (t != dotV) {
- DEBUG_PRINTF("connecting sds -> %zu\n", g[t].index);
+ DEBUG_PRINTF("connecting sds -> %zu\n", g[t].index);
add_edge(g.startDs, t, g);
add_edge(g.start, t, g);
compUnanchoredStarts.insert(t);
}
}
- DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index);
+ DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index);
dead.insert(dotV);
clear_vertex(dotV, g);
compUnanchoredStarts.erase(dotV);
@@ -417,7 +417,7 @@ bool gatherParticipants(const NGHolder &g,
if (isOptionalDot(t, v, g)) {
// another dot; bail if we've seen it once already
if (dots.find(t) != dots.end()) {
- DEBUG_PRINTF("cycle detected at vertex %zu\n", g[t].index);
+ DEBUG_PRINTF("cycle detected at vertex %zu\n", g[t].index);
return false;
}
dots.insert(t);
@@ -433,7 +433,7 @@ bool gatherParticipants(const NGHolder &g,
for (auto w : adjacent_vertices_range(v, g)) {
succ.insert(w);
if (!edge(start, w, g).second) {
- DEBUG_PRINTF("failing, vertex %zu does not have edge from start\n",
+ DEBUG_PRINTF("failing, vertex %zu does not have edge from start\n",
g[w].index);
return false;
}
@@ -465,7 +465,7 @@ void collapseVariableDotRepeat(NGHolder &g, NFAVertex start,
// The first of our optional dots must be connected to start. The jump edge
// past it will be verified in gatherParticipants(). If start is
// graph.start, it should not be connected to startDs.
- NFAVertex initialDot = NGHolder::null_vertex();
+ NFAVertex initialDot = NGHolder::null_vertex();
for (auto v : adjacent_vertices_range(start, g)) {
if (is_special(v, g)) {
continue;
@@ -475,7 +475,7 @@ void collapseVariableDotRepeat(NGHolder &g, NFAVertex start,
return;
}
initialDot = v;
- DEBUG_PRINTF("initial dot vertex is %zu\n", g[v].index);
+ DEBUG_PRINTF("initial dot vertex is %zu\n", g[v].index);
}
}
@@ -502,14 +502,14 @@ void collapseVariableDotRepeat(NGHolder &g, NFAVertex start,
startEnd->str().c_str());
if (start == g.start && startEnd->is_infinite()) {
- *startEnd = depth(dots.size());
+ *startEnd = depth(dots.size());
} else if (startEnd->is_finite()) {
*startEnd += dots.size();
}
assert(startEnd->is_reachable());
// Connect our successor vertices to both start and startDs.
- for (auto v : succ) {
+ for (auto v : succ) {
add_edge_if_not_present(g.start, v, g);
add_edge_if_not_present(g.startDs, v, g);
}
@@ -634,8 +634,8 @@ void restoreLeadingDots(NGHolder &g, const depth &startBegin,
}
addDotsBetween(g, root, rhs, startBegin, startEnd);
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
}
// Entry point.
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_asserts.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_asserts.cpp
index e4603514a08..8812afadb7e 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_asserts.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_asserts.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -47,7 +47,7 @@
#include "ng_prune.h"
#include "ng_redundancy.h"
#include "ng_util.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "parser/position.h" // for POS flags
#include "util/bitutils.h" // for findAndClearLSB_32
#include "util/boundary_reports.h"
@@ -102,7 +102,7 @@ vector<NFAEdge> getAsserts(const NGHolder &g) {
static
void addToSplit(const NGHolder &g, NFAVertex v, map<u32, NFAVertex> *to_split) {
- DEBUG_PRINTF("%zu needs splitting\n", g[v].index);
+ DEBUG_PRINTF("%zu needs splitting\n", g[v].index);
to_split->emplace(g[v].index, v);
}
@@ -185,49 +185,49 @@ void findSplitters(const NGHolder &g, const vector<NFAEdge> &asserts,
}
static
-void setReportId(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
- NFAVertex v, s32 adj) {
+void setReportId(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
+ NFAVertex v, s32 adj) {
// Don't try and set the report ID of a special vertex.
assert(!is_special(v, g));
// If there's a report set already, we're replacing it.
g[v].reports.clear();
- Report ir = rm.getBasicInternalReport(expr, adj);
+ Report ir = rm.getBasicInternalReport(expr, adj);
g[v].reports.insert(rm.getInternalId(ir));
- DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj);
+ DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj);
}
static
-NFAVertex makeClone(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
- NFAVertex v, const CharReach &cr_mask) {
+NFAVertex makeClone(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
+ NFAVertex v, const CharReach &cr_mask) {
NFAVertex clone = clone_vertex(g, v);
g[clone].char_reach &= cr_mask;
clone_out_edges(g, v, clone);
clone_in_edges(g, v, clone);
if (v == g.startDs) {
- if (expr.utf8) {
+ if (expr.utf8) {
g[clone].char_reach &= ~UTF_START_CR;
}
DEBUG_PRINTF("marked as virt\n");
g[clone].assert_flags = POS_FLAG_VIRTUAL_START;
- setReportId(rm, g, expr, clone, 0);
+ setReportId(rm, g, expr, clone, 0);
}
return clone;
}
static
-void splitVertex(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
- NFAVertex v, bool ucp) {
+void splitVertex(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
+ NFAVertex v, bool ucp) {
assert(v != g.start);
assert(v != g.accept);
assert(v != g.acceptEod);
- DEBUG_PRINTF("partitioning vertex %zu ucp:%d\n", g[v].index, (int)ucp);
+ DEBUG_PRINTF("partitioning vertex %zu ucp:%d\n", g[v].index, (int)ucp);
CharReach cr_word = ucp ? CHARREACH_WORD_UCP_PRE : CHARREACH_WORD;
CharReach cr_nonword = ucp ? CHARREACH_NONWORD_UCP_PRE : CHARREACH_NONWORD;
@@ -235,14 +235,14 @@ void splitVertex(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
auto has_no_assert = [&g](const NFAEdge &e) { return !g[e].assert_flags; };
// Split v into word/nonword vertices with only asserting out-edges.
- NFAVertex w_out = makeClone(rm, g, expr, v, cr_word);
- NFAVertex nw_out = makeClone(rm, g, expr, v, cr_nonword);
+ NFAVertex w_out = makeClone(rm, g, expr, v, cr_word);
+ NFAVertex nw_out = makeClone(rm, g, expr, v, cr_nonword);
remove_out_edge_if(w_out, has_no_assert, g);
remove_out_edge_if(nw_out, has_no_assert, g);
// Split v into word/nonword vertices with only asserting in-edges.
- NFAVertex w_in = makeClone(rm, g, expr, v, cr_word);
- NFAVertex nw_in = makeClone(rm, g, expr, v, cr_nonword);
+ NFAVertex w_in = makeClone(rm, g, expr, v, cr_word);
+ NFAVertex nw_in = makeClone(rm, g, expr, v, cr_nonword);
remove_in_edge_if(w_in, has_no_assert, g);
remove_in_edge_if(nw_in, has_no_assert, g);
@@ -253,8 +253,8 @@ void splitVertex(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
}
static
-void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
- set<NFAEdge> *dead) {
+void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
+ set<NFAEdge> *dead) {
for (const auto &e : edges_range(g)) {
u32 flags = g[e].assert_flags;
if (!flags) {
@@ -271,8 +271,8 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
bool impassable = true;
bool ucp = flags & UCP_ASSERT_FLAGS;
- DEBUG_PRINTF("resolving edge %zu->%zu (flags=0x%x, ucp=%d)\n",
- g[u].index, g[v].index, flags, (int)ucp);
+ DEBUG_PRINTF("resolving edge %zu->%zu (flags=0x%x, ucp=%d)\n",
+ g[u].index, g[v].index, flags, (int)ucp);
while (flags && impassable) {
u32 flag = 1U << findAndClearLSB_32(&flags);
switch (flag) {
@@ -367,7 +367,7 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
} else if (v_w) {
/* need to add a word byte */
NFAVertex vv = add_vertex(g);
- setReportId(rm, g, expr, vv, -1);
+ setReportId(rm, g, expr, vv, -1);
g[vv].char_reach = CHARREACH_WORD;
add_edge(vv, g.accept, g);
g[e].assert_flags = 0;
@@ -376,19 +376,19 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
} else {
/* need to add a non word byte or see eod */
NFAVertex vv = add_vertex(g);
- setReportId(rm, g, expr, vv, -1);
+ setReportId(rm, g, expr, vv, -1);
g[vv].char_reach = CHARREACH_NONWORD;
add_edge(vv, g.accept, g);
g[e].assert_flags = 0;
add_edge(u, vv, g[e], g);
- /* there may already be a different edge from start to eod if so
- * we need to make it unconditional and alive
- */
- if (NFAEdge start_eod = edge(u, g.acceptEod, g)) {
+ /* there may already be a different edge from start to eod if so
+ * we need to make it unconditional and alive
+ */
+ if (NFAEdge start_eod = edge(u, g.acceptEod, g)) {
g[start_eod].assert_flags = 0;
dead->erase(start_eod);
- } else {
- add_edge(u, g.acceptEod, g[e], g);
+ } else {
+ add_edge(u, g.acceptEod, g[e], g);
}
dead->insert(e);
}
@@ -420,7 +420,7 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
} else if (v_w) {
/* need to add a word byte */
NFAVertex vv = add_vertex(g);
- setReportId(rm, g, expr, vv, -1);
+ setReportId(rm, g, expr, vv, -1);
g[vv].char_reach = CHARREACH_WORD_UCP_PRE;
add_edge(vv, g.accept, g);
g[e].assert_flags = 0;
@@ -429,19 +429,19 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
} else {
/* need to add a non word byte or see eod */
NFAVertex vv = add_vertex(g);
- setReportId(rm, g, expr, vv, -1);
+ setReportId(rm, g, expr, vv, -1);
g[vv].char_reach = CHARREACH_NONWORD_UCP_PRE;
add_edge(vv, g.accept, g);
g[e].assert_flags = 0;
add_edge(u, vv, g[e], g);
- /* there may already be a different edge from start to eod if so
- * we need to make it unconditional and alive
- */
- if (NFAEdge start_eod = edge(u, g.acceptEod, g)) {
+ /* there may already be a different edge from start to eod if so
+ * we need to make it unconditional and alive
+ */
+ if (NFAEdge start_eod = edge(u, g.acceptEod, g)) {
g[start_eod].assert_flags = 0;
dead->erase(start_eod);
- } else {
- add_edge(u, g.acceptEod, g[e], g);
+ } else {
+ add_edge(u, g.acceptEod, g[e], g);
}
dead->insert(e);
}
@@ -454,8 +454,8 @@ void resolveEdges(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr,
}
}
-void resolveAsserts(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
+void resolveAsserts(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
vector<NFAEdge> asserts = getAsserts(g);
if (asserts.empty()) {
return;
@@ -465,41 +465,41 @@ void resolveAsserts(ReportManager &rm, NGHolder &g,
map<u32, NFAVertex> to_split_ucp; /* by index, for determinism */
findSplitters(g, asserts, &to_split, &to_split_ucp);
if (to_split.size() + to_split_ucp.size() > MAX_CLONED_VERTICES) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
for (const auto &m : to_split) {
assert(!contains(to_split_ucp, m.first));
- splitVertex(rm, g, expr, m.second, false);
+ splitVertex(rm, g, expr, m.second, false);
}
for (const auto &m : to_split_ucp) {
- splitVertex(rm, g, expr, m.second, true);
+ splitVertex(rm, g, expr, m.second, true);
}
set<NFAEdge> dead;
- resolveEdges(rm, g, expr, &dead);
+ resolveEdges(rm, g, expr, &dead);
remove_edges(dead, g);
- renumber_vertices(g);
+ renumber_vertices(g);
pruneUseless(g);
pruneEmptyVertices(g);
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
clearReports(g);
}
-void ensureCodePointStart(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
+void ensureCodePointStart(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
/* In utf8 mode there is an implicit assertion that we start at codepoint
* boundaries. Assert resolution handles the badness coming from asserts.
* The only other source of trouble is startDs->accept connections.
*/
- NFAEdge orig = edge(g.startDs, g.accept, g);
- if (expr.utf8 && orig) {
- DEBUG_PRINTF("rectifying %u\n", expr.report);
- Report ir = rm.getBasicInternalReport(expr);
+ NFAEdge orig = edge(g.startDs, g.accept, g);
+ if (expr.utf8 && orig) {
+ DEBUG_PRINTF("rectifying %u\n", expr.report);
+ Report ir = rm.getBasicInternalReport(expr);
ReportID rep = rm.getInternalId(ir);
NFAVertex v_a = add_vertex(g);
@@ -550,8 +550,8 @@ void ensureCodePointStart(ReportManager &rm, NGHolder &g,
add_edge(g.start, v_4, g);
add_edge(g.startDs, v_4, g);
remove_edge(orig, g);
- renumber_edges(g);
- clearReports(g);
+ renumber_edges(g);
+ clearReports(g);
}
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_asserts.h b/contrib/libs/hyperscan/src/nfagraph/ng_asserts.h
index 04d619752d3..2534f571473 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_asserts.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_asserts.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,14 +36,14 @@
namespace ue2 {
struct BoundaryReports;
-class ExpressionInfo;
-class NGHolder;
+class ExpressionInfo;
+class NGHolder;
class ReportManager;
-void resolveAsserts(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr);
+void resolveAsserts(ReportManager &rm, NGHolder &g, const ExpressionInfo &expr);
-void ensureCodePointStart(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr);
+void ensureCodePointStart(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_builder.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_builder.cpp
index a740eab65e6..60f667f4912 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_builder.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_builder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,11 +28,11 @@
/** \file
* \brief: NFA Graph Builder: used by Glushkov construction to construct an
- * NGHolder from a parsed expression.
+ * NGHolder from a parsed expression.
*/
-
-#include "ng_builder.h"
-
+
+#include "ng_builder.h"
+
#include "grey.h"
#include "ng.h"
#include "ng_util.h"
@@ -81,7 +81,7 @@ public:
void cloneRegion(Position first, Position last,
unsigned posOffset) override;
- BuiltExpression getGraph() override;
+ BuiltExpression getGraph() override;
private:
/** fetch a vertex given its Position ID. */
@@ -96,12 +96,12 @@ private:
/** \brief Greybox: used for resource limits. */
const Grey &grey;
- /** \brief Underlying graph. */
- unique_ptr<NGHolder> graph;
+ /** \brief Underlying graph. */
+ unique_ptr<NGHolder> graph;
+
+ /** \brief Underlying expression info. */
+ ExpressionInfo expr;
- /** \brief Underlying expression info. */
- ExpressionInfo expr;
-
/** \brief mapping from position to vertex. Use \ref getVertex for access.
* */
vector<NFAVertex> id2vertex;
@@ -113,9 +113,9 @@ private:
} // namespace
NFABuilderImpl::NFABuilderImpl(ReportManager &rm_in, const Grey &grey_in,
- const ParsedExpression &parsed)
- : rm(rm_in), grey(grey_in), graph(ue2::make_unique<NGHolder>()),
- expr(parsed.expr), vertIdx(N_SPECIALS) {
+ const ParsedExpression &parsed)
+ : rm(rm_in), grey(grey_in), graph(ue2::make_unique<NGHolder>()),
+ expr(parsed.expr), vertIdx(N_SPECIALS) {
// Reserve space for a reasonably-sized NFA
id2vertex.reserve(64);
@@ -133,8 +133,8 @@ NFABuilderImpl::~NFABuilderImpl() {
NFAVertex NFABuilderImpl::getVertex(Position pos) const {
assert(id2vertex.size() >= pos);
const NFAVertex v = id2vertex[pos];
- assert(v != NGHolder::null_vertex());
- assert((*graph)[v].index == pos);
+ assert(v != NGHolder::null_vertex());
+ assert((*graph)[v].index == pos);
return v;
}
@@ -149,10 +149,10 @@ void NFABuilderImpl::addVertex(Position pos) {
id2vertex.resize(pos + 1);
}
id2vertex[pos] = v;
- (*graph)[v].index = pos;
+ (*graph)[v].index = pos;
}
-BuiltExpression NFABuilderImpl::getGraph() {
+BuiltExpression NFABuilderImpl::getGraph() {
DEBUG_PRINTF("built graph has %zu vertices and %zu edges\n",
num_vertices(*graph), num_edges(*graph));
@@ -163,13 +163,13 @@ BuiltExpression NFABuilderImpl::getGraph() {
throw CompileError("Pattern too large.");
}
- return { expr, move(graph) };
+ return { expr, move(graph) };
}
void NFABuilderImpl::setNodeReportID(Position pos, int offsetAdjust) {
- Report ir = rm.getBasicInternalReport(expr, offsetAdjust);
+ Report ir = rm.getBasicInternalReport(expr, offsetAdjust);
DEBUG_PRINTF("setting report id on %u = (%u, %d, %u)\n",
- pos, expr.report, offsetAdjust, ir.ekey);
+ pos, expr.report, offsetAdjust, ir.ekey);
NFAVertex v = getVertex(pos);
auto &reports = (*graph)[v].reports;
@@ -179,24 +179,24 @@ void NFABuilderImpl::setNodeReportID(Position pos, int offsetAdjust) {
void NFABuilderImpl::addCharReach(Position pos, const CharReach &cr) {
NFAVertex v = getVertex(pos);
- (*graph)[v].char_reach |= cr;
+ (*graph)[v].char_reach |= cr;
}
void NFABuilderImpl::setAssertFlag(Position pos, u32 flag) {
NFAVertex v = getVertex(pos);
- (*graph)[v].assert_flags |= flag;
+ (*graph)[v].assert_flags |= flag;
}
u32 NFABuilderImpl::getAssertFlag(Position pos) {
NFAVertex v = getVertex(pos);
- return (*graph)[v].assert_flags;
+ return (*graph)[v].assert_flags;
}
pair<NFAEdge, bool> NFABuilderImpl::addEdge(NFAVertex u, NFAVertex v) {
// assert that the edge doesn't already exist
- assert(edge(u, v, *graph).second == false);
+ assert(edge(u, v, *graph).second == false);
- return add_edge(u, v, *graph);
+ return add_edge(u, v, *graph);
}
void NFABuilderImpl::addEdge(Position startPos, Position endPos) {
@@ -209,16 +209,16 @@ void NFABuilderImpl::addEdge(Position startPos, Position endPos) {
if ((u == graph->start || u == graph->startDs) && v == graph->startDs) {
/* standard special -> special edges already exist */
- assert(edge(u, v, *graph).second == true);
+ assert(edge(u, v, *graph).second == true);
return;
}
- assert(edge(u, v, *graph).second == false);
+ assert(edge(u, v, *graph).second == false);
addEdge(u, v);
}
bool NFABuilderImpl::hasEdge(Position startPos, Position endPos) const {
- return edge(getVertex(startPos), getVertex(endPos), *graph).second;
+ return edge(getVertex(startPos), getVertex(endPos), *graph).second;
}
Position NFABuilderImpl::getStart() const {
@@ -252,7 +252,7 @@ Position NFABuilderImpl::makePositions(size_t nPositions) {
}
void NFABuilderImpl::cloneRegion(Position first, Position last, unsigned posOffset) {
- NGHolder &g = *graph;
+ NGHolder &g = *graph;
assert(posOffset > 0);
// walk the nodes between first and last and copy their vertex properties
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_builder.h b/contrib/libs/hyperscan/src/nfagraph/ng_builder.h
index 6ae1eea15f5..9f71b62235e 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_builder.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_builder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,7 +28,7 @@
/** \file
* \brief: NFA Graph Builder: used by Glushkov construction to construct an
- * NGHolder from a parsed expression.
+ * NGHolder from a parsed expression.
*/
#ifndef NG_BUILDER_H
@@ -37,7 +37,7 @@
#include "ue2common.h"
#include "parser/position.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include <memory>
@@ -45,14 +45,14 @@ namespace ue2 {
class CharReach;
class ReportManager;
-struct BuiltExpression;
+struct BuiltExpression;
struct CompileContext;
class ParsedExpression;
/** \brief Abstract builder interface. Use \ref makeNFABuilder to construct
* one. Used by GlushkovBuildState. */
-class NFABuilder : noncopyable {
+class NFABuilder : noncopyable {
public:
virtual ~NFABuilder();
@@ -83,10 +83,10 @@ public:
unsigned posOffset) = 0;
/**
- * \brief Returns the built NGHolder graph and ExpressionInfo.
+ * \brief Returns the built NGHolder graph and ExpressionInfo.
* Note that this builder cannot be used after this call.
*/
- virtual BuiltExpression getGraph() = 0;
+ virtual BuiltExpression getGraph() = 0;
};
/** Construct a usable NFABuilder. */
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.cpp
index daa78e1052a..3e9454eeedc 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.cpp
@@ -54,7 +54,7 @@
#include "ng_holder.h"
#include "ng_prune.h"
#include "ng_util.h"
-#include "grey.h"
+#include "grey.h"
#include "ue2common.h"
#include "util/graph_range.h"
#include "util/graph_undirected.h"
@@ -64,7 +64,7 @@
#include <vector>
#include <boost/graph/connected_components.hpp>
-#include <boost/graph/filtered_graph.hpp>
+#include <boost/graph/filtered_graph.hpp>
using namespace std;
@@ -164,7 +164,7 @@ flat_set<NFAVertex> findHeadShell(const NGHolder &g,
}
for (UNUSED auto v : shell) {
- DEBUG_PRINTF("shell: %zu\n", g[v].index);
+ DEBUG_PRINTF("shell: %zu\n", g[v].index);
}
return shell;
@@ -186,7 +186,7 @@ flat_set<NFAVertex> findTailShell(const NGHolder &g,
}
for (UNUSED auto v : shell) {
- DEBUG_PRINTF("shell: %zu\n", g[v].index);
+ DEBUG_PRINTF("shell: %zu\n", g[v].index);
}
return shell;
@@ -211,8 +211,8 @@ vector<NFAEdge> findShellEdges(const NGHolder &g,
if ((is_special(u, g) || contains(head_shell, u)) &&
(is_special(v, g) || contains(tail_shell, v))) {
- DEBUG_PRINTF("edge (%zu,%zu) is a shell edge\n", g[u].index,
- g[v].index);
+ DEBUG_PRINTF("edge (%zu,%zu) is a shell edge\n", g[u].index,
+ g[v].index);
shell_edges.push_back(e);
}
}
@@ -220,50 +220,50 @@ vector<NFAEdge> findShellEdges(const NGHolder &g,
return shell_edges;
}
-template<typename GetAdjRange>
-bool shellHasOnePath(const NGHolder &g, const flat_set<NFAVertex> &shell,
- GetAdjRange adj_range_func) {
- if (shell.empty()) {
- DEBUG_PRINTF("no shell\n");
- return false;
+template<typename GetAdjRange>
+bool shellHasOnePath(const NGHolder &g, const flat_set<NFAVertex> &shell,
+ GetAdjRange adj_range_func) {
+ if (shell.empty()) {
+ DEBUG_PRINTF("no shell\n");
+ return false;
}
-
- NFAVertex exit_vertex = NGHolder::null_vertex();
- for (auto u : shell) {
- for (auto v : adj_range_func(u, g)) {
- if (contains(shell, v)) {
- continue;
- }
- if (!exit_vertex) {
- exit_vertex = v;
- continue;
- }
- if (exit_vertex == v) {
- continue;
- }
- return false;
- }
- }
-
- return true;
+
+ NFAVertex exit_vertex = NGHolder::null_vertex();
+ for (auto u : shell) {
+ for (auto v : adj_range_func(u, g)) {
+ if (contains(shell, v)) {
+ continue;
+ }
+ if (!exit_vertex) {
+ exit_vertex = v;
+ continue;
+ }
+ if (exit_vertex == v) {
+ continue;
+ }
+ return false;
+ }
+ }
+
+ return true;
}
-/**
- * True if all edges out of vertices in the head shell lead to at most a single
- * outside vertex, or the inverse for the tail shell.
- */
+/**
+ * True if all edges out of vertices in the head shell lead to at most a single
+ * outside vertex, or the inverse for the tail shell.
+ */
static
-bool shellHasOnePath(const NGHolder &g, const flat_set<NFAVertex> &head_shell,
- const flat_set<NFAVertex> &tail_shell) {
- if (shellHasOnePath(g, head_shell, adjacent_vertices_range<NGHolder>)) {
- DEBUG_PRINTF("head shell has only one path through it\n");
- return true;
+bool shellHasOnePath(const NGHolder &g, const flat_set<NFAVertex> &head_shell,
+ const flat_set<NFAVertex> &tail_shell) {
+ if (shellHasOnePath(g, head_shell, adjacent_vertices_range<NGHolder>)) {
+ DEBUG_PRINTF("head shell has only one path through it\n");
+ return true;
}
- if (shellHasOnePath(g, tail_shell, inv_adjacent_vertices_range<NGHolder>)) {
- DEBUG_PRINTF("tail shell has only one path into it\n");
- return true;
- }
- return false;
+ if (shellHasOnePath(g, tail_shell, inv_adjacent_vertices_range<NGHolder>)) {
+ DEBUG_PRINTF("tail shell has only one path into it\n");
+ return true;
+ }
+ return false;
}
/**
@@ -271,44 +271,44 @@ bool shellHasOnePath(const NGHolder &g, const flat_set<NFAVertex> &head_shell,
* one or more connected components, adding them to the comps deque.
*/
static
-void splitIntoComponents(unique_ptr<NGHolder> g,
- deque<unique_ptr<NGHolder>> &comps,
+void splitIntoComponents(unique_ptr<NGHolder> g,
+ deque<unique_ptr<NGHolder>> &comps,
const depth &max_head_depth,
const depth &max_tail_depth, bool *shell_comp) {
- DEBUG_PRINTF("graph has %zu vertices\n", num_vertices(*g));
+ DEBUG_PRINTF("graph has %zu vertices\n", num_vertices(*g));
assert(shell_comp);
*shell_comp = false;
// Compute "shell" head and tail subgraphs.
- auto depths = calcBidiDepths(*g);
- auto head_shell = findHeadShell(*g, depths, max_head_depth);
- auto tail_shell = findTailShell(*g, depths, max_tail_depth);
+ auto depths = calcBidiDepths(*g);
+ auto head_shell = findHeadShell(*g, depths, max_head_depth);
+ auto tail_shell = findTailShell(*g, depths, max_tail_depth);
for (auto v : head_shell) {
tail_shell.erase(v);
}
- if (head_shell.size() + tail_shell.size() + N_SPECIALS >=
- num_vertices(*g)) {
+ if (head_shell.size() + tail_shell.size() + N_SPECIALS >=
+ num_vertices(*g)) {
DEBUG_PRINTF("all in shell component\n");
- comps.push_back(std::move(g));
+ comps.push_back(std::move(g));
*shell_comp = true;
return;
}
- // Find edges connecting the head and tail shells directly.
- vector<NFAEdge> shell_edges = findShellEdges(*g, head_shell, tail_shell);
+ // Find edges connecting the head and tail shells directly.
+ vector<NFAEdge> shell_edges = findShellEdges(*g, head_shell, tail_shell);
DEBUG_PRINTF("%zu vertices in head, %zu in tail, %zu shell edges\n",
head_shell.size(), tail_shell.size(), shell_edges.size());
- // If there are no shell edges and only one path out of the head shell or
- // into the tail shell, we aren't going to find more than one component.
- if (shell_edges.empty() && shellHasOnePath(*g, head_shell, tail_shell)) {
- DEBUG_PRINTF("single component\n");
- comps.push_back(std::move(g));
- return;
- }
+ // If there are no shell edges and only one path out of the head shell or
+ // into the tail shell, we aren't going to find more than one component.
+ if (shell_edges.empty() && shellHasOnePath(*g, head_shell, tail_shell)) {
+ DEBUG_PRINTF("single component\n");
+ comps.push_back(std::move(g));
+ return;
+ }
auto ug = make_undirected_graph(*g);
@@ -318,18 +318,18 @@ void splitIntoComponents(unique_ptr<NGHolder> g,
bad_vertices.insert(head_shell.begin(), head_shell.end());
bad_vertices.insert(tail_shell.begin(), tail_shell.end());
- auto filtered_ug = boost::make_filtered_graph(
+ auto filtered_ug = boost::make_filtered_graph(
ug, boost::keep_all(), make_bad_vertex_filter(&bad_vertices));
- // Actually run the connected components algorithm.
+ // Actually run the connected components algorithm.
map<NFAVertex, u32> split_components;
const u32 num = connected_components(
- filtered_ug, boost::make_assoc_property_map(split_components));
+ filtered_ug, boost::make_assoc_property_map(split_components));
assert(num > 0);
if (num == 1 && shell_edges.empty()) {
DEBUG_PRINTF("single component\n");
- comps.push_back(std::move(g));
+ comps.push_back(std::move(g));
return;
}
@@ -342,27 +342,27 @@ void splitIntoComponents(unique_ptr<NGHolder> g,
NFAVertex v = m.first;
u32 c = m.second;
verts[c].push_back(v);
- DEBUG_PRINTF("vertex %zu is in comp %u\n", (*g)[v].index, c);
+ DEBUG_PRINTF("vertex %zu is in comp %u\n", (*g)[v].index, c);
}
- unordered_map<NFAVertex, NFAVertex> v_map; // temp map for fillHolder
+ unordered_map<NFAVertex, NFAVertex> v_map; // temp map for fillHolder
for (auto &vv : verts) {
// Shells are in every component.
vv.insert(vv.end(), begin(head_shell), end(head_shell));
vv.insert(vv.end(), begin(tail_shell), end(tail_shell));
- /* Sort for determinism. Still required as NFAUndirectedVertex have
- * no deterministic ordering (split_components map). */
- sort(begin(vv), end(vv));
+ /* Sort for determinism. Still required as NFAUndirectedVertex have
+ * no deterministic ordering (split_components map). */
+ sort(begin(vv), end(vv));
auto gc = ue2::make_unique<NGHolder>();
v_map.clear();
- fillHolder(gc.get(), *g, vv, &v_map);
+ fillHolder(gc.get(), *g, vv, &v_map);
// Remove shell edges, which will get their own component.
for (const auto &e : shell_edges) {
- auto cu = v_map.at(source(e, *g));
- auto cv = v_map.at(target(e, *g));
+ auto cu = v_map.at(source(e, *g));
+ auto cv = v_map.at(target(e, *g));
assert(edge(cu, cv, *gc).second);
remove_edge(cu, cv, *gc);
}
@@ -381,7 +381,7 @@ void splitIntoComponents(unique_ptr<NGHolder> g,
auto gc = ue2::make_unique<NGHolder>();
v_map.clear();
- fillHolder(gc.get(), *g, vv, &v_map);
+ fillHolder(gc.get(), *g, vv, &v_map);
pruneUseless(*gc);
DEBUG_PRINTF("shell edge component %zu has %zu vertices\n",
@@ -390,12 +390,12 @@ void splitIntoComponents(unique_ptr<NGHolder> g,
*shell_comp = true;
}
- // Ensure that only vertices with accept edges have reports.
- for (auto &gc : comps) {
- assert(gc);
- clearReports(*gc);
- }
-
+ // Ensure that only vertices with accept edges have reports.
+ for (auto &gc : comps) {
+ assert(gc);
+ clearReports(*gc);
+ }
+
// We should never produce empty component graphs.
assert(all_of(begin(comps), end(comps),
[](const unique_ptr<NGHolder> &g_comp) {
@@ -403,39 +403,39 @@ void splitIntoComponents(unique_ptr<NGHolder> g,
}));
}
-deque<unique_ptr<NGHolder>> calcComponents(unique_ptr<NGHolder> g,
- const Grey &grey) {
+deque<unique_ptr<NGHolder>> calcComponents(unique_ptr<NGHolder> g,
+ const Grey &grey) {
deque<unique_ptr<NGHolder>> comps;
// For trivial cases, we needn't bother running the full
// connected_components algorithm.
- if (!grey.calcComponents || isAlternationOfClasses(*g)) {
- comps.push_back(std::move(g));
+ if (!grey.calcComponents || isAlternationOfClasses(*g)) {
+ comps.push_back(std::move(g));
return comps;
}
bool shell_comp = false;
- splitIntoComponents(std::move(g), comps, depth(MAX_HEAD_SHELL_DEPTH),
- depth(MAX_TAIL_SHELL_DEPTH), &shell_comp);
+ splitIntoComponents(std::move(g), comps, depth(MAX_HEAD_SHELL_DEPTH),
+ depth(MAX_TAIL_SHELL_DEPTH), &shell_comp);
if (shell_comp) {
DEBUG_PRINTF("re-running on shell comp\n");
assert(!comps.empty());
- auto sc = std::move(comps.back());
+ auto sc = std::move(comps.back());
comps.pop_back();
- splitIntoComponents(std::move(sc), comps, depth(0), depth(0),
- &shell_comp);
+ splitIntoComponents(std::move(sc), comps, depth(0), depth(0),
+ &shell_comp);
}
DEBUG_PRINTF("finished; split into %zu components\n", comps.size());
return comps;
}
-void recalcComponents(deque<unique_ptr<NGHolder>> &comps, const Grey &grey) {
- if (!grey.calcComponents) {
- return;
- }
-
+void recalcComponents(deque<unique_ptr<NGHolder>> &comps, const Grey &grey) {
+ if (!grey.calcComponents) {
+ return;
+ }
+
deque<unique_ptr<NGHolder>> out;
for (auto &gc : comps) {
@@ -444,13 +444,13 @@ void recalcComponents(deque<unique_ptr<NGHolder>> &comps, const Grey &grey) {
}
if (isAlternationOfClasses(*gc)) {
- out.push_back(std::move(gc));
+ out.push_back(std::move(gc));
continue;
}
- auto gc_comps = calcComponents(std::move(gc), grey);
- out.insert(end(out), std::make_move_iterator(begin(gc_comps)),
- std::make_move_iterator(end(gc_comps)));
+ auto gc_comps = calcComponents(std::move(gc), grey);
+ out.insert(end(out), std::make_move_iterator(begin(gc_comps)),
+ std::make_move_iterator(end(gc_comps)));
}
// Replace comps with our recalculated list.
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.h b/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.h
index 97f0f9b5dfb..1bcdc5f81e1 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_calc_components.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,15 +39,15 @@
namespace ue2 {
class NGHolder;
-struct Grey;
+struct Grey;
bool isAlternationOfClasses(const NGHolder &g);
-std::deque<std::unique_ptr<NGHolder>>
-calcComponents(std::unique_ptr<NGHolder> g, const Grey &grey);
+std::deque<std::unique_ptr<NGHolder>>
+calcComponents(std::unique_ptr<NGHolder> g, const Grey &grey);
-void recalcComponents(std::deque<std::unique_ptr<NGHolder>> &comps,
- const Grey &grey);
+void recalcComponents(std::deque<std::unique_ptr<NGHolder>> &comps,
+ const Grey &grey);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_cyclic_redundancy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_cyclic_redundancy.cpp
index 928455fbd22..0b24bf07a82 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_cyclic_redundancy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_cyclic_redundancy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -62,11 +62,11 @@
#include "ng_prune.h"
#include "ng_util.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
-#include <algorithm>
+#include <algorithm>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/reverse_graph.hpp>
@@ -101,7 +101,7 @@ class SearchVisitor : public boost::default_dfs_visitor {
template<class Vertex, class Graph>
void discover_vertex(const Vertex &v, const Graph &g) const {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
if (is_special(v, g)) {
DEBUG_PRINTF("start or accept\n");
throw SearchFailed();
@@ -125,17 +125,17 @@ class SearchVisitor : public boost::default_dfs_visitor {
} // namespace
-template<class Graph, class ColorMap>
+template<class Graph, class ColorMap>
static
bool searchForward(const Graph &g, const CharReach &reach,
- ColorMap &colours,
+ ColorMap &colours,
const flat_set<typename Graph::vertex_descriptor> &s,
typename Graph::vertex_descriptor w) {
- colours.fill(small_color::white);
+ colours.fill(small_color::white);
try {
- depth_first_visit(g, w, SearchVisitor(reach), colours,
- VertexInSet<typename Graph::vertex_descriptor, Graph>(s));
- } catch (SearchFailed &) {
+ depth_first_visit(g, w, SearchVisitor(reach), colours,
+ VertexInSet<typename Graph::vertex_descriptor, Graph>(s));
+ } catch (SearchFailed &) {
return false;
}
@@ -143,14 +143,14 @@ bool searchForward(const Graph &g, const CharReach &reach,
}
static
-NFAEdge to_raw(const NFAEdge &e, const NGHolder &) {
+NFAEdge to_raw(const NFAEdge &e, const NGHolder &) {
return e;
}
static
-NFAEdge to_raw(const reverse_graph<NGHolder, NGHolder &>::edge_descriptor &e,
- const reverse_graph<NGHolder, NGHolder &> &g) {
- return get(boost::edge_underlying, g, e);
+NFAEdge to_raw(const reverse_graph<NGHolder, NGHolder &>::edge_descriptor &e,
+ const reverse_graph<NGHolder, NGHolder &> &g) {
+ return get(boost::edge_underlying, g, e);
}
/* returns true if we did stuff */
@@ -164,9 +164,9 @@ bool removeCyclicPathRedundancy(Graph &g, typename Graph::vertex_descriptor v,
typedef typename Graph::vertex_descriptor vertex_descriptor;
- // Colour map used for depth_first_visit().
- auto colours = make_small_color_map(g);
-
+ // Colour map used for depth_first_visit().
+ auto colours = make_small_color_map(g);
+
// precalc successors of v.
flat_set<vertex_descriptor> succ_v;
insert(&succ_v, adjacent_vertices(v, g));
@@ -182,7 +182,7 @@ bool removeCyclicPathRedundancy(Graph &g, typename Graph::vertex_descriptor v,
continue;
}
- DEBUG_PRINTF("- checking u %zu\n", g[u].index);
+ DEBUG_PRINTF("- checking u %zu\n", g[u].index);
// let s be intersection(succ(u), succ(v))
s.clear();
@@ -203,18 +203,18 @@ bool removeCyclicPathRedundancy(Graph &g, typename Graph::vertex_descriptor v,
continue;
}
- DEBUG_PRINTF(" - checking w %zu\n", g[w].index);
+ DEBUG_PRINTF(" - checking w %zu\n", g[w].index);
if (!searchForward(g, reach, colours, succ_v, w)) {
- continue;
+ continue;
}
-
- DEBUG_PRINTF("removing edge (%zu,%zu)\n", g[u].index, g[w].index);
- /* we are currently iterating over the in-edges of v, so it
- would be unwise to remove edges to v. However, */
- assert(w != v); /* as v is in s */
- remove_edge(to_raw(e_u, g), raw);
- did_stuff = true;
+
+ DEBUG_PRINTF("removing edge (%zu,%zu)\n", g[u].index, g[w].index);
+ /* we are currently iterating over the in-edges of v, so it
+ would be unwise to remove edges to v. However, */
+ assert(w != v); /* as v is in s */
+ remove_edge(to_raw(e_u, g), raw);
+ did_stuff = true;
}
}
@@ -231,7 +231,7 @@ bool cyclicPathRedundancyPass(Graph &g, NGHolder &raw) {
continue;
}
- DEBUG_PRINTF("examining cyclic vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("examining cyclic vertex %zu\n", g[v].index);
did_stuff |= removeCyclicPathRedundancy(g, v, raw);
}
@@ -239,10 +239,10 @@ bool cyclicPathRedundancyPass(Graph &g, NGHolder &raw) {
}
bool removeCyclicPathRedundancy(NGHolder &g) {
- assert(hasCorrectlyNumberedVertices(g));
-
+ assert(hasCorrectlyNumberedVertices(g));
+
// Forward pass.
- bool f_changed = cyclicPathRedundancyPass(g, g);
+ bool f_changed = cyclicPathRedundancyPass(g, g);
if (f_changed) {
DEBUG_PRINTF("edges removed by forward pass\n");
pruneUseless(g);
@@ -250,8 +250,8 @@ bool removeCyclicPathRedundancy(NGHolder &g) {
// Reverse pass.
DEBUG_PRINTF("REVERSE PASS\n");
- typedef reverse_graph<NGHolder, NGHolder &> RevGraph;
- RevGraph revg(g);
+ typedef reverse_graph<NGHolder, NGHolder &> RevGraph;
+ RevGraph revg(g);
bool r_changed = cyclicPathRedundancyPass(revg, g);
if (r_changed) {
DEBUG_PRINTF("edges removed by reverse pass\n");
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_depth.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_depth.cpp
index 1335b6e2672..6c90326ce47 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_depth.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_depth.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,34 +26,34 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief NFA graph vertex depth calculations.
*/
#include "ng_depth.h"
#include "ng_util.h"
#include "ue2common.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include <deque>
#include <vector>
-#include <boost/graph/breadth_first_search.hpp>
+#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dag_shortest_paths.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/filtered_graph.hpp>
-#include <boost/graph/property_maps/constant_property_map.hpp>
+#include <boost/graph/property_maps/constant_property_map.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/topological_sort.hpp>
-#include <boost/range/adaptor/reversed.hpp>
+#include <boost/range/adaptor/reversed.hpp>
using namespace std;
using boost::filtered_graph;
-using boost::make_filtered_graph;
+using boost::make_filtered_graph;
using boost::make_constant_property;
using boost::reverse_graph;
-using boost::adaptors::reverse;
+using boost::adaptors::reverse;
namespace ue2 {
@@ -125,37 +125,37 @@ private:
} // namespace
-template<class Graph>
+template<class Graph>
static
-vector<bool> findLoopReachable(const Graph &g,
- const typename Graph::vertex_descriptor src) {
- vector<bool> deadNodes(num_vertices(g));
-
- using Edge = typename Graph::edge_descriptor;
- using Vertex = typename Graph::vertex_descriptor;
- using EdgeSet = set<Edge>;
-
+vector<bool> findLoopReachable(const Graph &g,
+ const typename Graph::vertex_descriptor src) {
+ vector<bool> deadNodes(num_vertices(g));
+
+ using Edge = typename Graph::edge_descriptor;
+ using Vertex = typename Graph::vertex_descriptor;
+ using EdgeSet = set<Edge>;
+
EdgeSet deadEdges;
BackEdges<EdgeSet> be(deadEdges);
- auto colors = make_small_color_map(g);
+ auto colors = make_small_color_map(g);
- depth_first_search(g, be, colors, src);
- auto af = make_bad_edge_filter(&deadEdges);
- auto acyclic_g = make_filtered_graph(g, af);
+ depth_first_search(g, be, colors, src);
+ auto af = make_bad_edge_filter(&deadEdges);
+ auto acyclic_g = make_filtered_graph(g, af);
- vector<Vertex> topoOrder; /* actually reverse topological order */
+ vector<Vertex> topoOrder; /* actually reverse topological order */
topoOrder.reserve(deadNodes.size());
- topological_sort(acyclic_g, back_inserter(topoOrder), color_map(colors));
+ topological_sort(acyclic_g, back_inserter(topoOrder), color_map(colors));
for (const auto &e : deadEdges) {
- size_t srcIdx = g[source(e, g)].index;
+ size_t srcIdx = g[source(e, g)].index;
if (srcIdx != NODE_START_DOTSTAR) {
deadNodes[srcIdx] = true;
}
}
- for (auto v : reverse(topoOrder)) {
+ for (auto v : reverse(topoOrder)) {
for (const auto &e : in_edges_range(v, g)) {
if (deadNodes[g[source(e, g)].index]) {
deadNodes[g[v].index] = true;
@@ -163,19 +163,19 @@ vector<bool> findLoopReachable(const Graph &g,
}
}
}
-
- return deadNodes;
+
+ return deadNodes;
}
template <class GraphT>
static
-void calcDepthFromSource(const GraphT &g,
+void calcDepthFromSource(const GraphT &g,
typename GraphT::vertex_descriptor srcVertex,
- const vector<bool> &deadNodes, vector<int> &dMin,
- vector<int> &dMax) {
+ const vector<bool> &deadNodes, vector<int> &dMin,
+ vector<int> &dMax) {
typedef typename GraphT::edge_descriptor EdgeT;
- const size_t numVerts = num_vertices(g);
+ const size_t numVerts = num_vertices(g);
NodeFilter<GraphT> nf(&deadNodes, &g);
StartFilter<GraphT> sf(&g);
@@ -201,22 +201,22 @@ void calcDepthFromSource(const GraphT &g,
using boost::make_iterator_property_map;
- auto min_index_map = get(vertex_index, mindist_g);
+ auto min_index_map = get(vertex_index, mindist_g);
breadth_first_search(mindist_g, srcVertex,
visitor(make_bfs_visitor(record_distances(
- make_iterator_property_map(dMin.begin(),
- min_index_map),
- boost::on_tree_edge())))
- .color_map(make_small_color_map(mindist_g)));
+ make_iterator_property_map(dMin.begin(),
+ min_index_map),
+ boost::on_tree_edge())))
+ .color_map(make_small_color_map(mindist_g)));
- auto max_index_map = get(vertex_index, maxdist_g);
+ auto max_index_map = get(vertex_index, maxdist_g);
dag_shortest_paths(maxdist_g, srcVertex,
- distance_map(make_iterator_property_map(dMax.begin(),
- max_index_map))
- .weight_map(make_constant_property<EdgeT>(-1))
- .color_map(make_small_color_map(maxdist_g)));
+ distance_map(make_iterator_property_map(dMax.begin(),
+ max_index_map))
+ .weight_map(make_constant_property<EdgeT>(-1))
+ .color_map(make_small_color_map(maxdist_g)));
for (size_t i = 0; i < numVerts; i++) {
if (dMin[i] > DIST_UNREACHABLE) {
@@ -261,14 +261,14 @@ DepthMinMax getDepths(u32 idx, const vector<int> &dMin,
template<class Graph, class Output>
static
-void calcAndStoreDepth(const Graph &g,
+void calcAndStoreDepth(const Graph &g,
const typename Graph::vertex_descriptor src,
const vector<bool> &deadNodes,
vector<int> &dMin /* util */,
vector<int> &dMax /* util */,
vector<Output> &depths,
DepthMinMax Output::*store) {
- calcDepthFromSource(g, src, deadNodes, dMin, dMax);
+ calcDepthFromSource(g, src, deadNodes, dMin, dMax);
for (auto v : vertices_range(g)) {
u32 idx = g[v].index;
@@ -278,11 +278,11 @@ void calcAndStoreDepth(const Graph &g,
}
}
-vector<NFAVertexDepth> calcDepths(const NGHolder &g) {
+vector<NFAVertexDepth> calcDepths(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
const size_t numVertices = num_vertices(g);
- vector<NFAVertexDepth> depths(numVertices);
+ vector<NFAVertexDepth> depths(numVertices);
vector<int> dMin;
vector<int> dMax;
@@ -290,56 +290,56 @@ vector<NFAVertexDepth> calcDepths(const NGHolder &g) {
* create a filtered graph for max depth calculations: all nodes/edges
* reachable from a loop need to be removed
*/
- auto deadNodes = findLoopReachable(g, g.start);
+ auto deadNodes = findLoopReachable(g, g.start);
DEBUG_PRINTF("doing start\n");
- calcAndStoreDepth(g, g.start, deadNodes, dMin, dMax, depths,
- &NFAVertexDepth::fromStart);
+ calcAndStoreDepth(g, g.start, deadNodes, dMin, dMax, depths,
+ &NFAVertexDepth::fromStart);
DEBUG_PRINTF("doing startds\n");
- calcAndStoreDepth(g, g.startDs, deadNodes, dMin, dMax, depths,
- &NFAVertexDepth::fromStartDotStar);
-
- return depths;
+ calcAndStoreDepth(g, g.startDs, deadNodes, dMin, dMax, depths,
+ &NFAVertexDepth::fromStartDotStar);
+
+ return depths;
}
-vector<NFAVertexRevDepth> calcRevDepths(const NGHolder &g) {
+vector<NFAVertexRevDepth> calcRevDepths(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
const size_t numVertices = num_vertices(g);
- vector<NFAVertexRevDepth> depths(numVertices);
+ vector<NFAVertexRevDepth> depths(numVertices);
vector<int> dMin;
vector<int> dMax;
/* reverse the graph before walking it */
- typedef reverse_graph<NGHolder, const NGHolder &> RevNFAGraph;
- const RevNFAGraph rg(g);
+ typedef reverse_graph<NGHolder, const NGHolder &> RevNFAGraph;
+ const RevNFAGraph rg(g);
+
+ assert(num_vertices(g) == num_vertices(rg));
- assert(num_vertices(g) == num_vertices(rg));
-
/*
* create a filtered graph for max depth calculations: all nodes/edges
* reachable from a loop need to be removed
*/
- auto deadNodes = findLoopReachable(rg, g.acceptEod);
+ auto deadNodes = findLoopReachable(rg, g.acceptEod);
DEBUG_PRINTF("doing accept\n");
calcAndStoreDepth<RevNFAGraph, NFAVertexRevDepth>(
- rg, g.accept, deadNodes, dMin, dMax, depths,
+ rg, g.accept, deadNodes, dMin, dMax, depths,
&NFAVertexRevDepth::toAccept);
DEBUG_PRINTF("doing accepteod\n");
deadNodes[NODE_ACCEPT] = true; // Hide accept->acceptEod edge.
calcAndStoreDepth<RevNFAGraph, NFAVertexRevDepth>(
- rg, g.acceptEod, deadNodes, dMin, dMax, depths,
+ rg, g.acceptEod, deadNodes, dMin, dMax, depths,
&NFAVertexRevDepth::toAcceptEod);
-
- return depths;
+
+ return depths;
}
-vector<NFAVertexBidiDepth> calcBidiDepths(const NGHolder &g) {
+vector<NFAVertexBidiDepth> calcBidiDepths(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
const size_t numVertices = num_vertices(g);
- vector<NFAVertexBidiDepth> depths(numVertices);
+ vector<NFAVertexBidiDepth> depths(numVertices);
vector<int> dMin;
vector<int> dMax;
@@ -347,52 +347,52 @@ vector<NFAVertexBidiDepth> calcBidiDepths(const NGHolder &g) {
* create a filtered graph for max depth calculations: all nodes/edges
* reachable from a loop need to be removed
*/
- auto deadNodes = findLoopReachable(g, g.start);
+ auto deadNodes = findLoopReachable(g, g.start);
DEBUG_PRINTF("doing start\n");
- calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
- g, g.start, deadNodes, dMin, dMax, depths,
+ calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
+ g, g.start, deadNodes, dMin, dMax, depths,
&NFAVertexBidiDepth::fromStart);
DEBUG_PRINTF("doing startds\n");
- calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
- g, g.startDs, deadNodes, dMin, dMax, depths,
+ calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
+ g, g.startDs, deadNodes, dMin, dMax, depths,
&NFAVertexBidiDepth::fromStartDotStar);
/* Now go backwards */
- typedef reverse_graph<NGHolder, const NGHolder &> RevNFAGraph;
- const RevNFAGraph rg(g);
- deadNodes = findLoopReachable(rg, g.acceptEod);
+ typedef reverse_graph<NGHolder, const NGHolder &> RevNFAGraph;
+ const RevNFAGraph rg(g);
+ deadNodes = findLoopReachable(rg, g.acceptEod);
DEBUG_PRINTF("doing accept\n");
calcAndStoreDepth<RevNFAGraph, NFAVertexBidiDepth>(
- rg, g.accept, deadNodes, dMin, dMax, depths,
+ rg, g.accept, deadNodes, dMin, dMax, depths,
&NFAVertexBidiDepth::toAccept);
DEBUG_PRINTF("doing accepteod\n");
deadNodes[NODE_ACCEPT] = true; // Hide accept->acceptEod edge.
calcAndStoreDepth<RevNFAGraph, NFAVertexBidiDepth>(
- rg, g.acceptEod, deadNodes, dMin, dMax, depths,
+ rg, g.acceptEod, deadNodes, dMin, dMax, depths,
&NFAVertexBidiDepth::toAcceptEod);
-
- return depths;
+
+ return depths;
}
-vector<DepthMinMax> calcDepthsFrom(const NGHolder &g, const NFAVertex src) {
+vector<DepthMinMax> calcDepthsFrom(const NGHolder &g, const NFAVertex src) {
assert(hasCorrectlyNumberedVertices(g));
const size_t numVertices = num_vertices(g);
- auto deadNodes = findLoopReachable(g, g.start);
+ auto deadNodes = findLoopReachable(g, g.start);
vector<int> dMin, dMax;
- calcDepthFromSource(g, src, deadNodes, dMin, dMax);
+ calcDepthFromSource(g, src, deadNodes, dMin, dMax);
- vector<DepthMinMax> depths(numVertices);
+ vector<DepthMinMax> depths(numVertices);
for (auto v : vertices_range(g)) {
- auto idx = g[v].index;
+ auto idx = g[v].index;
depths.at(idx) = getDepths(idx, dMin, dMax);
}
-
- return depths;
+
+ return depths;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_depth.h b/contrib/libs/hyperscan/src/nfagraph/ng_depth.h
index fbec996b892..36cca87e845 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_depth.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_depth.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,15 +26,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief NFA graph vertex depth calculations.
*/
-#ifndef NG_DEPTH_H
-#define NG_DEPTH_H
+#ifndef NG_DEPTH_H
+#define NG_DEPTH_H
-#include "ue2common.h"
+#include "ue2common.h"
#include "nfagraph/ng_holder.h"
#include "util/depth.h"
@@ -63,37 +63,37 @@ struct NFAVertexRevDepth {
/**
* \brief Encapsulates min/max depths relative to all of our special vertices.
*/
-struct NFAVertexBidiDepth {
- DepthMinMax fromStart;
- DepthMinMax fromStartDotStar;
- DepthMinMax toAccept;
- DepthMinMax toAcceptEod;
+struct NFAVertexBidiDepth {
+ DepthMinMax fromStart;
+ DepthMinMax fromStartDotStar;
+ DepthMinMax toAccept;
+ DepthMinMax toAcceptEod;
};
/**
- * \brief Calculate depths from start and startDs. Returns them in a vector,
- * indexed by vertex index.
+ * \brief Calculate depths from start and startDs. Returns them in a vector,
+ * indexed by vertex index.
*/
-std::vector<NFAVertexDepth> calcDepths(const NGHolder &g);
+std::vector<NFAVertexDepth> calcDepths(const NGHolder &g);
/**
- * \brief Calculate depths to accept and acceptEod. Returns them in a vector,
- * indexed by vertex index.
+ * \brief Calculate depths to accept and acceptEod. Returns them in a vector,
+ * indexed by vertex index.
*/
-std::vector<NFAVertexRevDepth> calcRevDepths(const NGHolder &g);
+std::vector<NFAVertexRevDepth> calcRevDepths(const NGHolder &g);
/**
- * \brief Calculate depths to/from all special vertices. Returns them in a
- * vector, indexed by vertex index.
+ * \brief Calculate depths to/from all special vertices. Returns them in a
+ * vector, indexed by vertex index.
*/
-std::vector<NFAVertexBidiDepth> calcBidiDepths(const NGHolder &g);
+std::vector<NFAVertexBidiDepth> calcBidiDepths(const NGHolder &g);
-/**
- * \brief Calculate the (min, max) depths from the given \p src to every vertex
- * in the graph and return them in a vector, indexed by \p vertex_index.
- */
-std::vector<DepthMinMax> calcDepthsFrom(const NGHolder &g, const NFAVertex src);
+/**
+ * \brief Calculate the (min, max) depths from the given \p src to every vertex
+ * in the graph and return them in a vector, indexed by \p vertex_index.
+ */
+std::vector<DepthMinMax> calcDepthsFrom(const NGHolder &g, const NFAVertex src);
} // namespace ue2
-#endif // NG_DEPTH_H
+#endif // NG_DEPTH_H
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_dominators.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_dominators.cpp
index 157784700e2..d6a064d12fd 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_dominators.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_dominators.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,7 +38,7 @@
#include "ng_util.h"
#include <boost-patched/graph/dominator_tree.hpp> // locally patched version
-#include <boost-patched/graph/reverse_graph.hpp>
+#include <boost-patched/graph/reverse_graph.hpp>
using namespace std;
using boost::make_assoc_property_map;
@@ -47,47 +47,47 @@ using boost::make_iterator_property_map;
namespace ue2 {
template <class Graph>
-unordered_map<NFAVertex, NFAVertex> calcDominators(const Graph &g,
- typename Graph::vertex_descriptor source) {
- using Vertex = typename Graph::vertex_descriptor;
+unordered_map<NFAVertex, NFAVertex> calcDominators(const Graph &g,
+ typename Graph::vertex_descriptor source) {
+ using Vertex = typename Graph::vertex_descriptor;
const size_t num_verts = num_vertices(g);
auto index_map = get(&NFAGraphVertexProps::index, g);
vector<size_t> dfnum(num_verts, 0);
- vector<Vertex> parents(num_verts, Graph::null_vertex());
+ vector<Vertex> parents(num_verts, Graph::null_vertex());
auto dfnum_map = make_iterator_property_map(dfnum.begin(), index_map);
auto parent_map = make_iterator_property_map(parents.begin(), index_map);
- vector<Vertex> vertices_by_dfnum(num_verts, Graph::null_vertex());
+ vector<Vertex> vertices_by_dfnum(num_verts, Graph::null_vertex());
// Output map.
- vector<Vertex> doms(num_verts, Graph::null_vertex());
- auto dom_map = make_iterator_property_map(doms.begin(), index_map);
+ vector<Vertex> doms(num_verts, Graph::null_vertex());
+ auto dom_map = make_iterator_property_map(doms.begin(), index_map);
boost_ue2::lengauer_tarjan_dominator_tree(g, source, index_map, dfnum_map,
parent_map, vertices_by_dfnum,
dom_map);
- /* Translate back to an NFAVertex map */
- unordered_map<NFAVertex, NFAVertex> doms2;
- doms2.reserve(num_verts);
- for (auto v : vertices_range(g)) {
- auto dom_of_v = doms[g[v].index];
- if (dom_of_v) {
- doms2.emplace(v, dom_of_v);
- }
- }
- return doms2;
+ /* Translate back to an NFAVertex map */
+ unordered_map<NFAVertex, NFAVertex> doms2;
+ doms2.reserve(num_verts);
+ for (auto v : vertices_range(g)) {
+ auto dom_of_v = doms[g[v].index];
+ if (dom_of_v) {
+ doms2.emplace(v, dom_of_v);
+ }
+ }
+ return doms2;
}
-unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g) {
+unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
- return calcDominators(g, g.start);
+ return calcDominators(g, g.start);
}
-unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g) {
+unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
- return calcDominators(boost::reverse_graph<NGHolder, const NGHolder &>(g),
+ return calcDominators(boost::reverse_graph<NGHolder, const NGHolder &>(g),
g.acceptEod);
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_dominators.h b/contrib/libs/hyperscan/src/nfagraph/ng_dominators.h
index 7b05574d7de..f505b7e4710 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_dominators.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_dominators.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,13 +37,13 @@
#include "ng_holder.h"
-#include <unordered_map>
-
+#include <unordered_map>
+
namespace ue2 {
-std::unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g);
+std::unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g);
-std::unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g);
+std::unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_dump.h b/contrib/libs/hyperscan/src/nfagraph/ng_dump.h
index a1047729830..3e12d1d22e4 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_dump.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_dump.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,8 +37,8 @@
#include "ng_holder.h" // for graph types
#include "ue2common.h"
-#include <unordered_map>
-
+#include <unordered_map>
+
#ifdef DUMP_SUPPORT
#include <fstream>
#endif
@@ -49,7 +49,7 @@ namespace ue2 {
class NGHolder;
class NG;
-class ExpressionInfo;
+class ExpressionInfo;
class ReportManager;
// Implementations for stubs below -- all have the suffix "Impl".
@@ -62,8 +62,8 @@ void dumpGraphImpl(const char *name, const GraphT &g);
template <typename GraphT>
void dumpGraphImpl(const char *name, const GraphT &g, const ReportManager &rm);
-void dumpDotWrapperImpl(const NGHolder &g, const ExpressionInfo &expr,
- const char *name, const Grey &grey);
+void dumpDotWrapperImpl(const NGHolder &g, const ExpressionInfo &expr,
+ const char *name, const Grey &grey);
void dumpComponentImpl(const NGHolder &g, const char *name, u32 expr, u32 comp,
const Grey &grey);
@@ -76,7 +76,7 @@ void dumpHolderImpl(const NGHolder &h, unsigned int stageNumber,
// Variant that takes a region map as well.
void dumpHolderImpl(const NGHolder &h,
- const std::unordered_map<NFAVertex, u32> &region_map,
+ const std::unordered_map<NFAVertex, u32> &region_map,
unsigned int stageNumber, const char *stageName,
const Grey &grey);
@@ -90,10 +90,10 @@ static inline void dumpGraph(UNUSED const char *name, UNUSED const GraphT &g) {
// Stubs which call through to dump code if compiled in.
UNUSED static inline
-void dumpDotWrapper(UNUSED const NGHolder &g, UNUSED const ExpressionInfo &expr,
- UNUSED const char *name, UNUSED const Grey &grey) {
+void dumpDotWrapper(UNUSED const NGHolder &g, UNUSED const ExpressionInfo &expr,
+ UNUSED const char *name, UNUSED const Grey &grey) {
#ifdef DUMP_SUPPORT
- dumpDotWrapperImpl(g, expr, name, grey);
+ dumpDotWrapperImpl(g, expr, name, grey);
#endif
}
@@ -124,7 +124,7 @@ void dumpHolder(UNUSED const NGHolder &h, UNUSED unsigned int stageNumber,
UNUSED static inline
void dumpHolder(UNUSED const NGHolder &h,
- UNUSED const std::unordered_map<NFAVertex, u32> &region_map,
+ UNUSED const std::unordered_map<NFAVertex, u32> &region_map,
UNUSED unsigned int stageNumber, UNUSED const char *name,
UNUSED const Grey &grey) {
#ifdef DUMP_SUPPORT
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_edge_redundancy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_edge_redundancy.cpp
index 3a1940d912e..b8354bd42ae 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_edge_redundancy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_edge_redundancy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,7 +38,7 @@
#include "parser/position.h"
#include "util/compile_context.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include <set>
@@ -181,28 +181,28 @@ bool removeEdgeRedundancyNearCyclesFwd(NGHolder &g, bool ignore_starts) {
return dead_count;
}
-static
-bool checkReportsRev(const NGHolder &g, NFAVertex v,
- const set<NFAVertex> &happy) {
- if (g[v].reports.empty()) {
- return true;
- }
-
- assert(edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second);
-
- /* an edge to accept takes priority over eod only accept */
- NFAVertex accept = edge(v, g.accept, g).second ? g.accept : g.acceptEod;
-
- flat_set<ReportID> happy_reports;
- for (NFAVertex u : happy) {
- if (edge(u, accept, g).second) {
- insert(&happy_reports, g[u].reports);
- }
- }
-
- return is_subset_of(g[v].reports, happy_reports);
-}
-
+static
+bool checkReportsRev(const NGHolder &g, NFAVertex v,
+ const set<NFAVertex> &happy) {
+ if (g[v].reports.empty()) {
+ return true;
+ }
+
+ assert(edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second);
+
+ /* an edge to accept takes priority over eod only accept */
+ NFAVertex accept = edge(v, g.accept, g).second ? g.accept : g.acceptEod;
+
+ flat_set<ReportID> happy_reports;
+ for (NFAVertex u : happy) {
+ if (edge(u, accept, g).second) {
+ insert(&happy_reports, g[u].reports);
+ }
+ }
+
+ return is_subset_of(g[v].reports, happy_reports);
+}
+
/** \brief Redundant self-loop removal (reverse version).
*
* A self loop on a vertex v can be removed if:
@@ -255,8 +255,8 @@ bool removeEdgeRedundancyNearCyclesRev(NGHolder &g) {
happy.insert(u);
}
- if (!happy.empty() && checkVerticesRev(g, sad, happy)
- && checkReportsRev(g, v, happy)) {
+ if (!happy.empty() && checkVerticesRev(g, sad, happy)
+ && checkReportsRev(g, v, happy)) {
dead_count++;
remove_edge(v, v, g);
}
@@ -320,8 +320,8 @@ bool checkFwdCandidate(const NGHolder &g, NFAVertex fixed_src,
return false;
}
- DEBUG_PRINTF("edge (%zu, %zu) killed by edge (%zu, %zu)\n",
- g[w].index, g[v].index, g[fixed_src].index, g[v].index);
+ DEBUG_PRINTF("edge (%zu, %zu) killed by edge (%zu, %zu)\n",
+ g[w].index, g[v].index, g[fixed_src].index, g[v].index);
return true;
}
@@ -437,7 +437,7 @@ bool removeEdgeRedundancyFwd(NGHolder &g, bool ignore_starts) {
pred(g, u, &parents_u);
done.clear();
- if (out_degree(u, g) > 1) {
+ if (out_degree(u, g) > 1) {
checkLargeOutU(g, u, parents_u, possible_w, done, &dead);
} else {
checkSmallOutU(g, u, parents_u, done, &dead);
@@ -482,7 +482,7 @@ bool removeSiblingsOfStartDotStar(NGHolder &g) {
vector<NFAEdge> dead;
for (auto v : adjacent_vertices_range(g.startDs, g)) {
- DEBUG_PRINTF("checking %zu\n", g[v].index);
+ DEBUG_PRINTF("checking %zu\n", g[v].index);
if (is_special(v, g)) {
continue;
}
@@ -492,7 +492,7 @@ bool removeSiblingsOfStartDotStar(NGHolder &g) {
if (is_special(u, g)) {
continue;
}
- DEBUG_PRINTF("removing %zu->%zu\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("removing %zu->%zu\n", g[u].index, g[v].index);
dead.push_back(e);
}
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_equivalence.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_equivalence.cpp
index 7e2243ee6e7..fba8ce7b741 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_equivalence.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_equivalence.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,13 +37,13 @@
#include "ng_holder.h"
#include "ng_util.h"
#include "util/compile_context.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
-#include "util/make_unique.h"
-#include "util/unordered.h"
+#include "util/make_unique.h"
+#include "util/unordered.h"
#include <algorithm>
-#include <memory>
+#include <memory>
#include <set>
#include <stack>
#include <vector>
@@ -53,7 +53,7 @@ using namespace std;
namespace ue2 {
enum EquivalenceType {
- LEFT_EQUIVALENCE,
+ LEFT_EQUIVALENCE,
RIGHT_EQUIVALENCE,
};
@@ -66,23 +66,23 @@ struct VertexInfoPtrCmp {
bool operator()(const VertexInfo *a, const VertexInfo *b) const;
};
-using VertexInfoSet = flat_set<VertexInfo *, VertexInfoPtrCmp>;
-
+using VertexInfoSet = flat_set<VertexInfo *, VertexInfoPtrCmp>;
+
/** Precalculated (and maintained) information about a vertex. */
class VertexInfo {
public:
VertexInfo(NFAVertex v_in, const NGHolder &g)
- : v(v_in), vert_index(g[v].index), cr(g[v].char_reach),
+ : v(v_in), vert_index(g[v].index), cr(g[v].char_reach),
equivalence_class(~0), vertex_flags(g[v].assert_flags) {}
- VertexInfoSet pred; //!< predecessors of this vertex
- VertexInfoSet succ; //!< successors of this vertex
+ VertexInfoSet pred; //!< predecessors of this vertex
+ VertexInfoSet succ; //!< successors of this vertex
NFAVertex v;
- size_t vert_index;
+ size_t vert_index;
CharReach cr;
CharReach pred_cr;
CharReach succ_cr;
- flat_set<u32> edge_tops; /**< tops on edge from start */
+ flat_set<u32> edge_tops; /**< tops on edge from start */
unsigned equivalence_class;
unsigned vertex_flags;
};
@@ -106,31 +106,31 @@ public:
DepthMinMax d1;
DepthMinMax d2;
};
- ClassInfo(const NGHolder &g, const VertexInfo &vi, const ClassDepth &d_in,
+ ClassInfo(const NGHolder &g, const VertexInfo &vi, const ClassDepth &d_in,
EquivalenceType eq)
- : /* reports only matter for right-equiv */
- rs(eq == RIGHT_EQUIVALENCE ? g[vi.v].reports : flat_set<ReportID>()),
- vertex_flags(vi.vertex_flags), edge_tops(vi.edge_tops), cr(vi.cr),
- adjacent_cr(eq == LEFT_EQUIVALENCE ? vi.pred_cr : vi.succ_cr),
- /* treat non-special vertices the same */
- node_type(min(g[vi.v].index, size_t{N_SPECIALS})), depth(d_in) {}
-
- bool operator==(const ClassInfo &b) const {
- return node_type == b.node_type && depth.d1 == b.depth.d1 &&
- depth.d2 == b.depth.d2 && cr == b.cr &&
- adjacent_cr == b.adjacent_cr && edge_tops == b.edge_tops &&
- vertex_flags == b.vertex_flags && rs == b.rs;
- }
-
- size_t hash() const {
- return hash_all(rs, vertex_flags, cr, adjacent_cr, node_type, depth.d1,
- depth.d2);
+ : /* reports only matter for right-equiv */
+ rs(eq == RIGHT_EQUIVALENCE ? g[vi.v].reports : flat_set<ReportID>()),
+ vertex_flags(vi.vertex_flags), edge_tops(vi.edge_tops), cr(vi.cr),
+ adjacent_cr(eq == LEFT_EQUIVALENCE ? vi.pred_cr : vi.succ_cr),
+ /* treat non-special vertices the same */
+ node_type(min(g[vi.v].index, size_t{N_SPECIALS})), depth(d_in) {}
+
+ bool operator==(const ClassInfo &b) const {
+ return node_type == b.node_type && depth.d1 == b.depth.d1 &&
+ depth.d2 == b.depth.d2 && cr == b.cr &&
+ adjacent_cr == b.adjacent_cr && edge_tops == b.edge_tops &&
+ vertex_flags == b.vertex_flags && rs == b.rs;
+ }
+
+ size_t hash() const {
+ return hash_all(rs, vertex_flags, cr, adjacent_cr, node_type, depth.d1,
+ depth.d2);
}
private:
flat_set<ReportID> rs; /* for right equiv only */
unsigned vertex_flags;
- flat_set<u32> edge_tops;
+ flat_set<u32> edge_tops;
CharReach cr;
CharReach adjacent_cr;
unsigned node_type;
@@ -187,7 +187,7 @@ public:
return q.capacity();
}
private:
- unordered_set<unsigned> ids; //!< stores id's, for uniqueness
+ unordered_set<unsigned> ids; //!< stores id's, for uniqueness
vector<unsigned> q; //!< vector of id's that we use as FILO.
};
@@ -259,112 +259,112 @@ bool hasEdgeAsserts(NFAVertex v, const NGHolder &g) {
// populate VertexInfo table
static
-vector<unique_ptr<VertexInfo>> getVertexInfos(const NGHolder &g) {
- const size_t num_verts = num_vertices(g);
-
- vector<unique_ptr<VertexInfo>> infos;
- infos.reserve(num_verts * 2);
-
+vector<unique_ptr<VertexInfo>> getVertexInfos(const NGHolder &g) {
+ const size_t num_verts = num_vertices(g);
+
+ vector<unique_ptr<VertexInfo>> infos;
+ infos.reserve(num_verts * 2);
+
vector<VertexInfo *> vertex_map; // indexed by vertex_index property
- vertex_map.resize(num_verts);
+ vertex_map.resize(num_verts);
for (auto v : vertices_range(g)) {
infos.push_back(std::make_unique<VertexInfo>(v, g));
- vertex_map[g[v].index] = infos.back().get();
- }
+ vertex_map[g[v].index] = infos.back().get();
+ }
- // now, go through each vertex and populate its predecessor and successor
- // lists
- for (auto &vi : infos) {
- assert(vi);
- NFAVertex v = vi->v;
+ // now, go through each vertex and populate its predecessor and successor
+ // lists
+ for (auto &vi : infos) {
+ assert(vi);
+ NFAVertex v = vi->v;
// find predecessors
- for (const auto &e : in_edges_range(v, g)) {
+ for (const auto &e : in_edges_range(v, g)) {
NFAVertex u = source(e, g);
- VertexInfo *u_vi = vertex_map[g[u].index];
+ VertexInfo *u_vi = vertex_map[g[u].index];
- vi->pred_cr |= u_vi->cr;
- vi->pred.insert(u_vi);
+ vi->pred_cr |= u_vi->cr;
+ vi->pred.insert(u_vi);
// also set up edge tops
if (is_triggered(g) && u == g.start) {
- vi->edge_tops = g[e].tops;
+ vi->edge_tops = g[e].tops;
}
}
// find successors
- for (auto w : adjacent_vertices_range(v, g)) {
- VertexInfo *w_vi = vertex_map[g[w].index];
- vi->succ_cr |= w_vi->cr;
- vi->succ.insert(w_vi);
+ for (auto w : adjacent_vertices_range(v, g)) {
+ VertexInfo *w_vi = vertex_map[g[w].index];
+ vi->succ_cr |= w_vi->cr;
+ vi->succ.insert(w_vi);
}
- assert(!hasEdgeAsserts(vi->v, g));
+ assert(!hasEdgeAsserts(vi->v, g));
}
-
- return infos;
+
+ return infos;
}
// store equivalence class in VertexInfo for each vertex
static
-vector<VertexInfoSet> partitionGraph(vector<unique_ptr<VertexInfo>> &infos,
- WorkQueue &work_queue, const NGHolder &g,
- EquivalenceType eq) {
- const size_t num_verts = infos.size();
-
- vector<VertexInfoSet> classes;
- ue2_unordered_map<ClassInfo, unsigned> classinfomap;
-
- // assume we will have lots of classes, so we don't waste time resizing
- // these structures.
- classes.reserve(num_verts);
- classinfomap.reserve(num_verts);
-
+vector<VertexInfoSet> partitionGraph(vector<unique_ptr<VertexInfo>> &infos,
+ WorkQueue &work_queue, const NGHolder &g,
+ EquivalenceType eq) {
+ const size_t num_verts = infos.size();
+
+ vector<VertexInfoSet> classes;
+ ue2_unordered_map<ClassInfo, unsigned> classinfomap;
+
+ // assume we will have lots of classes, so we don't waste time resizing
+ // these structures.
+ classes.reserve(num_verts);
+ classinfomap.reserve(num_verts);
+
// get distances from start (or accept) for all vertices
// only one of them is used at a time, never both
vector<NFAVertexDepth> depths;
vector<NFAVertexRevDepth> rdepths;
if (eq == LEFT_EQUIVALENCE) {
- depths = calcDepths(g);
+ depths = calcDepths(g);
} else {
- rdepths = calcRevDepths(g);
+ rdepths = calcRevDepths(g);
}
// partition the graph based on CharReach
- for (auto &vi : infos) {
- assert(vi);
-
+ for (auto &vi : infos) {
+ assert(vi);
+
ClassInfo::ClassDepth depth;
if (eq == LEFT_EQUIVALENCE) {
- depth = depths[vi->vert_index];
+ depth = depths[vi->vert_index];
} else {
- depth = rdepths[vi->vert_index];
+ depth = rdepths[vi->vert_index];
}
- ClassInfo ci(g, *vi, depth, eq);
+ ClassInfo ci(g, *vi, depth, eq);
auto ii = classinfomap.find(ci);
if (ii == classinfomap.end()) {
- // vertex is in a new equivalence class by itself.
- unsigned eq_class = classes.size();
- vi->equivalence_class = eq_class;
- classes.push_back({vi.get()});
- classinfomap.emplace(move(ci), eq_class);
+ // vertex is in a new equivalence class by itself.
+ unsigned eq_class = classes.size();
+ vi->equivalence_class = eq_class;
+ classes.push_back({vi.get()});
+ classinfomap.emplace(move(ci), eq_class);
} else {
- // vertex is added to an existing class.
+ // vertex is added to an existing class.
unsigned eq_class = ii->second;
- vi->equivalence_class = eq_class;
- classes.at(eq_class).insert(vi.get());
+ vi->equivalence_class = eq_class;
+ classes.at(eq_class).insert(vi.get());
// we now know that this particular class has more than one
// vertex, so we add it to the work queue
work_queue.push(eq_class);
}
}
-
- DEBUG_PRINTF("partitioned, %zu equivalence classes\n", classes.size());
- return classes;
+
+ DEBUG_PRINTF("partitioned, %zu equivalence classes\n", classes.size());
+ return classes;
}
// generalized equivalence processing (left and right)
@@ -375,7 +375,7 @@ vector<VertexInfoSet> partitionGraph(vector<unique_ptr<VertexInfo>> &infos,
// equivalence, predecessors for right equivalence) classes get revalidated in
// case of a split.
static
-void equivalence(vector<VertexInfoSet> &classes, WorkQueue &work_queue,
+void equivalence(vector<VertexInfoSet> &classes, WorkQueue &work_queue,
EquivalenceType eq_type) {
// now, go through the work queue until it's empty
map<flat_set<unsigned>, VertexInfoSet> tentative_classmap;
@@ -388,7 +388,7 @@ void equivalence(vector<VertexInfoSet> &classes, WorkQueue &work_queue,
unsigned cur_class = work_queue.pop();
// get all vertices in current equivalence class
- VertexInfoSet &cur_class_vertices = classes.at(cur_class);
+ VertexInfoSet &cur_class_vertices = classes.at(cur_class);
if (cur_class_vertices.size() < 2) {
continue;
@@ -432,19 +432,19 @@ void equivalence(vector<VertexInfoSet> &classes, WorkQueue &work_queue,
// start from the second class
for (++tmi; tmi != tentative_classmap.end(); ++tmi) {
const VertexInfoSet &vertices_to_split = tmi->second;
- unsigned new_class = classes.size();
- VertexInfoSet new_class_vertices;
+ unsigned new_class = classes.size();
+ VertexInfoSet new_class_vertices;
for (VertexInfo *vi : vertices_to_split) {
vi->equivalence_class = new_class;
- // note: we cannot use the cur_class_vertices ref, as it is
- // invalidated by modifications to the classes vector.
- classes[cur_class].erase(vi);
+ // note: we cannot use the cur_class_vertices ref, as it is
+ // invalidated by modifications to the classes vector.
+ classes[cur_class].erase(vi);
new_class_vertices.insert(vi);
}
- classes.push_back(move(new_class_vertices));
-
- if (contains(tmi->first, cur_class)) {
+ classes.push_back(move(new_class_vertices));
+
+ if (contains(tmi->first, cur_class)) {
reval_queue.push(new_class);
}
}
@@ -485,9 +485,9 @@ bool require_separate_eod_vertex(const VertexInfoSet &vert_infos,
}
static
-void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
- unsigned eq_class, VertexInfoSet &cur_class_vertices,
- set<NFAVertex> *toRemove) {
+void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
+ unsigned eq_class, VertexInfoSet &cur_class_vertices,
+ set<NFAVertex> *toRemove) {
DEBUG_PRINTF("Replacing %zd vertices from equivalence class %u with a "
"single vertex.\n", cur_class_vertices.size(), eq_class);
@@ -517,7 +517,7 @@ void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
// store this vertex in our global vertex list
infos.push_back(std::make_unique<VertexInfo>(new_v, g));
- VertexInfo *new_vertex_info = infos.back().get();
+ VertexInfo *new_vertex_info = infos.back().get();
NFAVertex new_v_eod = NGHolder::null_vertex();
VertexInfo *new_vertex_info_eod = nullptr;
@@ -526,10 +526,10 @@ void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
new_v_eod = clone_vertex(g, old_v);
g[new_v_eod].reports.clear();
infos.push_back(std::make_unique<VertexInfo>(new_v_eod, g));
- new_vertex_info_eod = infos.back().get();
+ new_vertex_info_eod = infos.back().get();
}
- const auto &edgetops = (*cur_class_vertices.begin())->edge_tops;
+ const auto &edgetops = (*cur_class_vertices.begin())->edge_tops;
for (VertexInfo *old_vertex_info : cur_class_vertices) {
assert(old_vertex_info->equivalence_class == eq_class);
@@ -548,24 +548,24 @@ void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
pred_info->succ.erase(old_vertex_info);
// if edge doesn't exist, create it
- NFAEdge e = add_edge_if_not_present(pred_info->v, new_v, g);
+ NFAEdge e = add_edge_if_not_present(pred_info->v, new_v, g);
- // put edge tops, if applicable
- if (!edgetops.empty()) {
- assert(g[e].tops.empty() || g[e].tops == edgetops);
- g[e].tops = edgetops;
+ // put edge tops, if applicable
+ if (!edgetops.empty()) {
+ assert(g[e].tops.empty() || g[e].tops == edgetops);
+ g[e].tops = edgetops;
}
pred_info->succ.insert(new_vertex_info);
if (new_v_eod) {
NFAEdge ee = add_edge_if_not_present(pred_info->v, new_v_eod,
- g);
+ g);
- // put edge tops, if applicable
- if (!edgetops.empty()) {
- assert(g[e].tops.empty() || g[e].tops == edgetops);
- g[ee].tops = edgetops;
+ // put edge tops, if applicable
+ if (!edgetops.empty()) {
+ assert(g[e].tops.empty() || g[e].tops == edgetops);
+ g[ee].tops = edgetops;
}
pred_info->succ.insert(new_vertex_info_eod);
@@ -612,16 +612,16 @@ void mergeClass(vector<unique_ptr<VertexInfo>> &infos, NGHolder &g,
// vertex (or, in rare cases for left equiv, a pair if we cannot satisfy the
// report behaviour with a single vertex).
static
-bool mergeEquivalentClasses(vector<VertexInfoSet> &classes,
- vector<unique_ptr<VertexInfo>> &infos,
+bool mergeEquivalentClasses(vector<VertexInfoSet> &classes,
+ vector<unique_ptr<VertexInfo>> &infos,
NGHolder &g) {
bool merged = false;
set<NFAVertex> toRemove;
// go through all classes and merge classes with more than one vertex
- for (unsigned eq_class = 0; eq_class < classes.size(); eq_class++) {
+ for (unsigned eq_class = 0; eq_class < classes.size(); eq_class++) {
// get all vertices in current equivalence class
- VertexInfoSet &cur_class_vertices = classes[eq_class];
+ VertexInfoSet &cur_class_vertices = classes[eq_class];
// we don't care for single-vertex classes
if (cur_class_vertices.size() > 1) {
@@ -637,32 +637,32 @@ bool mergeEquivalentClasses(vector<VertexInfoSet> &classes,
return merged;
}
-static
-bool reduceGraphEquivalences(NGHolder &g, EquivalenceType eq_type) {
- // create a list of equivalence classes to check
- WorkQueue work_queue(num_vertices(g));
-
- // get information on every vertex in the graph
- // new vertices are allocated here, and stored in infos
- auto infos = getVertexInfos(g);
-
- // partition the graph
- auto classes = partitionGraph(infos, work_queue, g, eq_type);
-
- // do equivalence processing
- equivalence(classes, work_queue, eq_type);
-
- // replace equivalent classes with single vertices
- // new vertices are (possibly) allocated here, and stored in infos
- return mergeEquivalentClasses(classes, infos, g);
-}
-
+static
+bool reduceGraphEquivalences(NGHolder &g, EquivalenceType eq_type) {
+ // create a list of equivalence classes to check
+ WorkQueue work_queue(num_vertices(g));
+
+ // get information on every vertex in the graph
+ // new vertices are allocated here, and stored in infos
+ auto infos = getVertexInfos(g);
+
+ // partition the graph
+ auto classes = partitionGraph(infos, work_queue, g, eq_type);
+
+ // do equivalence processing
+ equivalence(classes, work_queue, eq_type);
+
+ // replace equivalent classes with single vertices
+ // new vertices are (possibly) allocated here, and stored in infos
+ return mergeEquivalentClasses(classes, infos, g);
+}
+
bool reduceGraphEquivalences(NGHolder &g, const CompileContext &cc) {
if (!cc.grey.equivalenceEnable) {
DEBUG_PRINTF("equivalence processing disabled in grey box\n");
return false;
}
- renumber_vertices(g);
+ renumber_vertices(g);
// Cheap check: if all the non-special vertices have in-degree one and
// out-degree one, there's no redundancy in this here graph and we can
@@ -674,8 +674,8 @@ bool reduceGraphEquivalences(NGHolder &g, const CompileContext &cc) {
// take note if we have merged any vertices
bool merge = false;
- merge |= reduceGraphEquivalences(g, LEFT_EQUIVALENCE);
- merge |= reduceGraphEquivalences(g, RIGHT_EQUIVALENCE);
+ merge |= reduceGraphEquivalences(g, LEFT_EQUIVALENCE);
+ merge |= reduceGraphEquivalences(g, RIGHT_EQUIVALENCE);
return merge;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_execute.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_execute.cpp
index 3834de5057c..9d90489471a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_execute.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_execute.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -58,7 +58,7 @@ namespace ue2 {
struct StateInfo {
StateInfo(NFAVertex v, const CharReach &cr) : vertex(v), reach(cr) {}
- StateInfo() : vertex(NGHolder::null_vertex()) {}
+ StateInfo() : vertex(NGHolder::null_vertex()) {}
NFAVertex vertex;
CharReach reach;
};
@@ -193,14 +193,14 @@ public:
info(info_in), input_g(input_g_in), states(states_in),
succs(vertex_count) {}
- void finish_vertex(NFAVertex input_v,
- const boost::reverse_graph<NGHolder, const NGHolder &> &) {
+ void finish_vertex(NFAVertex input_v,
+ const boost::reverse_graph<NGHolder, const NGHolder &> &) {
if (input_v == input_g.accept) {
return;
}
assert(input_v != input_g.acceptEod);
- DEBUG_PRINTF("finished p%zu\n", input_g[input_v].index);
+ DEBUG_PRINTF("finished p%zu\n", input_g[input_v].index);
/* finish vertex is called on vertex --> implies that all its parents
* (in the forward graph) are also finished. Our parents will have
@@ -235,7 +235,7 @@ public:
/* we need to push into all our (forward) children their successors
* from us. */
for (auto v : adjacent_vertices_range(input_v, input_g)) {
- DEBUG_PRINTF("pushing our states to pstate %zu\n",
+ DEBUG_PRINTF("pushing our states to pstate %zu\n",
input_g[v].index);
if (v == input_g.startDs) {
/* no need for intra start edges */
@@ -288,7 +288,7 @@ flat_set<NFAVertex> execute_graph(const NGHolder &running_g,
map<NFAVertex, boost::default_color_type> colours;
/* could just a topo order, but really it is time to pull a slightly bigger
* gun: DFS */
- boost::reverse_graph<NGHolder, const NGHolder &> revg(input_dag);
+ boost::reverse_graph<NGHolder, const NGHolder &> revg(input_dag);
map<NFAVertex, dynamic_bitset<> > dfs_states;
auto info = makeInfoTable(running_g);
@@ -307,7 +307,7 @@ flat_set<NFAVertex> execute_graph(const NGHolder &running_g,
#ifdef DEBUG
DEBUG_PRINTF(" output rstates:");
for (const auto &v : states) {
- printf(" %zu", running_g[v].index);
+ printf(" %zu", running_g[v].index);
}
printf("\n");
#endif
@@ -323,49 +323,49 @@ flat_set<NFAVertex> execute_graph(const NGHolder &running_g,
initial_states);
}
-static
-bool can_die_early(const NGHolder &g, const vector<StateInfo> &info,
- const dynamic_bitset<> &s,
- map<dynamic_bitset<>, u32> &visited, u32 age_limit) {
- if (contains(visited, s) && visited[s] >= age_limit) {
- /* we have already (or are in the process) of visiting here with a
- * looser limit. */
- return false;
- }
- visited[s] = age_limit;
-
- if (s.none()) {
- DEBUG_PRINTF("dead\n");
- return true;
- }
-
- if (age_limit == 0) {
- return false;
- }
-
- dynamic_bitset<> all_succ(s.size());
- step(g, info, s, &all_succ);
- all_succ.reset(NODE_START_DOTSTAR);
-
- for (u32 i = 0; i < N_CHARS; i++) {
- dynamic_bitset<> next = all_succ;
- filter_by_reach(info, &next, CharReach(i));
- if (can_die_early(g, info, next, visited, age_limit - 1)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool can_die_early(const NGHolder &g, u32 age_limit) {
- if (proper_out_degree(g.startDs, g)) {
- return false;
- }
- const vector<StateInfo> &info = makeInfoTable(g);
- map<dynamic_bitset<>, u32> visited;
- return can_die_early(g, info, makeStateBitset(g, {g.start}), visited,
- age_limit);
-}
-
+static
+bool can_die_early(const NGHolder &g, const vector<StateInfo> &info,
+ const dynamic_bitset<> &s,
+ map<dynamic_bitset<>, u32> &visited, u32 age_limit) {
+ if (contains(visited, s) && visited[s] >= age_limit) {
+ /* we have already (or are in the process) of visiting here with a
+ * looser limit. */
+ return false;
+ }
+ visited[s] = age_limit;
+
+ if (s.none()) {
+ DEBUG_PRINTF("dead\n");
+ return true;
+ }
+
+ if (age_limit == 0) {
+ return false;
+ }
+
+ dynamic_bitset<> all_succ(s.size());
+ step(g, info, s, &all_succ);
+ all_succ.reset(NODE_START_DOTSTAR);
+
+ for (u32 i = 0; i < N_CHARS; i++) {
+ dynamic_bitset<> next = all_succ;
+ filter_by_reach(info, &next, CharReach(i));
+ if (can_die_early(g, info, next, visited, age_limit - 1)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool can_die_early(const NGHolder &g, u32 age_limit) {
+ if (proper_out_degree(g.startDs, g)) {
+ return false;
+ }
+ const vector<StateInfo> &info = makeInfoTable(g);
+ map<dynamic_bitset<>, u32> visited;
+ return can_die_early(g, info, makeStateBitset(g, {g.start}), visited,
+ age_limit);
+}
+
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_execute.h b/contrib/libs/hyperscan/src/nfagraph/ng_execute.h
index 0dea4768c40..32f5520d331 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_execute.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_execute.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
#define NG_EXECUTE_H
#include "ng_holder.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <vector>
@@ -64,9 +64,9 @@ flat_set<NFAVertex> execute_graph(const NGHolder &g, const NGHolder &input_dag,
const flat_set<NFAVertex> &input_start_states,
const flat_set<NFAVertex> &initial);
-/* returns true if it is possible for the nfa to die within age_limit bytes */
-bool can_die_early(const NGHolder &g, u32 age_limit);
-
+/* returns true if it is possible for the nfa to die within age_limit bytes */
+bool can_die_early(const NGHolder &g, u32 age_limit);
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.cpp
index 85f5933d217..f8abbd04a21 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,8 +27,8 @@
*/
/** \file
- * \brief Code for discovering properties of an NFA graph used by
- * hs_expression_info().
+ * \brief Code for discovering properties of an NFA graph used by
+ * hs_expression_info().
*/
#include "ng_expr_info.h"
@@ -37,14 +37,14 @@
#include "ng_asserts.h"
#include "ng_depth.h"
#include "ng_edge_redundancy.h"
-#include "ng_extparam.h"
-#include "ng_fuzzy.h"
+#include "ng_extparam.h"
+#include "ng_fuzzy.h"
#include "ng_holder.h"
-#include "ng_prune.h"
+#include "ng_prune.h"
#include "ng_reports.h"
#include "ng_util.h"
#include "ue2common.h"
-#include "compiler/expression_info.h"
+#include "compiler/expression_info.h"
#include "parser/position.h" // for POS flags
#include "util/boundary_reports.h"
#include "util/compile_context.h"
@@ -62,76 +62,76 @@ namespace ue2 {
/* get rid of leading \b and multiline ^ vertices */
static
-void removeLeadingVirtualVerticesFromRoot(NGHolder &g, NFAVertex root) {
+void removeLeadingVirtualVerticesFromRoot(NGHolder &g, NFAVertex root) {
vector<NFAVertex> victims;
- for (auto v : adjacent_vertices_range(root, g)) {
- if (g[v].assert_flags & POS_FLAG_VIRTUAL_START) {
+ for (auto v : adjacent_vertices_range(root, g)) {
+ if (g[v].assert_flags & POS_FLAG_VIRTUAL_START) {
DEBUG_PRINTF("(?m)^ vertex or leading \\[bB] vertex\n");
victims.push_back(v);
}
}
for (auto u : victims) {
- for (auto v : adjacent_vertices_range(u, g)) {
- add_edge_if_not_present(root, v, g);
+ for (auto v : adjacent_vertices_range(u, g)) {
+ add_edge_if_not_present(root, v, g);
}
}
- remove_vertices(victims, g);
+ remove_vertices(victims, g);
}
static
-void checkVertex(const ReportManager &rm, const NGHolder &g, NFAVertex v,
+void checkVertex(const ReportManager &rm, const NGHolder &g, NFAVertex v,
const vector<DepthMinMax> &depths, DepthMinMax &info) {
- if (is_any_accept(v, g)) {
+ if (is_any_accept(v, g)) {
return;
}
- if (is_any_start(v, g)) {
- info.min = depth(0);
+ if (is_any_start(v, g)) {
+ info.min = depth(0);
info.max = max(info.max, depth(0));
return;
}
- u32 idx = g[v].index;
+ u32 idx = g[v].index;
assert(idx < depths.size());
const DepthMinMax &d = depths.at(idx);
- for (ReportID report_id : g[v].reports) {
- const Report &report = rm.getReport(report_id);
- assert(report.type == EXTERNAL_CALLBACK);
-
- DepthMinMax rd = d;
-
- // Compute graph width to this report, taking any offset adjustment
- // into account.
- rd.min += report.offsetAdjust;
- rd.max += report.offsetAdjust;
-
- // A min_length param is a lower bound for match width.
- if (report.minLength && report.minLength <= depth::max_value()) {
- depth min_len((u32)report.minLength);
- rd.min = max(rd.min, min_len);
- rd.max = max(rd.max, min_len);
- }
-
- // A max_offset param is an upper bound for match width.
- if (report.maxOffset && report.maxOffset <= depth::max_value()) {
- depth max_offset((u32)report.maxOffset);
- rd.min = min(rd.min, max_offset);
- rd.max = min(rd.max, max_offset);
- }
-
- DEBUG_PRINTF("vertex %zu report %u: %s\n", g[v].index, report_id,
- rd.str().c_str());
-
- info = unionDepthMinMax(info, rd);
+ for (ReportID report_id : g[v].reports) {
+ const Report &report = rm.getReport(report_id);
+ assert(report.type == EXTERNAL_CALLBACK);
+
+ DepthMinMax rd = d;
+
+ // Compute graph width to this report, taking any offset adjustment
+ // into account.
+ rd.min += report.offsetAdjust;
+ rd.max += report.offsetAdjust;
+
+ // A min_length param is a lower bound for match width.
+ if (report.minLength && report.minLength <= depth::max_value()) {
+ depth min_len((u32)report.minLength);
+ rd.min = max(rd.min, min_len);
+ rd.max = max(rd.max, min_len);
+ }
+
+ // A max_offset param is an upper bound for match width.
+ if (report.maxOffset && report.maxOffset <= depth::max_value()) {
+ depth max_offset((u32)report.maxOffset);
+ rd.min = min(rd.min, max_offset);
+ rd.max = min(rd.max, max_offset);
+ }
+
+ DEBUG_PRINTF("vertex %zu report %u: %s\n", g[v].index, report_id,
+ rd.str().c_str());
+
+ info = unionDepthMinMax(info, rd);
}
}
static
-bool hasOffsetAdjust(const ReportManager &rm, const NGHolder &g) {
- for (const auto &report_id : all_reports(g)) {
+bool hasOffsetAdjust(const ReportManager &rm, const NGHolder &g) {
+ for (const auto &report_id : all_reports(g)) {
if (rm.getReport(report_id).offsetAdjust) {
return true;
}
@@ -139,64 +139,64 @@ bool hasOffsetAdjust(const ReportManager &rm, const NGHolder &g) {
return false;
}
-void fillExpressionInfo(ReportManager &rm, const CompileContext &cc,
- NGHolder &g, ExpressionInfo &expr,
- hs_expr_info *info) {
+void fillExpressionInfo(ReportManager &rm, const CompileContext &cc,
+ NGHolder &g, ExpressionInfo &expr,
+ hs_expr_info *info) {
assert(info);
- // remove reports that aren't on vertices connected to accept.
- clearReports(g);
-
- assert(allMatchStatesHaveReports(g));
-
- /*
- * Note: the following set of analysis passes / transformations should
- * match those in NG::addGraph().
- */
-
+ // remove reports that aren't on vertices connected to accept.
+ clearReports(g);
+
+ assert(allMatchStatesHaveReports(g));
+
+ /*
+ * Note: the following set of analysis passes / transformations should
+ * match those in NG::addGraph().
+ */
+
/* ensure utf8 starts at cp boundary */
- ensureCodePointStart(rm, g, expr);
-
- if (can_never_match(g)) {
- throw CompileError(expr.index, "Pattern can never match.");
- }
-
- bool hamming = expr.hamm_distance > 0;
- u32 e_dist = hamming ? expr.hamm_distance : expr.edit_distance;
-
- // validate graph's suitability for fuzzing
- validate_fuzzy_compile(g, e_dist, hamming, expr.utf8, cc.grey);
-
- resolveAsserts(rm, g, expr);
- assert(allMatchStatesHaveReports(g));
-
- // fuzz graph - this must happen before any transformations are made
- make_fuzzy(g, e_dist, hamming, cc.grey);
-
- pruneUseless(g);
- pruneEmptyVertices(g);
-
- if (can_never_match(g)) {
- throw CompileError(expr.index, "Pattern can never match.");
- }
-
- optimiseVirtualStarts(g);
-
- propagateExtendedParams(g, expr, rm);
-
- removeLeadingVirtualVerticesFromRoot(g, g.start);
- removeLeadingVirtualVerticesFromRoot(g, g.startDs);
-
- auto depths = calcDepthsFrom(g, g.start);
-
+ ensureCodePointStart(rm, g, expr);
+
+ if (can_never_match(g)) {
+ throw CompileError(expr.index, "Pattern can never match.");
+ }
+
+ bool hamming = expr.hamm_distance > 0;
+ u32 e_dist = hamming ? expr.hamm_distance : expr.edit_distance;
+
+ // validate graph's suitability for fuzzing
+ validate_fuzzy_compile(g, e_dist, hamming, expr.utf8, cc.grey);
+
+ resolveAsserts(rm, g, expr);
+ assert(allMatchStatesHaveReports(g));
+
+ // fuzz graph - this must happen before any transformations are made
+ make_fuzzy(g, e_dist, hamming, cc.grey);
+
+ pruneUseless(g);
+ pruneEmptyVertices(g);
+
+ if (can_never_match(g)) {
+ throw CompileError(expr.index, "Pattern can never match.");
+ }
+
+ optimiseVirtualStarts(g);
+
+ propagateExtendedParams(g, expr, rm);
+
+ removeLeadingVirtualVerticesFromRoot(g, g.start);
+ removeLeadingVirtualVerticesFromRoot(g, g.startDs);
+
+ auto depths = calcDepthsFrom(g, g.start);
+
DepthMinMax d;
- for (auto u : inv_adjacent_vertices_range(g.accept, g)) {
- checkVertex(rm, g, u, depths, d);
+ for (auto u : inv_adjacent_vertices_range(g.accept, g)) {
+ checkVertex(rm, g, u, depths, d);
}
- for (auto u : inv_adjacent_vertices_range(g.acceptEod, g)) {
- checkVertex(rm, g, u, depths, d);
+ for (auto u : inv_adjacent_vertices_range(g.acceptEod, g)) {
+ checkVertex(rm, g, u, depths, d);
}
if (d.max.is_finite()) {
@@ -210,9 +210,9 @@ void fillExpressionInfo(ReportManager &rm, const CompileContext &cc,
info->min_width = UINT_MAX;
}
- info->unordered_matches = hasOffsetAdjust(rm, g);
- info->matches_at_eod = can_match_at_eod(g);
- info->matches_only_at_eod = can_only_match_at_eod(g);
+ info->unordered_matches = hasOffsetAdjust(rm, g);
+ info->matches_at_eod = can_match_at_eod(g);
+ info->matches_only_at_eod = can_only_match_at_eod(g);
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.h b/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.h
index aedd05069ab..f9bd6809392 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_expr_info.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,7 +27,7 @@
*/
/** \file
- * \brief Code for discovering properties of an expression used by
+ * \brief Code for discovering properties of an expression used by
* hs_expression_info.
*/
@@ -38,13 +38,13 @@ struct hs_expr_info;
namespace ue2 {
-class ExpressionInfo;
-class NGHolder;
+class ExpressionInfo;
+class NGHolder;
class ReportManager;
-struct CompileContext;
+struct CompileContext;
-void fillExpressionInfo(ReportManager &rm, const CompileContext &cc,
- NGHolder &g, ExpressionInfo &expr, hs_expr_info *info);
+void fillExpressionInfo(ReportManager &rm, const CompileContext &cc,
+ NGHolder &g, ExpressionInfo &expr, hs_expr_info *info);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_extparam.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_extparam.cpp
index 4be5b73f779..6eb23113f38 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_extparam.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_extparam.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,22 +26,22 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Propagate extended parameters to vertex reports and reduce graph if
* possible.
*
* This code handles the propagation of the extension parameters specified by
- * the user with the \ref hs_expr_ext structure into the reports on the graph's
+ * the user with the \ref hs_expr_ext structure into the reports on the graph's
* vertices.
*
* There are also some analyses that prune edges that cannot contribute to a
* match given these constraints, or transform the graph in order to make a
* constraint implicit.
*/
-
-#include "ng_extparam.h"
-
+
+#include "ng_extparam.h"
+
#include "ng.h"
#include "ng_depth.h"
#include "ng_dump.h"
@@ -51,7 +51,7 @@
#include "ng_width.h"
#include "ng_util.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "parser/position.h"
#include "util/compile_context.h"
#include "util/compile_error.h"
@@ -69,28 +69,28 @@ namespace ue2 {
static const u32 MAX_MAXOFFSET_TO_ANCHOR = 2000;
static const u32 MAX_MINLENGTH_TO_CONVERT = 2000;
-/** True if all the given reports have the same extparam bounds. */
-template<typename Container>
-bool hasSameBounds(const Container &reports, const ReportManager &rm) {
- assert(!reports.empty());
-
- const auto &first = rm.getReport(*reports.begin());
- for (auto id : reports) {
- const auto &report = rm.getReport(id);
- if (report.minOffset != first.minOffset ||
- report.maxOffset != first.maxOffset ||
- report.minLength != first.minLength) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * \brief Find the (min, max) offset adjustment for the reports on a given
- * vertex.
- */
+/** True if all the given reports have the same extparam bounds. */
+template<typename Container>
+bool hasSameBounds(const Container &reports, const ReportManager &rm) {
+ assert(!reports.empty());
+
+ const auto &first = rm.getReport(*reports.begin());
+ for (auto id : reports) {
+ const auto &report = rm.getReport(id);
+ if (report.minOffset != first.minOffset ||
+ report.maxOffset != first.maxOffset ||
+ report.minLength != first.minLength) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * \brief Find the (min, max) offset adjustment for the reports on a given
+ * vertex.
+ */
static
pair<s32,s32> getMinMaxOffsetAdjust(const ReportManager &rm,
const NGHolder &g, NFAVertex v) {
@@ -151,76 +151,76 @@ DepthMinMax findMatchLengths(const ReportManager &rm, const NGHolder &g) {
return match_depths;
}
-template<typename Function>
-void replaceReports(NGHolder &g, NFAVertex accept, flat_set<NFAVertex> &seen,
- Function func) {
+template<typename Function>
+void replaceReports(NGHolder &g, NFAVertex accept, flat_set<NFAVertex> &seen,
+ Function func) {
for (auto v : inv_adjacent_vertices_range(accept, g)) {
if (v == g.accept) {
- // Don't operate on accept: the accept->acceptEod edge is stylised.
+ // Don't operate on accept: the accept->acceptEod edge is stylised.
assert(accept == g.acceptEod);
- assert(g[v].reports.empty());
+ assert(g[v].reports.empty());
continue;
}
- if (!seen.insert(v).second) {
- continue; // We have already processed v.
+ if (!seen.insert(v).second) {
+ continue; // We have already processed v.
}
auto &reports = g[v].reports;
- if (reports.empty()) {
- continue;
- }
- decltype(g[v].reports) new_reports;
- for (auto id : g[v].reports) {
- new_reports.insert(func(v, id));
- }
- reports = std::move(new_reports);
- }
-}
-
-/**
- * Generic function for replacing all the reports in the graph.
- *
- * Pass this a function that takes a vertex and a ReportID returns another
- * ReportID (or the same one) to replace it with.
- */
-template<typename Function>
-void replaceReports(NGHolder &g, Function func) {
- flat_set<NFAVertex> seen;
- replaceReports(g, g.accept, seen, func);
- replaceReports(g, g.acceptEod, seen, func);
-}
-
-/** \brief Replace the graph's reports with new reports that specify bounds. */
-static
-void updateReportBounds(ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
- DEBUG_PRINTF("updating report bounds\n");
- replaceReports(g, [&](NFAVertex, ReportID id) {
- Report report = rm.getReport(id); // make a copy
- assert(!report.hasBounds());
-
- // Note that we need to cope with offset adjustment here.
-
- report.minOffset = expr.min_offset - report.offsetAdjust;
- if (expr.max_offset == MAX_OFFSET) {
- report.maxOffset = MAX_OFFSET;
- } else {
- report.maxOffset = expr.max_offset - report.offsetAdjust;
- }
- assert(report.maxOffset >= report.minOffset);
-
- report.minLength = expr.min_length;
- if (expr.min_length && !expr.som) {
- report.quashSom = true;
+ if (reports.empty()) {
+ continue;
+ }
+ decltype(g[v].reports) new_reports;
+ for (auto id : g[v].reports) {
+ new_reports.insert(func(v, id));
+ }
+ reports = std::move(new_reports);
+ }
+}
+
+/**
+ * Generic function for replacing all the reports in the graph.
+ *
+ * Pass this a function that takes a vertex and a ReportID returns another
+ * ReportID (or the same one) to replace it with.
+ */
+template<typename Function>
+void replaceReports(NGHolder &g, Function func) {
+ flat_set<NFAVertex> seen;
+ replaceReports(g, g.accept, seen, func);
+ replaceReports(g, g.acceptEod, seen, func);
+}
+
+/** \brief Replace the graph's reports with new reports that specify bounds. */
+static
+void updateReportBounds(ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
+ DEBUG_PRINTF("updating report bounds\n");
+ replaceReports(g, [&](NFAVertex, ReportID id) {
+ Report report = rm.getReport(id); // make a copy
+ assert(!report.hasBounds());
+
+ // Note that we need to cope with offset adjustment here.
+
+ report.minOffset = expr.min_offset - report.offsetAdjust;
+ if (expr.max_offset == MAX_OFFSET) {
+ report.maxOffset = MAX_OFFSET;
+ } else {
+ report.maxOffset = expr.max_offset - report.offsetAdjust;
+ }
+ assert(report.maxOffset >= report.minOffset);
+
+ report.minLength = expr.min_length;
+ if (expr.min_length && !expr.som) {
+ report.quashSom = true;
}
- DEBUG_PRINTF("id %u -> min_offset=%llu, max_offset=%llu, "
- "min_length=%llu\n", id, report.minOffset,
- report.maxOffset, report.minLength);
-
- return rm.getInternalId(report);
- });
+ DEBUG_PRINTF("id %u -> min_offset=%llu, max_offset=%llu, "
+ "min_length=%llu\n", id, report.minOffset,
+ report.maxOffset, report.minLength);
+
+ return rm.getInternalId(report);
+ });
}
static
@@ -233,93 +233,93 @@ bool hasVirtualStarts(const NGHolder &g) {
return false;
}
-/** Set the min_length param for all reports to zero. */
-static
-void clearMinLengthParam(NGHolder &g, ReportManager &rm) {
- DEBUG_PRINTF("clearing min length\n");
- replaceReports(g, [&rm](NFAVertex, ReportID id) {
- const auto &report = rm.getReport(id);
- if (report.minLength) {
- Report new_report = report;
- new_report.minLength = 0;
- return rm.getInternalId(new_report);
- }
- return id;
- });
-}
-
-/**
- * Set the min_offset param to zero and the max_offset param to MAX_OFFSET for
- * all reports.
- */
-static
-void clearOffsetParams(NGHolder &g, ReportManager &rm) {
- DEBUG_PRINTF("clearing min and max offset\n");
- replaceReports(g, [&rm](NFAVertex, ReportID id) {
- const auto &report = rm.getReport(id);
- if (report.minLength) {
- Report new_report = report;
- new_report.minOffset = 0;
- new_report.maxOffset = MAX_OFFSET;
- return rm.getInternalId(new_report);
- }
- return id;
- });
-}
-
-/**
- * If the pattern is unanchored, has a max_offset and has not asked for SOM, we
- * can use that knowledge to anchor it which will limit its lifespan. Note that
- * we can't use this transformation if there's a min_length, as it's currently
- * handled using "sly SOM".
+/** Set the min_length param for all reports to zero. */
+static
+void clearMinLengthParam(NGHolder &g, ReportManager &rm) {
+ DEBUG_PRINTF("clearing min length\n");
+ replaceReports(g, [&rm](NFAVertex, ReportID id) {
+ const auto &report = rm.getReport(id);
+ if (report.minLength) {
+ Report new_report = report;
+ new_report.minLength = 0;
+ return rm.getInternalId(new_report);
+ }
+ return id;
+ });
+}
+
+/**
+ * Set the min_offset param to zero and the max_offset param to MAX_OFFSET for
+ * all reports.
+ */
+static
+void clearOffsetParams(NGHolder &g, ReportManager &rm) {
+ DEBUG_PRINTF("clearing min and max offset\n");
+ replaceReports(g, [&rm](NFAVertex, ReportID id) {
+ const auto &report = rm.getReport(id);
+ if (report.minLength) {
+ Report new_report = report;
+ new_report.minOffset = 0;
+ new_report.maxOffset = MAX_OFFSET;
+ return rm.getInternalId(new_report);
+ }
+ return id;
+ });
+}
+
+/**
+ * If the pattern is unanchored, has a max_offset and has not asked for SOM, we
+ * can use that knowledge to anchor it which will limit its lifespan. Note that
+ * we can't use this transformation if there's a min_length, as it's currently
+ * handled using "sly SOM".
*
* Note that it is possible to handle graphs that have a combination of
* anchored and unanchored paths, but it's too tricky for the moment.
*/
static
-bool anchorPatternWithBoundedRepeat(NGHolder &g, ReportManager &rm) {
- if (!isFloating(g)) {
- return false;
- }
-
- const auto &reports = all_reports(g);
- if (reports.empty()) {
- return false;
- }
-
- if (any_of_in(reports, [&](ReportID id) {
- const auto &report = rm.getReport(id);
- return report.maxOffset == MAX_OFFSET || report.minLength ||
- report.offsetAdjust;
- })) {
- return false;
- }
-
- if (!hasSameBounds(reports, rm)) {
- DEBUG_PRINTF("mixed report bounds\n");
- return false;
- }
-
- const depth minWidth = findMinWidth(g);
- const depth maxWidth = findMaxWidth(g);
-
+bool anchorPatternWithBoundedRepeat(NGHolder &g, ReportManager &rm) {
+ if (!isFloating(g)) {
+ return false;
+ }
+
+ const auto &reports = all_reports(g);
+ if (reports.empty()) {
+ return false;
+ }
+
+ if (any_of_in(reports, [&](ReportID id) {
+ const auto &report = rm.getReport(id);
+ return report.maxOffset == MAX_OFFSET || report.minLength ||
+ report.offsetAdjust;
+ })) {
+ return false;
+ }
+
+ if (!hasSameBounds(reports, rm)) {
+ DEBUG_PRINTF("mixed report bounds\n");
+ return false;
+ }
+
+ const depth minWidth = findMinWidth(g);
+ const depth maxWidth = findMaxWidth(g);
+
assert(minWidth <= maxWidth);
assert(maxWidth.is_reachable());
- const auto &first_report = rm.getReport(*reports.begin());
- const auto min_offset = first_report.minOffset;
- const auto max_offset = first_report.maxOffset;
- assert(max_offset < MAX_OFFSET);
-
+ const auto &first_report = rm.getReport(*reports.begin());
+ const auto min_offset = first_report.minOffset;
+ const auto max_offset = first_report.maxOffset;
+ assert(max_offset < MAX_OFFSET);
+
DEBUG_PRINTF("widths=[%s,%s], min/max offsets=[%llu,%llu]\n",
- minWidth.str().c_str(), maxWidth.str().c_str(),
- min_offset, max_offset);
+ minWidth.str().c_str(), maxWidth.str().c_str(),
+ min_offset, max_offset);
- if (max_offset > MAX_MAXOFFSET_TO_ANCHOR) {
+ if (max_offset > MAX_MAXOFFSET_TO_ANCHOR) {
return false;
}
- if (max_offset < minWidth) {
+ if (max_offset < minWidth) {
assert(0);
return false;
}
@@ -340,10 +340,10 @@ bool anchorPatternWithBoundedRepeat(NGHolder &g, ReportManager &rm) {
u32 min_bound, max_bound;
if (maxWidth.is_infinite()) {
min_bound = 0;
- max_bound = max_offset - minWidth;
+ max_bound = max_offset - minWidth;
} else {
- min_bound = min_offset > maxWidth ? min_offset - maxWidth : 0;
- max_bound = max_offset - minWidth;
+ min_bound = min_offset > maxWidth ? min_offset - maxWidth : 0;
+ max_bound = max_offset - minWidth;
}
DEBUG_PRINTF("prepending ^.{%u,%u}\n", min_bound, max_bound);
@@ -393,44 +393,44 @@ bool anchorPatternWithBoundedRepeat(NGHolder &g, ReportManager &rm) {
add_edge(u, v, g);
}
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
+
+ if (minWidth == maxWidth) {
+ // For a fixed width pattern, we can retire the offsets as
+ // they are implicit in the graph now.
+ clearOffsetParams(g, rm);
+ }
- if (minWidth == maxWidth) {
- // For a fixed width pattern, we can retire the offsets as
- // they are implicit in the graph now.
- clearOffsetParams(g, rm);
- }
-
- clearReports(g);
+ clearReports(g);
return true;
}
static
NFAVertex findSingleCyclic(const NGHolder &g) {
- NFAVertex v = NGHolder::null_vertex();
+ NFAVertex v = NGHolder::null_vertex();
for (const auto &e : edges_range(g)) {
if (source(e, g) == target(e, g)) {
if (source(e, g) == g.startDs) {
continue;
}
- if (v != NGHolder::null_vertex()) {
+ if (v != NGHolder::null_vertex()) {
// More than one cyclic vertex.
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
v = source(e, g);
}
}
- if (v != NGHolder::null_vertex()) {
- DEBUG_PRINTF("cyclic is %zu\n", g[v].index);
+ if (v != NGHolder::null_vertex()) {
+ DEBUG_PRINTF("cyclic is %zu\n", g[v].index);
assert(!is_special(v, g));
}
return v;
}
static
-bool hasOffsetAdjust(const ReportManager &rm, NGHolder &g,
+bool hasOffsetAdjust(const ReportManager &rm, NGHolder &g,
int *adjust) {
const auto &reports = all_reports(g);
if (reports.empty()) {
@@ -451,30 +451,30 @@ bool hasOffsetAdjust(const ReportManager &rm, NGHolder &g,
return true;
}
-/**
- * If the pattern has a min_length and is of "ratchet" form with one unbounded
+/**
+ * If the pattern has a min_length and is of "ratchet" form with one unbounded
* repeat, that repeat can become a bounded repeat.
*
* /foo.*bar/{min_length=100} --> /foo.{94,}bar/
*/
static
-bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
- const auto &reports = all_reports(g);
+bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
+ const auto &reports = all_reports(g);
+
+ if (reports.empty()) {
+ return false;
+ }
- if (reports.empty()) {
+ if (!hasSameBounds(reports, rm)) {
+ DEBUG_PRINTF("mixed report bounds\n");
+ return false;
+ }
+
+ const auto &min_length = rm.getReport(*reports.begin()).minLength;
+ if (!min_length || min_length > MAX_MINLENGTH_TO_CONVERT) {
return false;
}
- if (!hasSameBounds(reports, rm)) {
- DEBUG_PRINTF("mixed report bounds\n");
- return false;
- }
-
- const auto &min_length = rm.getReport(*reports.begin()).minLength;
- if (!min_length || min_length > MAX_MINLENGTH_TO_CONVERT) {
- return false;
- }
-
// If the pattern has virtual starts, we probably don't want to touch it.
if (hasVirtualStarts(g)) {
DEBUG_PRINTF("virtual starts, bailing\n");
@@ -484,11 +484,11 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
// The graph must contain a single cyclic vertex (other than startDs), and
// that vertex can have one pred and one successor.
NFAVertex cyclic = findSingleCyclic(g);
- if (cyclic == NGHolder::null_vertex()) {
+ if (cyclic == NGHolder::null_vertex()) {
return false;
}
- NGHolder::adjacency_iterator ai, ae;
+ NGHolder::adjacency_iterator ai, ae;
tie(ai, ae) = adjacent_vertices(g.start, g);
if (*ai == g.startDs) {
++ai;
@@ -504,9 +504,9 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
// Walk from the start vertex to the cyclic state and ensure we have a
// chain of vertices.
while (v != cyclic) {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
width++;
- auto succ = succs(v, g);
+ auto succ = succs(v, g);
if (contains(succ, cyclic)) {
if (succ.size() == 1) {
v = cyclic;
@@ -534,7 +534,7 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
// Check the cyclic state is A-OK.
v = getSoleDestVertex(g, cyclic);
- if (v == NGHolder::null_vertex()) {
+ if (v == NGHolder::null_vertex()) {
DEBUG_PRINTF("cyclic has more than one successor\n");
return false;
}
@@ -542,9 +542,9 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
// Walk from the cyclic state to an accept and ensure we have a chain of
// vertices.
while (!is_any_accept(v, g)) {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
width++;
- auto succ = succs(v, g);
+ auto succ = succs(v, g);
if (succ.size() != 1) {
DEBUG_PRINTF("bad form\n");
return false;
@@ -559,20 +559,20 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
DEBUG_PRINTF("adjusting width by %d\n", offsetAdjust);
width += offsetAdjust;
- DEBUG_PRINTF("width=%u, vertex %zu is cyclic\n", width,
+ DEBUG_PRINTF("width=%u, vertex %zu is cyclic\n", width,
g[cyclic].index);
- if (width >= min_length) {
+ if (width >= min_length) {
DEBUG_PRINTF("min_length=%llu is guaranteed, as width=%u\n",
- min_length, width);
- clearMinLengthParam(g, rm);
+ min_length, width);
+ clearMinLengthParam(g, rm);
return true;
}
vector<NFAVertex> preds;
vector<NFAEdge> dead;
for (auto u : inv_adjacent_vertices_range(cyclic, g)) {
- DEBUG_PRINTF("pred %zu\n", g[u].index);
+ DEBUG_PRINTF("pred %zu\n", g[u].index);
if (u == cyclic) {
continue;
}
@@ -593,7 +593,7 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
const CharReach &cr = g[cyclic].char_reach;
- for (u32 i = 0; i < min_length - width - 1; ++i) {
+ for (u32 i = 0; i < min_length - width - 1; ++i) {
v = add_vertex(g);
g[v].char_reach = cr;
@@ -608,22 +608,22 @@ bool transformMinLengthToRepeat(NGHolder &g, ReportManager &rm) {
add_edge(u, cyclic, g);
}
- renumber_vertices(g);
- renumber_edges(g);
- clearMinLengthParam(g, rm);
+ renumber_vertices(g);
+ renumber_edges(g);
+ clearMinLengthParam(g, rm);
clearReports(g);
return true;
}
static
-bool hasExtParams(const ExpressionInfo &expr) {
- if (expr.min_length != 0) {
+bool hasExtParams(const ExpressionInfo &expr) {
+ if (expr.min_length != 0) {
return true;
}
- if (expr.min_offset != 0) {
+ if (expr.min_offset != 0) {
return true;
}
- if (expr.max_offset != MAX_OFFSET) {
+ if (expr.max_offset != MAX_OFFSET) {
return true;
}
return false;
@@ -650,13 +650,13 @@ const depth& minDistToAccept(const NFAVertexBidiDepth &d) {
}
static
-bool isEdgePrunable(const NGHolder &g, const Report &report,
+bool isEdgePrunable(const NGHolder &g, const Report &report,
const vector<NFAVertexBidiDepth> &depths,
const NFAEdge &e) {
const NFAVertex u = source(e, g);
const NFAVertex v = target(e, g);
- DEBUG_PRINTF("edge (%zu,%zu)\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("edge (%zu,%zu)\n", g[u].index, g[v].index);
// Leave our special-to-special edges alone.
if (is_special(u, g) && is_special(v, g)) {
@@ -679,29 +679,29 @@ bool isEdgePrunable(const NGHolder &g, const Report &report,
const NFAVertexBidiDepth &du = depths.at(u_idx);
const NFAVertexBidiDepth &dv = depths.at(v_idx);
- if (report.minOffset) {
- depth max_offset = maxDistFromStartOfData(du) + maxDistToAccept(dv);
- if (max_offset.is_finite() && max_offset < report.minOffset) {
+ if (report.minOffset) {
+ depth max_offset = maxDistFromStartOfData(du) + maxDistToAccept(dv);
+ if (max_offset.is_finite() && max_offset < report.minOffset) {
DEBUG_PRINTF("max_offset=%s too small\n", max_offset.str().c_str());
return true;
}
}
- if (report.maxOffset != MAX_OFFSET) {
+ if (report.maxOffset != MAX_OFFSET) {
depth min_offset = minDistFromStart(du) + minDistToAccept(dv);
assert(min_offset.is_finite());
- if (min_offset > report.maxOffset) {
+ if (min_offset > report.maxOffset) {
DEBUG_PRINTF("min_offset=%s too large\n", min_offset.str().c_str());
return true;
}
}
- if (report.minLength && is_any_accept(v, g)) {
+ if (report.minLength && is_any_accept(v, g)) {
// Simple take on min_length. If we're an edge to accept and our max
// dist from start is too small, we can be pruned.
- const depth &width = maxDistFromInit(du);
- if (width.is_finite() && width < report.minLength) {
+ const depth &width = maxDistFromInit(du);
+ if (width.is_finite() && width < report.minLength) {
DEBUG_PRINTF("max width %s from start too small for min_length\n",
width.str().c_str());
return true;
@@ -712,25 +712,25 @@ bool isEdgePrunable(const NGHolder &g, const Report &report,
}
static
-void pruneExtUnreachable(NGHolder &g, const ReportManager &rm) {
- const auto &reports = all_reports(g);
- if (reports.empty()) {
- return;
- }
-
- if (!hasSameBounds(reports, rm)) {
- DEBUG_PRINTF("report bounds vary\n");
- return;
- }
-
- const auto &report = rm.getReport(*reports.begin());
-
- auto depths = calcBidiDepths(g);
-
+void pruneExtUnreachable(NGHolder &g, const ReportManager &rm) {
+ const auto &reports = all_reports(g);
+ if (reports.empty()) {
+ return;
+ }
+
+ if (!hasSameBounds(reports, rm)) {
+ DEBUG_PRINTF("report bounds vary\n");
+ return;
+ }
+
+ const auto &report = rm.getReport(*reports.begin());
+
+ auto depths = calcBidiDepths(g);
+
vector<NFAEdge> dead;
for (const auto &e : edges_range(g)) {
- if (isEdgePrunable(g, report, depths, e)) {
+ if (isEdgePrunable(g, report, depths, e)) {
DEBUG_PRINTF("pruning\n");
dead.push_back(e);
}
@@ -742,45 +742,45 @@ void pruneExtUnreachable(NGHolder &g, const ReportManager &rm) {
remove_edges(dead, g);
pruneUseless(g);
- clearReports(g);
+ clearReports(g);
}
-/**
- * Remove vacuous edges in graphs where the min_offset or min_length
- * constraints dictate that they can never produce a match.
- */
+/**
+ * Remove vacuous edges in graphs where the min_offset or min_length
+ * constraints dictate that they can never produce a match.
+ */
static
-void pruneVacuousEdges(NGHolder &g, const ReportManager &rm) {
+void pruneVacuousEdges(NGHolder &g, const ReportManager &rm) {
vector<NFAEdge> dead;
- auto has_min_offset = [&](NFAVertex v) {
- assert(!g[v].reports.empty()); // must be reporter
- return all_of_in(g[v].reports, [&](ReportID id) {
- return rm.getReport(id).minOffset > 0;
- });
- };
-
- auto has_min_length = [&](NFAVertex v) {
- assert(!g[v].reports.empty()); // must be reporter
- return all_of_in(g[v].reports, [&](ReportID id) {
- return rm.getReport(id).minLength > 0;
- });
- };
-
+ auto has_min_offset = [&](NFAVertex v) {
+ assert(!g[v].reports.empty()); // must be reporter
+ return all_of_in(g[v].reports, [&](ReportID id) {
+ return rm.getReport(id).minOffset > 0;
+ });
+ };
+
+ auto has_min_length = [&](NFAVertex v) {
+ assert(!g[v].reports.empty()); // must be reporter
+ return all_of_in(g[v].reports, [&](ReportID id) {
+ return rm.getReport(id).minLength > 0;
+ });
+ };
+
for (const auto &e : edges_range(g)) {
const NFAVertex u = source(e, g);
const NFAVertex v = target(e, g);
- // Special case: Crudely remove vacuous edges from start in graphs with
- // a min_offset.
- if (u == g.start && is_any_accept(v, g) && has_min_offset(u)) {
+ // Special case: Crudely remove vacuous edges from start in graphs with
+ // a min_offset.
+ if (u == g.start && is_any_accept(v, g) && has_min_offset(u)) {
DEBUG_PRINTF("vacuous edge in graph with min_offset!\n");
dead.push_back(e);
continue;
}
// If a min_length is set, vacuous edges can be removed.
- if (is_any_start(u, g) && is_any_accept(v, g) && has_min_length(u)) {
+ if (is_any_start(u, g) && is_any_accept(v, g) && has_min_length(u)) {
DEBUG_PRINTF("vacuous edge in graph with min_length!\n");
dead.push_back(e);
continue;
@@ -791,14 +791,14 @@ void pruneVacuousEdges(NGHolder &g, const ReportManager &rm) {
return;
}
- DEBUG_PRINTF("removing %zu vacuous edges\n", dead.size());
+ DEBUG_PRINTF("removing %zu vacuous edges\n", dead.size());
remove_edges(dead, g);
pruneUseless(g);
- clearReports(g);
+ clearReports(g);
}
static
-void pruneUnmatchable(NGHolder &g, const vector<DepthMinMax> &depths,
+void pruneUnmatchable(NGHolder &g, const vector<DepthMinMax> &depths,
const ReportManager &rm, NFAVertex accept) {
vector<NFAEdge> dead;
@@ -809,11 +809,11 @@ void pruneUnmatchable(NGHolder &g, const vector<DepthMinMax> &depths,
continue;
}
- if (!hasSameBounds(g[v].reports, rm)) {
- continue;
- }
- const auto &report = rm.getReport(*g[v].reports.begin());
-
+ if (!hasSameBounds(g[v].reports, rm)) {
+ continue;
+ }
+ const auto &report = rm.getReport(*g[v].reports.begin());
+
u32 idx = g[v].index;
DepthMinMax d = depths[idx]; // copy
pair<s32, s32> adj = getMinMaxOffsetAdjust(rm, g, v);
@@ -822,16 +822,16 @@ void pruneUnmatchable(NGHolder &g, const vector<DepthMinMax> &depths,
d.min += adj.first;
d.max += adj.second;
- if (d.max.is_finite() && d.max < report.minLength) {
+ if (d.max.is_finite() && d.max < report.minLength) {
DEBUG_PRINTF("prune, max match length %s < min_length=%llu\n",
- d.max.str().c_str(), report.minLength);
+ d.max.str().c_str(), report.minLength);
dead.push_back(e);
continue;
}
- if (report.maxOffset != MAX_OFFSET && d.min > report.maxOffset) {
+ if (report.maxOffset != MAX_OFFSET && d.min > report.maxOffset) {
DEBUG_PRINTF("prune, min match length %s > max_offset=%llu\n",
- d.min.str().c_str(), report.maxOffset);
+ d.min.str().c_str(), report.maxOffset);
dead.push_back(e);
continue;
}
@@ -840,15 +840,15 @@ void pruneUnmatchable(NGHolder &g, const vector<DepthMinMax> &depths,
remove_edges(dead, g);
}
-/**
- * Remove edges to accepts that can never produce a match long enough to
- * satisfy our min_length and max_offset constraints.
- */
+/**
+ * Remove edges to accepts that can never produce a match long enough to
+ * satisfy our min_length and max_offset constraints.
+ */
static
-void pruneUnmatchable(NGHolder &g, const ReportManager &rm) {
- if (!any_of_in(all_reports(g), [&](ReportID id) {
- return rm.getReport(id).minLength > 0;
- })) {
+void pruneUnmatchable(NGHolder &g, const ReportManager &rm) {
+ if (!any_of_in(all_reports(g), [&](ReportID id) {
+ return rm.getReport(id).minLength > 0;
+ })) {
return;
}
@@ -858,19 +858,19 @@ void pruneUnmatchable(NGHolder &g, const ReportManager &rm) {
pruneUnmatchable(g, depths, rm, g.acceptEod);
pruneUseless(g);
- clearReports(g);
+ clearReports(g);
}
static
bool hasOffsetAdjustments(const ReportManager &rm, const NGHolder &g) {
- return any_of_in(all_reports(g), [&rm](ReportID id) {
- return rm.getReport(id).offsetAdjust != 0;
- });
+ return any_of_in(all_reports(g), [&rm](ReportID id) {
+ return rm.getReport(id).offsetAdjust != 0;
+ });
}
-void propagateExtendedParams(NGHolder &g, ExpressionInfo &expr,
- ReportManager &rm) {
- if (!hasExtParams(expr)) {
+void propagateExtendedParams(NGHolder &g, ExpressionInfo &expr,
+ ReportManager &rm) {
+ if (!hasExtParams(expr)) {
return;
}
@@ -882,154 +882,154 @@ void propagateExtendedParams(NGHolder &g, ExpressionInfo &expr,
DepthMinMax match_depths = findMatchLengths(rm, g);
DEBUG_PRINTF("match depths %s\n", match_depths.str().c_str());
- if (is_anchored && maxWidth.is_finite() && expr.min_offset > maxWidth) {
+ if (is_anchored && maxWidth.is_finite() && expr.min_offset > maxWidth) {
ostringstream oss;
oss << "Expression is anchored and cannot satisfy min_offset="
- << expr.min_offset << " as it can only produce matches of length "
+ << expr.min_offset << " as it can only produce matches of length "
<< maxWidth << " bytes at most.";
- throw CompileError(expr.index, oss.str());
+ throw CompileError(expr.index, oss.str());
}
- if (minWidth > expr.max_offset) {
+ if (minWidth > expr.max_offset) {
ostringstream oss;
- oss << "Expression has max_offset=" << expr.max_offset
- << " but requires " << minWidth << " bytes to match.";
- throw CompileError(expr.index, oss.str());
+ oss << "Expression has max_offset=" << expr.max_offset
+ << " but requires " << minWidth << " bytes to match.";
+ throw CompileError(expr.index, oss.str());
}
- if (maxWidth.is_finite() && match_depths.max < expr.min_length) {
+ if (maxWidth.is_finite() && match_depths.max < expr.min_length) {
ostringstream oss;
- oss << "Expression has min_length=" << expr.min_length << " but can "
+ oss << "Expression has min_length=" << expr.min_length << " but can "
"only produce matches of length " << match_depths.max <<
" bytes at most.";
- throw CompileError(expr.index, oss.str());
+ throw CompileError(expr.index, oss.str());
}
- if (expr.min_length && expr.min_length <= match_depths.min) {
+ if (expr.min_length && expr.min_length <= match_depths.min) {
DEBUG_PRINTF("min_length=%llu constraint is unnecessary\n",
- expr.min_length);
- expr.min_length = 0;
+ expr.min_length);
+ expr.min_length = 0;
+ }
+
+ if (!hasExtParams(expr)) {
+ return;
}
- if (!hasExtParams(expr)) {
+ updateReportBounds(rm, g, expr);
+}
+
+/**
+ * If the pattern is completely anchored and has a min_length set, this can
+ * be converted to a min_offset.
+ */
+static
+void replaceMinLengthWithOffset(NGHolder &g, ReportManager &rm) {
+ if (has_proper_successor(g.startDs, g)) {
+ return; // not wholly anchored
+ }
+
+ replaceReports(g, [&rm](NFAVertex, ReportID id) {
+ const auto &report = rm.getReport(id);
+ if (report.minLength) {
+ Report new_report = report;
+ u64a min_len_offset = report.minLength - report.offsetAdjust;
+ new_report.minOffset = max(report.minOffset, min_len_offset);
+ new_report.minLength = 0;
+ return rm.getInternalId(new_report);
+ }
+ return id;
+ });
+}
+
+/**
+ * Clear offset bounds on reports that are not needed because they're satisfied
+ * by vertex depth.
+ */
+static
+void removeUnneededOffsetBounds(NGHolder &g, ReportManager &rm) {
+ auto depths = calcDepths(g);
+
+ replaceReports(g, [&](NFAVertex v, ReportID id) {
+ const auto &d = depths.at(g[v].index);
+ const depth &min_depth = min(d.fromStartDotStar.min, d.fromStart.min);
+ const depth &max_depth = maxDistFromStartOfData(d);
+
+ DEBUG_PRINTF("vertex %zu has min_depth=%s, max_depth=%s\n", g[v].index,
+ min_depth.str().c_str(), max_depth.str().c_str());
+
+ Report report = rm.getReport(id); // copy
+ bool modified = false;
+ if (report.minOffset && !report.offsetAdjust &&
+ report.minOffset <= min_depth) {
+ report.minOffset = 0;
+ modified = true;
+ }
+ if (report.maxOffset != MAX_OFFSET && max_depth.is_finite() &&
+ report.maxOffset >= max_depth) {
+ report.maxOffset = MAX_OFFSET;
+ modified = true;
+ }
+ if (modified) {
+ DEBUG_PRINTF("vertex %zu, changed bounds to [%llu,%llu]\n",
+ g[v].index, report.minOffset, report.maxOffset);
+ return rm.getInternalId(report);
+ }
+
+ return id;
+ });
+}
+
+void reduceExtendedParams(NGHolder &g, ReportManager &rm, som_type som) {
+ if (!any_of_in(all_reports(g),
+ [&](ReportID id) { return rm.getReport(id).hasBounds(); })) {
+ DEBUG_PRINTF("no extparam bounds\n");
+ return;
+ }
+
+ DEBUG_PRINTF("graph has extparam bounds\n");
+
+ pruneVacuousEdges(g, rm);
+ if (can_never_match(g)) {
return;
}
- updateReportBounds(rm, g, expr);
-}
-
-/**
- * If the pattern is completely anchored and has a min_length set, this can
- * be converted to a min_offset.
- */
-static
-void replaceMinLengthWithOffset(NGHolder &g, ReportManager &rm) {
- if (has_proper_successor(g.startDs, g)) {
- return; // not wholly anchored
- }
-
- replaceReports(g, [&rm](NFAVertex, ReportID id) {
- const auto &report = rm.getReport(id);
- if (report.minLength) {
- Report new_report = report;
- u64a min_len_offset = report.minLength - report.offsetAdjust;
- new_report.minOffset = max(report.minOffset, min_len_offset);
- new_report.minLength = 0;
- return rm.getInternalId(new_report);
- }
- return id;
- });
-}
-
-/**
- * Clear offset bounds on reports that are not needed because they're satisfied
- * by vertex depth.
- */
-static
-void removeUnneededOffsetBounds(NGHolder &g, ReportManager &rm) {
- auto depths = calcDepths(g);
-
- replaceReports(g, [&](NFAVertex v, ReportID id) {
- const auto &d = depths.at(g[v].index);
- const depth &min_depth = min(d.fromStartDotStar.min, d.fromStart.min);
- const depth &max_depth = maxDistFromStartOfData(d);
-
- DEBUG_PRINTF("vertex %zu has min_depth=%s, max_depth=%s\n", g[v].index,
- min_depth.str().c_str(), max_depth.str().c_str());
-
- Report report = rm.getReport(id); // copy
- bool modified = false;
- if (report.minOffset && !report.offsetAdjust &&
- report.minOffset <= min_depth) {
- report.minOffset = 0;
- modified = true;
- }
- if (report.maxOffset != MAX_OFFSET && max_depth.is_finite() &&
- report.maxOffset >= max_depth) {
- report.maxOffset = MAX_OFFSET;
- modified = true;
- }
- if (modified) {
- DEBUG_PRINTF("vertex %zu, changed bounds to [%llu,%llu]\n",
- g[v].index, report.minOffset, report.maxOffset);
- return rm.getInternalId(report);
- }
-
- return id;
- });
-}
-
-void reduceExtendedParams(NGHolder &g, ReportManager &rm, som_type som) {
- if (!any_of_in(all_reports(g),
- [&](ReportID id) { return rm.getReport(id).hasBounds(); })) {
- DEBUG_PRINTF("no extparam bounds\n");
- return;
- }
-
- DEBUG_PRINTF("graph has extparam bounds\n");
-
- pruneVacuousEdges(g, rm);
- if (can_never_match(g)) {
- return;
- }
-
- pruneUnmatchable(g, rm);
- if (can_never_match(g)) {
- return;
- }
-
- if (!hasOffsetAdjustments(rm, g)) {
- pruneExtUnreachable(g, rm);
- if (can_never_match(g)) {
- return;
- }
- }
-
- replaceMinLengthWithOffset(g, rm);
- if (can_never_match(g)) {
+ pruneUnmatchable(g, rm);
+ if (can_never_match(g)) {
+ return;
+ }
+
+ if (!hasOffsetAdjustments(rm, g)) {
+ pruneExtUnreachable(g, rm);
+ if (can_never_match(g)) {
+ return;
+ }
+ }
+
+ replaceMinLengthWithOffset(g, rm);
+ if (can_never_match(g)) {
return;
}
// If the pattern has a min_length and is of "ratchet" form with one
// unbounded repeat, that repeat can become a bounded repeat.
// e.g. /foo.*bar/{min_length=100} --> /foo.{94,}bar/
- transformMinLengthToRepeat(g, rm);
- if (can_never_match(g)) {
- return;
+ transformMinLengthToRepeat(g, rm);
+ if (can_never_match(g)) {
+ return;
}
// If the pattern is unanchored, has a max_offset and has not asked for
// SOM, we can use that knowledge to anchor it which will limit its
// lifespan. Note that we can't use this transformation if there's a
// min_length, as it's currently handled using "sly SOM".
- if (som == SOM_NONE) {
- anchorPatternWithBoundedRepeat(g, rm);
- if (can_never_match(g)) {
- return;
+ if (som == SOM_NONE) {
+ anchorPatternWithBoundedRepeat(g, rm);
+ if (can_never_match(g)) {
+ return;
}
}
- removeUnneededOffsetBounds(g, rm);
+ removeUnneededOffsetBounds(g, rm);
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_extparam.h b/contrib/libs/hyperscan/src/nfagraph/ng_extparam.h
index 521302642a0..ae818075c07 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_extparam.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_extparam.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,31 +34,31 @@
#ifndef NG_EXTPARAM_H
#define NG_EXTPARAM_H
-#include "som/som.h"
-
+#include "som/som.h"
+
namespace ue2 {
-class ExpressionInfo;
-class NGHolder;
+class ExpressionInfo;
+class NGHolder;
class ReportManager;
-/**
- * \brief Propagate extended parameter information to vertex reports. Will
- * throw CompileError if this expression's extended parameters are not
- * satisfiable.
- *
- * This will also remove extended parameter constraints that are guaranteed to
- * be satisfied from ExpressionInfo.
- */
-void propagateExtendedParams(NGHolder &g, ExpressionInfo &expr,
- ReportManager &rm);
+/**
+ * \brief Propagate extended parameter information to vertex reports. Will
+ * throw CompileError if this expression's extended parameters are not
+ * satisfiable.
+ *
+ * This will also remove extended parameter constraints that are guaranteed to
+ * be satisfied from ExpressionInfo.
+ */
+void propagateExtendedParams(NGHolder &g, ExpressionInfo &expr,
+ ReportManager &rm);
+
+/**
+ * \brief Perform graph reductions (if possible) to do with extended parameter
+ * constraints on reports.
+ */
+void reduceExtendedParams(NGHolder &g, ReportManager &rm, som_type som);
-/**
- * \brief Perform graph reductions (if possible) to do with extended parameter
- * constraints on reports.
- */
-void reduceExtendedParams(NGHolder &g, ReportManager &rm, som_type som);
-
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_fixed_width.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_fixed_width.cpp
index d5ca5116474..8fb264d8a9f 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_fixed_width.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_fixed_width.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -48,7 +48,7 @@ namespace ue2 {
static
bool findMask(const NGHolder &g, vector<CharReach> *mask, bool *anchored,
- flat_set<ReportID> *reports) {
+ flat_set<ReportID> *reports) {
DEBUG_PRINTF("looking for a mask pattern\n");
set<NFAVertex> s_succ;
insert(&s_succ, adjacent_vertices(g.start, g));
@@ -77,7 +77,7 @@ bool findMask(const NGHolder &g, vector<CharReach> *mask, bool *anchored,
NFAVertex v = *succs.begin();
while (true) {
- DEBUG_PRINTF("validating vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("validating vertex %zu\n", g[v].index);
assert(v != g.acceptEod);
@@ -117,7 +117,7 @@ bool handleFixedWidth(RoseBuild &rose, const NGHolder &g, const Grey &grey) {
return false;
}
- flat_set<ReportID> reports;
+ flat_set<ReportID> reports;
bool anchored = false;
vector<CharReach> mask;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.cpp
index 9dd19f05de9..78fd862919a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.cpp
@@ -1,707 +1,707 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Graph fuzzer for approximate matching
- */
-
-#include "ng_fuzzy.h"
-
-#include "ng.h"
-#include "ng_depth.h"
-#include "ng_util.h"
-
-#include <map>
-#include <vector>
-using namespace std;
-
-namespace ue2 {
-
-// returns all successors up to a given depth in a vector of sets, indexed by
-// zero-based depth from source vertex
-static
-vector<flat_set<NFAVertex>> gatherSuccessorsByDepth(const NGHolder &g,
- NFAVertex src, u32 depth) {
- vector<flat_set<NFAVertex>> result(depth);
- flat_set<NFAVertex> cur, next;
-
- assert(depth > 0);
-
- // populate current set of successors
- for (auto v : adjacent_vertices_range(src, g)) {
- // ignore self-loops
- if (src == v) {
- continue;
- }
- DEBUG_PRINTF("Node %zu depth 1\n", g[v].index);
- cur.insert(v);
- }
- result[0] = cur;
-
- for (unsigned d = 1; d < depth; d++) {
- // collect all successors for all current level vertices
- for (auto v : cur) {
- // don't go past special nodes
- if (is_special(v, g)) {
- continue;
- }
-
- for (auto succ : adjacent_vertices_range(v, g)) {
- // ignore self-loops
- if (v == succ) {
- continue;
- }
- DEBUG_PRINTF("Node %zu depth %u\n", g[succ].index, d + 1);
- next.insert(succ);
- }
- }
- result[d] = next;
- next.swap(cur);
- next.clear();
- }
-
- return result;
-}
-
-// returns all predecessors up to a given depth in a vector of sets, indexed by
-// zero-based depth from source vertex
-static
-vector<flat_set<NFAVertex>> gatherPredecessorsByDepth(const NGHolder &g,
- NFAVertex src,
- u32 depth) {
- vector<flat_set<NFAVertex>> result(depth);
- flat_set<NFAVertex> cur, next;
-
- assert(depth > 0);
-
- // populate current set of successors
- for (auto v : inv_adjacent_vertices_range(src, g)) {
- // ignore self-loops
- if (src == v) {
- continue;
- }
- DEBUG_PRINTF("Node %zu depth 1\n", g[v].index);
- cur.insert(v);
- }
- result[0] = cur;
-
- for (unsigned d = 1; d < depth; d++) {
- // collect all successors for all current level vertices
- for (auto v : cur) {
- for (auto pred : inv_adjacent_vertices_range(v, g)) {
- // ignore self-loops
- if (v == pred) {
- continue;
- }
- DEBUG_PRINTF("Node %zu depth %u\n", g[pred].index, d + 1);
- next.insert(pred);
- }
- }
- result[d] = next;
- next.swap(cur);
- next.clear();
- }
-
- return result;
-}
-
-/*
- * This struct produces a fuzzed graph; that is, a graph that is able to match
- * the original pattern, as well as input data within a certain edit distance.
- * Construct the struct, then call fuzz_graph() to transform the graph.
- *
- * Terminology used:
- * - Shadow vertices: vertices mirroring the original graph at various edit
- * distances
- * - Shadow graph level: edit distance of a particular shadow graph
- * - Helpers: dot vertices assigned to shadow vertices, used for insert/replace
- */
-struct ShadowGraph {
- NGHolder &g;
- u32 edit_distance;
- bool hamming;
- map<pair<NFAVertex, u32>, NFAVertex> shadow_map;
- map<pair<NFAVertex, u32>, NFAVertex> helper_map;
- map<NFAVertex, NFAVertex> clones;
- // edge creation is deferred
- vector<pair<NFAVertex, NFAVertex>> edges_to_be_added;
- flat_set<NFAVertex> orig;
-
- ShadowGraph(NGHolder &g_in, u32 ed_in, bool hamm_in)
- : g(g_in), edit_distance(ed_in), hamming(hamm_in) {}
-
- void fuzz_graph() {
- if (edit_distance == 0) {
- return;
- }
-
- DEBUG_PRINTF("edit distance = %u hamming = %s\n", edit_distance,
- hamming ? "true" : "false");
-
- // step 1: prepare the vertices, helpers and shadows according to
- // the original graph
- prepare_graph();
-
- // step 2: add shadow and helper nodes
- build_shadow_graph();
-
- // step 3: set up reports for newly created vertices (and make clones
- // if necessary)
- if (!hamming) {
- create_reports();
- }
-
- // step 4: wire up shadow graph and helpers for insert/replace/remove
- connect_shadow_graph();
-
- // step 5: commit all the edge wirings
- DEBUG_PRINTF("Committing edge wirings\n");
- for (const auto &p : edges_to_be_added) {
- add_edge_if_not_present(p.first, p.second, g);
- }
-
- DEBUG_PRINTF("Done!\n");
- }
-
-private:
- const NFAVertex& get_clone(const NFAVertex &v) {
- return contains(clones, v) ?
- clones[v] : v;
- }
-
- void connect_to_clones(const NFAVertex &u, const NFAVertex &v) {
- const NFAVertex &clone_u = get_clone(u);
- const NFAVertex &clone_v = get_clone(v);
-
- edges_to_be_added.emplace_back(u, v);
- DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[u].index, g[v].index);
-
- // do not connect clones to accepts, we do it during cloning
- if (is_any_accept(clone_v, g)) {
- return;
- }
- edges_to_be_added.emplace_back(clone_u, clone_v);
- DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[clone_u].index,
- g[clone_v].index);
- }
-
- void prepare_graph() {
- DEBUG_PRINTF("Building shadow graphs\n");
-
- for (auto v : vertices_range(g)) {
- // all level 0 vertices are their own helpers and their own shadows
- helper_map[make_pair(v, 0)] = v;
- shadow_map[make_pair(v, 0)] = v;
-
- // find special nodes
- if (is_any_accept(v, g)) {
- DEBUG_PRINTF("Node %zu is a special node\n", g[v].index);
- for (unsigned edit = 1; edit <= edit_distance; edit++) {
- // all accepts are their own shadows and helpers at all
- // levels
- shadow_map[make_pair(v, edit)] = v;
- helper_map[make_pair(v, edit)] = v;
- }
- continue;
- }
- DEBUG_PRINTF("Node %zu is to be shadowed\n", g[v].index);
- orig.insert(v);
- }
- }
-
- void build_shadow_graph() {
- for (auto v : orig) {
- DEBUG_PRINTF("Adding shadow/helper nodes for node %zu\n",
- g[v].index);
- for (unsigned dist = 1; dist <= edit_distance; dist++) {
- auto shadow_v = v;
-
- // start and startDs cannot have shadows but do have helpers
- if (!is_any_start(v, g)) {
- shadow_v = clone_vertex(g, v);
- DEBUG_PRINTF("New shadow node ID: %zu (level %u)\n",
- g[shadow_v].index, dist);
- }
- shadow_map[make_pair(v, dist)] = shadow_v;
-
- // if there's nowhere to go from this vertex, no helper needed
- if (proper_out_degree(v, g) < 1) {
- DEBUG_PRINTF("No helper for node ID: %zu (level %u)\n",
- g[shadow_v].index, dist);
- helper_map[make_pair(v, dist)] = shadow_v;
- continue;
- }
-
- // start and startDs only have helpers for insert, so not Hamming
- if (hamming && is_any_start(v, g)) {
- DEBUG_PRINTF("No helper for node ID: %zu (level %u)\n",
- g[shadow_v].index, dist);
- helper_map[make_pair(v, dist)] = shadow_v;
- continue;
- }
-
- auto helper_v = clone_vertex(g, v);
- DEBUG_PRINTF("New helper node ID: %zu (level %u)\n",
- g[helper_v].index, dist);
-
- // this is a helper, so make it a dot
- g[helper_v].char_reach = CharReach::dot();
- // do not copy virtual start's assert flags
- if (is_virtual_start(v, g)) {
- DEBUG_PRINTF("Helper node ID is virtual start: %zu (level %u)\n",
- g[helper_v].index, dist);
- g[helper_v].assert_flags = 0;
- }
- helper_map[make_pair(v, dist)] = helper_v;
- }
- }
- }
-
- // wire up successors according to the original graph, wire helpers
- // to shadow successors (insert/replace)
- void connect_succs(NFAVertex v, u32 dist) {
- DEBUG_PRINTF("Wiring up successors for node %zu shadow level %u\n",
- g[v].index, dist);
- const auto &cur_shadow_v = shadow_map[make_pair(v, dist)];
- const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
-
- // multiple insert
- if (!hamming && dist > 1) {
- const auto &prev_level_helper = helper_map[make_pair(v, dist - 1)];
- connect_to_clones(prev_level_helper, cur_shadow_helper);
- }
-
- for (auto orig_dst : adjacent_vertices_range(v, g)) {
- const auto &shadow_dst = shadow_map[make_pair(orig_dst, dist)];
-
- connect_to_clones(cur_shadow_v, shadow_dst);
-
- // ignore startDs for insert/replace
- if (orig_dst == g.startDs) {
- continue;
- }
-
- connect_to_clones(cur_shadow_helper, shadow_dst);
- }
- }
-
- // wire up predecessors according to the original graph, wire
- // predecessors to helpers (replace), wire predecessor helpers to
- // helpers (multiple replace)
- void connect_preds(NFAVertex v, u32 dist) {
- DEBUG_PRINTF("Wiring up predecessors for node %zu shadow level %u\n",
- g[v].index, dist);
- const auto &cur_shadow_v = shadow_map[make_pair(v, dist)];
- const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
-
- auto orig_src_vertices = inv_adjacent_vertices_range(v, g);
- for (auto orig_src : orig_src_vertices) {
- // ignore edges from start to startDs
- if (v == g.startDs && orig_src == g.start) {
- continue;
- }
- // ignore self-loops for replace
- if (orig_src != v) {
- // do not wire a replace node for start vertices if we
- // have a virtual start
- if (is_virtual_start(v, g) && is_any_start(orig_src, g)) {
- continue;
- }
-
- if (dist) {
- const auto &prev_level_src =
- shadow_map[make_pair(orig_src, dist - 1)];
- const auto &prev_level_helper =
- helper_map[make_pair(orig_src, dist - 1)];
-
- connect_to_clones(prev_level_src, cur_shadow_helper);
- connect_to_clones(prev_level_helper, cur_shadow_helper);
- }
- }
- // wire predecessor according to original graph
- const auto &shadow_src = shadow_map[make_pair(orig_src, dist)];
-
- connect_to_clones(shadow_src, cur_shadow_v);
- }
- }
-
- // wire up previous level helper to current shadow (insert)
- void connect_helpers(NFAVertex v, u32 dist) {
- DEBUG_PRINTF("Wiring up helpers for node %zu shadow level %u\n",
- g[v].index, dist);
- const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
- auto prev_level_v = shadow_map[make_pair(v, dist - 1)];
-
- connect_to_clones(prev_level_v, cur_shadow_helper);
- }
-
- /*
- * wiring edges for removal is a special case.
- *
- * when wiring edges for removal, as well as wiring up immediate
- * predecessors to immediate successors, we also need to wire up more
- * distant successors to their respective shadow graph levels.
- *
- * for example, consider graph start->a->b->c->d->accept.
- *
- * at edit distance 1, we need remove edges start->b, a->c, b->d, and
- * c->accept, all going from original graph (level 0) to shadow graph
- * level 1.
- *
- * at edit distance 2, we also need edges start->c, a->d and b->accept,
- * all going from level 0 to shadow graph level 2.
- *
- * this is propagated to all shadow levels; that is, given edit
- * distance 3, we will have edges from shadow levels 0->1, 0->2,
- * 0->3, 1->2, 1->3, and 2->3.
- *
- * therefore, we wire them in steps: first wire with step 1 (0->1, 1->2,
- * 2->3) at depth 1, then wire with step 2 (0->2, 1->3) at depth 2, etc.
- *
- * we also have to wire helpers to their removal successors, to
- * accommodate for a replace followed by a remove, on all shadow levels.
- *
- * and finally, we also have to wire source shadows into removal
- * successor helpers on a level above, to accommodate for a remove
- * followed by a replace.
- */
- void connect_removals(NFAVertex v) {
- DEBUG_PRINTF("Wiring up remove edges for node %zu\n", g[v].index);
-
- // vertices returned by this function don't include self-loops
- auto dst_vertices_by_depth =
- gatherSuccessorsByDepth(g, v, edit_distance);
- auto orig_src_vertices = inv_adjacent_vertices_range(v, g);
- for (auto orig_src : orig_src_vertices) {
- // ignore self-loops
- if (orig_src == v) {
- continue;
- }
- for (unsigned step = 1; step <= edit_distance; step++) {
- for (unsigned dist = step; dist <= edit_distance; dist++) {
- auto &dst_vertices = dst_vertices_by_depth[step - 1];
- for (auto &orig_dst : dst_vertices) {
- const auto &shadow_src =
- shadow_map[make_pair(orig_src, dist - step)];
- const auto &shadow_helper =
- helper_map[make_pair(orig_src, dist - step)];
- const auto &shadow_dst =
- shadow_map[make_pair(orig_dst, dist)];
-
- // removal
- connect_to_clones(shadow_src, shadow_dst);
-
- // removal from helper vertex
- connect_to_clones(shadow_helper, shadow_dst);
-
- // removal into helper, requires additional edit
- if ((dist + 1) <= edit_distance) {
- const auto &next_level_helper =
- helper_map[make_pair(orig_dst, dist + 1)];
-
- connect_to_clones(shadow_src, next_level_helper);
- }
- }
- }
- }
- }
- }
-
- void connect_shadow_graph() {
- DEBUG_PRINTF("Wiring up the graph\n");
-
- for (auto v : orig) {
-
- DEBUG_PRINTF("Wiring up edges for node %zu\n", g[v].index);
-
- for (unsigned dist = 0; dist <= edit_distance; dist++) {
-
- // handle insert/replace
- connect_succs(v, dist);
-
- // handle replace/multiple insert
- connect_preds(v, dist);
-
- // handle helpers
- if (!hamming && dist > 0) {
- connect_helpers(v, dist);
- }
- }
-
- // handle removals
- if (!hamming) {
- connect_removals(v);
- }
- }
- }
-
- void connect_to_targets(NFAVertex src, const flat_set<NFAVertex> &targets) {
- for (auto dst : targets) {
- DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[src].index,
- g[dst].index);
- edges_to_be_added.emplace_back(src, dst);
- }
- }
-
- // create a clone of the vertex, but overwrite its report set
- void create_clone(NFAVertex v, const flat_set<ReportID> &reports,
- unsigned max_edit_distance,
- const flat_set<NFAVertex> &targets) {
- // some vertices may have the same reports, but different successors;
- // therefore, we may need to connect them multiple times, but still only
- // clone once
- bool needs_cloning = !contains(clones, v);
-
- DEBUG_PRINTF("Cloning node %zu\n", g[v].index);
- // go through all shadows and helpers, including
- // original vertex
- for (unsigned d = 0; d < max_edit_distance; d++) {
- auto shadow_v = shadow_map[make_pair(v, d)];
- auto helper_v = helper_map[make_pair(v, d)];
-
- NFAVertex new_shadow_v, new_helper_v;
-
- // make sure we don't clone the same vertex twice
- if (needs_cloning) {
- new_shadow_v = clone_vertex(g, shadow_v);
- DEBUG_PRINTF("New shadow node ID: %zu (level %u)\n",
- g[new_shadow_v].index, d);
- clones[shadow_v] = new_shadow_v;
- } else {
- new_shadow_v = clones[shadow_v];
- }
- g[new_shadow_v].reports = reports;
-
- connect_to_targets(new_shadow_v, targets);
-
- if (shadow_v == helper_v) {
- continue;
- }
- if (needs_cloning) {
- new_helper_v = clone_vertex(g, helper_v);
- DEBUG_PRINTF("New helper node ID: %zu (level %u)\n",
- g[new_helper_v].index, d);
- clones[helper_v] = new_helper_v;
- } else {
- new_helper_v = clones[helper_v];
- }
- g[new_helper_v].reports = reports;
-
- connect_to_targets(new_helper_v, targets);
- }
- }
-
- void write_reports(NFAVertex v, const flat_set<ReportID> &reports,
- unsigned max_edit_distance,
- const flat_set<NFAVertex> &targets) {
- // we're overwriting reports, but we're not losing any
- // information as we already cached all the different report
- // sets, so vertices having different reports will be cloned and set up
- // with the correct report set
-
- // go through all shadows and helpers, including original
- // vertex
- for (unsigned d = 0; d < max_edit_distance; d++) {
- auto shadow_v = shadow_map[make_pair(v, d)];
- auto helper_v = helper_map[make_pair(v, d)];
- DEBUG_PRINTF("Setting up reports for shadow node: %zu "
- "(level %u)\n",
- g[shadow_v].index, d);
- DEBUG_PRINTF("Setting up reports for helper node: %zu "
- "(level %u)\n",
- g[helper_v].index, d);
- g[shadow_v].reports = reports;
- g[helper_v].reports = reports;
-
- connect_to_targets(shadow_v, targets);
- connect_to_targets(helper_v, targets);
- }
- }
-
- /*
- * we may have multiple report sets per graph. that means, whenever we
- * construct additional paths through the graph (alternations, removals), we
- * have to account for the fact that some vertices are predecessors to
- * vertices with different report sets.
- *
- * whenever that happens, we have to clone the paths for both report sets,
- * and set up these new vertices with their respective report sets as well.
- *
- * in order to do that, we first have to get all the predecessors for accept
- * and acceptEod vertices. then, go through them one by one, and take note
- * of the report lists. the first report set we find, wins, the rest we
- * clone.
- *
- * we also have to do this in two passes, because there may be vertices that
- * are predecessors to vertices with different report sets, so to avoid
- * overwriting reports we will be caching reports info instead.
- */
- void create_reports() {
- map<flat_set<ReportID>, flat_set<NFAVertex>> reports_to_vertices;
- flat_set<NFAVertex> accepts{g.accept, g.acceptEod};
-
- // gather reports info from all vertices connected to accept
- for (auto accept : accepts) {
- for (auto src : inv_adjacent_vertices_range(accept, g)) {
- // skip special vertices
- if (is_special(src, g)) {
- continue;
- }
- reports_to_vertices[g[src].reports].insert(src);
- }
- }
-
- // we expect to see at most two report sets
- assert(reports_to_vertices.size() > 0 &&
- reports_to_vertices.size() <= 2);
-
- // set up all reports
- bool clone = false;
- for (auto &pair : reports_to_vertices) {
- const auto &reports = pair.first;
- const auto &vertices = pair.second;
-
- for (auto src : vertices) {
- // get all predecessors up to edit distance
- auto src_vertices_by_depth =
- gatherPredecessorsByDepth(g, src, edit_distance);
-
- // find which accepts source vertex connects to
- flat_set<NFAVertex> targets;
- for (const auto &accept : accepts) {
- NFAEdge e = edge(src, accept, g);
- if (e) {
- targets.insert(accept);
- }
- }
- assert(targets.size());
-
- for (unsigned d = 0; d < src_vertices_by_depth.size(); d++) {
- const auto &preds = src_vertices_by_depth[d];
- for (auto v : preds) {
- // only clone a node if it already contains reports
- if (clone && !g[v].reports.empty()) {
- create_clone(v, reports, edit_distance - d,
- targets);
- } else {
- write_reports(v, reports, edit_distance - d,
- targets);
- }
- }
- }
- }
- // clone vertices only if it's not our first report set
- clone = true;
- }
- }
-};
-
-// check if we will edit our way into a vacuous pattern
-static
-bool will_turn_vacuous(const NGHolder &g, u32 edit_distance) {
- auto depths = calcRevDepths(g);
-
- depth min_depth = depth::infinity();
- auto idx = g[g.start].index;
-
- // check distance from start to accept/acceptEod
- if (depths[idx].toAccept.min.is_finite()) {
- min_depth = min(depths[idx].toAccept.min, min_depth);
- }
- if (depths[idx].toAcceptEod.min.is_finite()) {
- min_depth = min(depths[idx].toAcceptEod.min, min_depth);
- }
-
- idx = g[g.startDs].index;
-
- // check distance from startDs to accept/acceptEod
- if (depths[idx].toAccept.min.is_finite()) {
- min_depth = min(depths[idx].toAccept.min, min_depth);
- }
- if (depths[idx].toAcceptEod.min.is_finite()) {
- min_depth = min(depths[idx].toAcceptEod.min, min_depth);
- }
-
- assert(min_depth.is_finite());
-
- // now, check if we can edit our way into a vacuous pattern
- if (min_depth <= (u64a) edit_distance + 1) {
- DEBUG_PRINTF("Pattern will turn vacuous if approximately matched\n");
- return true;
- }
- return false;
-}
-
-void validate_fuzzy_compile(const NGHolder &g, u32 edit_distance, bool hamming,
- bool utf8, const Grey &grey) {
- if (edit_distance == 0) {
- return;
- }
- if (!grey.allowApproximateMatching) {
- throw CompileError("Approximate matching is disabled.");
- }
- if (edit_distance > grey.maxEditDistance) {
- throw CompileError("Edit distance is too big.");
- }
- if (utf8) {
- throw CompileError("UTF-8 is disallowed for approximate matching.");
- }
- // graph isn't fuzzable if there are edge assertions anywhere in the graph
- for (auto e : edges_range(g)) {
- if (g[e].assert_flags) {
- throw CompileError("Zero-width assertions are disallowed for "
- "approximate matching.");
- }
- }
- if (!hamming && will_turn_vacuous(g, edit_distance)) {
- throw CompileError("Approximate matching patterns that reduce to "
- "vacuous patterns are disallowed.");
- }
-}
-
-void make_fuzzy(NGHolder &g, u32 edit_distance, bool hamming,
- const Grey &grey) {
- if (edit_distance == 0) {
- return;
- }
-
- assert(grey.allowApproximateMatching);
- assert(grey.maxEditDistance >= edit_distance);
-
- ShadowGraph sg(g, edit_distance, hamming);
- sg.fuzz_graph();
-
- // For safety, enforce limit on actual vertex count.
- if (num_vertices(g) > grey.limitApproxMatchingVertices) {
- DEBUG_PRINTF("built %zu vertices > limit of %u\n", num_vertices(g),
- grey.limitApproxMatchingVertices);
- throw ResourceLimitError();
- }
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Graph fuzzer for approximate matching
+ */
+
+#include "ng_fuzzy.h"
+
+#include "ng.h"
+#include "ng_depth.h"
+#include "ng_util.h"
+
+#include <map>
+#include <vector>
+using namespace std;
+
+namespace ue2 {
+
+// returns all successors up to a given depth in a vector of sets, indexed by
+// zero-based depth from source vertex
+static
+vector<flat_set<NFAVertex>> gatherSuccessorsByDepth(const NGHolder &g,
+ NFAVertex src, u32 depth) {
+ vector<flat_set<NFAVertex>> result(depth);
+ flat_set<NFAVertex> cur, next;
+
+ assert(depth > 0);
+
+ // populate current set of successors
+ for (auto v : adjacent_vertices_range(src, g)) {
+ // ignore self-loops
+ if (src == v) {
+ continue;
+ }
+ DEBUG_PRINTF("Node %zu depth 1\n", g[v].index);
+ cur.insert(v);
+ }
+ result[0] = cur;
+
+ for (unsigned d = 1; d < depth; d++) {
+ // collect all successors for all current level vertices
+ for (auto v : cur) {
+ // don't go past special nodes
+ if (is_special(v, g)) {
+ continue;
+ }
+
+ for (auto succ : adjacent_vertices_range(v, g)) {
+ // ignore self-loops
+ if (v == succ) {
+ continue;
+ }
+ DEBUG_PRINTF("Node %zu depth %u\n", g[succ].index, d + 1);
+ next.insert(succ);
+ }
+ }
+ result[d] = next;
+ next.swap(cur);
+ next.clear();
+ }
+
+ return result;
+}
+
+// returns all predecessors up to a given depth in a vector of sets, indexed by
+// zero-based depth from source vertex
+static
+vector<flat_set<NFAVertex>> gatherPredecessorsByDepth(const NGHolder &g,
+ NFAVertex src,
+ u32 depth) {
+ vector<flat_set<NFAVertex>> result(depth);
+ flat_set<NFAVertex> cur, next;
+
+ assert(depth > 0);
+
+ // populate current set of successors
+ for (auto v : inv_adjacent_vertices_range(src, g)) {
+ // ignore self-loops
+ if (src == v) {
+ continue;
+ }
+ DEBUG_PRINTF("Node %zu depth 1\n", g[v].index);
+ cur.insert(v);
+ }
+ result[0] = cur;
+
+ for (unsigned d = 1; d < depth; d++) {
+ // collect all successors for all current level vertices
+ for (auto v : cur) {
+ for (auto pred : inv_adjacent_vertices_range(v, g)) {
+ // ignore self-loops
+ if (v == pred) {
+ continue;
+ }
+ DEBUG_PRINTF("Node %zu depth %u\n", g[pred].index, d + 1);
+ next.insert(pred);
+ }
+ }
+ result[d] = next;
+ next.swap(cur);
+ next.clear();
+ }
+
+ return result;
+}
+
+/*
+ * This struct produces a fuzzed graph; that is, a graph that is able to match
+ * the original pattern, as well as input data within a certain edit distance.
+ * Construct the struct, then call fuzz_graph() to transform the graph.
+ *
+ * Terminology used:
+ * - Shadow vertices: vertices mirroring the original graph at various edit
+ * distances
+ * - Shadow graph level: edit distance of a particular shadow graph
+ * - Helpers: dot vertices assigned to shadow vertices, used for insert/replace
+ */
+struct ShadowGraph {
+ NGHolder &g;
+ u32 edit_distance;
+ bool hamming;
+ map<pair<NFAVertex, u32>, NFAVertex> shadow_map;
+ map<pair<NFAVertex, u32>, NFAVertex> helper_map;
+ map<NFAVertex, NFAVertex> clones;
+ // edge creation is deferred
+ vector<pair<NFAVertex, NFAVertex>> edges_to_be_added;
+ flat_set<NFAVertex> orig;
+
+ ShadowGraph(NGHolder &g_in, u32 ed_in, bool hamm_in)
+ : g(g_in), edit_distance(ed_in), hamming(hamm_in) {}
+
+ void fuzz_graph() {
+ if (edit_distance == 0) {
+ return;
+ }
+
+ DEBUG_PRINTF("edit distance = %u hamming = %s\n", edit_distance,
+ hamming ? "true" : "false");
+
+ // step 1: prepare the vertices, helpers and shadows according to
+ // the original graph
+ prepare_graph();
+
+ // step 2: add shadow and helper nodes
+ build_shadow_graph();
+
+ // step 3: set up reports for newly created vertices (and make clones
+ // if necessary)
+ if (!hamming) {
+ create_reports();
+ }
+
+ // step 4: wire up shadow graph and helpers for insert/replace/remove
+ connect_shadow_graph();
+
+ // step 5: commit all the edge wirings
+ DEBUG_PRINTF("Committing edge wirings\n");
+ for (const auto &p : edges_to_be_added) {
+ add_edge_if_not_present(p.first, p.second, g);
+ }
+
+ DEBUG_PRINTF("Done!\n");
+ }
+
+private:
+ const NFAVertex& get_clone(const NFAVertex &v) {
+ return contains(clones, v) ?
+ clones[v] : v;
+ }
+
+ void connect_to_clones(const NFAVertex &u, const NFAVertex &v) {
+ const NFAVertex &clone_u = get_clone(u);
+ const NFAVertex &clone_v = get_clone(v);
+
+ edges_to_be_added.emplace_back(u, v);
+ DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[u].index, g[v].index);
+
+ // do not connect clones to accepts, we do it during cloning
+ if (is_any_accept(clone_v, g)) {
+ return;
+ }
+ edges_to_be_added.emplace_back(clone_u, clone_v);
+ DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[clone_u].index,
+ g[clone_v].index);
+ }
+
+ void prepare_graph() {
+ DEBUG_PRINTF("Building shadow graphs\n");
+
+ for (auto v : vertices_range(g)) {
+ // all level 0 vertices are their own helpers and their own shadows
+ helper_map[make_pair(v, 0)] = v;
+ shadow_map[make_pair(v, 0)] = v;
+
+ // find special nodes
+ if (is_any_accept(v, g)) {
+ DEBUG_PRINTF("Node %zu is a special node\n", g[v].index);
+ for (unsigned edit = 1; edit <= edit_distance; edit++) {
+ // all accepts are their own shadows and helpers at all
+ // levels
+ shadow_map[make_pair(v, edit)] = v;
+ helper_map[make_pair(v, edit)] = v;
+ }
+ continue;
+ }
+ DEBUG_PRINTF("Node %zu is to be shadowed\n", g[v].index);
+ orig.insert(v);
+ }
+ }
+
+ void build_shadow_graph() {
+ for (auto v : orig) {
+ DEBUG_PRINTF("Adding shadow/helper nodes for node %zu\n",
+ g[v].index);
+ for (unsigned dist = 1; dist <= edit_distance; dist++) {
+ auto shadow_v = v;
+
+ // start and startDs cannot have shadows but do have helpers
+ if (!is_any_start(v, g)) {
+ shadow_v = clone_vertex(g, v);
+ DEBUG_PRINTF("New shadow node ID: %zu (level %u)\n",
+ g[shadow_v].index, dist);
+ }
+ shadow_map[make_pair(v, dist)] = shadow_v;
+
+ // if there's nowhere to go from this vertex, no helper needed
+ if (proper_out_degree(v, g) < 1) {
+ DEBUG_PRINTF("No helper for node ID: %zu (level %u)\n",
+ g[shadow_v].index, dist);
+ helper_map[make_pair(v, dist)] = shadow_v;
+ continue;
+ }
+
+ // start and startDs only have helpers for insert, so not Hamming
+ if (hamming && is_any_start(v, g)) {
+ DEBUG_PRINTF("No helper for node ID: %zu (level %u)\n",
+ g[shadow_v].index, dist);
+ helper_map[make_pair(v, dist)] = shadow_v;
+ continue;
+ }
+
+ auto helper_v = clone_vertex(g, v);
+ DEBUG_PRINTF("New helper node ID: %zu (level %u)\n",
+ g[helper_v].index, dist);
+
+ // this is a helper, so make it a dot
+ g[helper_v].char_reach = CharReach::dot();
+ // do not copy virtual start's assert flags
+ if (is_virtual_start(v, g)) {
+ DEBUG_PRINTF("Helper node ID is virtual start: %zu (level %u)\n",
+ g[helper_v].index, dist);
+ g[helper_v].assert_flags = 0;
+ }
+ helper_map[make_pair(v, dist)] = helper_v;
+ }
+ }
+ }
+
+ // wire up successors according to the original graph, wire helpers
+ // to shadow successors (insert/replace)
+ void connect_succs(NFAVertex v, u32 dist) {
+ DEBUG_PRINTF("Wiring up successors for node %zu shadow level %u\n",
+ g[v].index, dist);
+ const auto &cur_shadow_v = shadow_map[make_pair(v, dist)];
+ const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
+
+ // multiple insert
+ if (!hamming && dist > 1) {
+ const auto &prev_level_helper = helper_map[make_pair(v, dist - 1)];
+ connect_to_clones(prev_level_helper, cur_shadow_helper);
+ }
+
+ for (auto orig_dst : adjacent_vertices_range(v, g)) {
+ const auto &shadow_dst = shadow_map[make_pair(orig_dst, dist)];
+
+ connect_to_clones(cur_shadow_v, shadow_dst);
+
+ // ignore startDs for insert/replace
+ if (orig_dst == g.startDs) {
+ continue;
+ }
+
+ connect_to_clones(cur_shadow_helper, shadow_dst);
+ }
+ }
+
+ // wire up predecessors according to the original graph, wire
+ // predecessors to helpers (replace), wire predecessor helpers to
+ // helpers (multiple replace)
+ void connect_preds(NFAVertex v, u32 dist) {
+ DEBUG_PRINTF("Wiring up predecessors for node %zu shadow level %u\n",
+ g[v].index, dist);
+ const auto &cur_shadow_v = shadow_map[make_pair(v, dist)];
+ const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
+
+ auto orig_src_vertices = inv_adjacent_vertices_range(v, g);
+ for (auto orig_src : orig_src_vertices) {
+ // ignore edges from start to startDs
+ if (v == g.startDs && orig_src == g.start) {
+ continue;
+ }
+ // ignore self-loops for replace
+ if (orig_src != v) {
+ // do not wire a replace node for start vertices if we
+ // have a virtual start
+ if (is_virtual_start(v, g) && is_any_start(orig_src, g)) {
+ continue;
+ }
+
+ if (dist) {
+ const auto &prev_level_src =
+ shadow_map[make_pair(orig_src, dist - 1)];
+ const auto &prev_level_helper =
+ helper_map[make_pair(orig_src, dist - 1)];
+
+ connect_to_clones(prev_level_src, cur_shadow_helper);
+ connect_to_clones(prev_level_helper, cur_shadow_helper);
+ }
+ }
+ // wire predecessor according to original graph
+ const auto &shadow_src = shadow_map[make_pair(orig_src, dist)];
+
+ connect_to_clones(shadow_src, cur_shadow_v);
+ }
+ }
+
+ // wire up previous level helper to current shadow (insert)
+ void connect_helpers(NFAVertex v, u32 dist) {
+ DEBUG_PRINTF("Wiring up helpers for node %zu shadow level %u\n",
+ g[v].index, dist);
+ const auto &cur_shadow_helper = helper_map[make_pair(v, dist)];
+ auto prev_level_v = shadow_map[make_pair(v, dist - 1)];
+
+ connect_to_clones(prev_level_v, cur_shadow_helper);
+ }
+
+ /*
+ * wiring edges for removal is a special case.
+ *
+ * when wiring edges for removal, as well as wiring up immediate
+ * predecessors to immediate successors, we also need to wire up more
+ * distant successors to their respective shadow graph levels.
+ *
+ * for example, consider graph start->a->b->c->d->accept.
+ *
+ * at edit distance 1, we need remove edges start->b, a->c, b->d, and
+ * c->accept, all going from original graph (level 0) to shadow graph
+ * level 1.
+ *
+ * at edit distance 2, we also need edges start->c, a->d and b->accept,
+ * all going from level 0 to shadow graph level 2.
+ *
+ * this is propagated to all shadow levels; that is, given edit
+ * distance 3, we will have edges from shadow levels 0->1, 0->2,
+ * 0->3, 1->2, 1->3, and 2->3.
+ *
+ * therefore, we wire them in steps: first wire with step 1 (0->1, 1->2,
+ * 2->3) at depth 1, then wire with step 2 (0->2, 1->3) at depth 2, etc.
+ *
+ * we also have to wire helpers to their removal successors, to
+ * accommodate for a replace followed by a remove, on all shadow levels.
+ *
+ * and finally, we also have to wire source shadows into removal
+ * successor helpers on a level above, to accommodate for a remove
+ * followed by a replace.
+ */
+ void connect_removals(NFAVertex v) {
+ DEBUG_PRINTF("Wiring up remove edges for node %zu\n", g[v].index);
+
+ // vertices returned by this function don't include self-loops
+ auto dst_vertices_by_depth =
+ gatherSuccessorsByDepth(g, v, edit_distance);
+ auto orig_src_vertices = inv_adjacent_vertices_range(v, g);
+ for (auto orig_src : orig_src_vertices) {
+ // ignore self-loops
+ if (orig_src == v) {
+ continue;
+ }
+ for (unsigned step = 1; step <= edit_distance; step++) {
+ for (unsigned dist = step; dist <= edit_distance; dist++) {
+ auto &dst_vertices = dst_vertices_by_depth[step - 1];
+ for (auto &orig_dst : dst_vertices) {
+ const auto &shadow_src =
+ shadow_map[make_pair(orig_src, dist - step)];
+ const auto &shadow_helper =
+ helper_map[make_pair(orig_src, dist - step)];
+ const auto &shadow_dst =
+ shadow_map[make_pair(orig_dst, dist)];
+
+ // removal
+ connect_to_clones(shadow_src, shadow_dst);
+
+ // removal from helper vertex
+ connect_to_clones(shadow_helper, shadow_dst);
+
+ // removal into helper, requires additional edit
+ if ((dist + 1) <= edit_distance) {
+ const auto &next_level_helper =
+ helper_map[make_pair(orig_dst, dist + 1)];
+
+ connect_to_clones(shadow_src, next_level_helper);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void connect_shadow_graph() {
+ DEBUG_PRINTF("Wiring up the graph\n");
+
+ for (auto v : orig) {
+
+ DEBUG_PRINTF("Wiring up edges for node %zu\n", g[v].index);
+
+ for (unsigned dist = 0; dist <= edit_distance; dist++) {
+
+ // handle insert/replace
+ connect_succs(v, dist);
+
+ // handle replace/multiple insert
+ connect_preds(v, dist);
+
+ // handle helpers
+ if (!hamming && dist > 0) {
+ connect_helpers(v, dist);
+ }
+ }
+
+ // handle removals
+ if (!hamming) {
+ connect_removals(v);
+ }
+ }
+ }
+
+ void connect_to_targets(NFAVertex src, const flat_set<NFAVertex> &targets) {
+ for (auto dst : targets) {
+ DEBUG_PRINTF("Adding edge: %zu -> %zu\n", g[src].index,
+ g[dst].index);
+ edges_to_be_added.emplace_back(src, dst);
+ }
+ }
+
+ // create a clone of the vertex, but overwrite its report set
+ void create_clone(NFAVertex v, const flat_set<ReportID> &reports,
+ unsigned max_edit_distance,
+ const flat_set<NFAVertex> &targets) {
+ // some vertices may have the same reports, but different successors;
+ // therefore, we may need to connect them multiple times, but still only
+ // clone once
+ bool needs_cloning = !contains(clones, v);
+
+ DEBUG_PRINTF("Cloning node %zu\n", g[v].index);
+ // go through all shadows and helpers, including
+ // original vertex
+ for (unsigned d = 0; d < max_edit_distance; d++) {
+ auto shadow_v = shadow_map[make_pair(v, d)];
+ auto helper_v = helper_map[make_pair(v, d)];
+
+ NFAVertex new_shadow_v, new_helper_v;
+
+ // make sure we don't clone the same vertex twice
+ if (needs_cloning) {
+ new_shadow_v = clone_vertex(g, shadow_v);
+ DEBUG_PRINTF("New shadow node ID: %zu (level %u)\n",
+ g[new_shadow_v].index, d);
+ clones[shadow_v] = new_shadow_v;
+ } else {
+ new_shadow_v = clones[shadow_v];
+ }
+ g[new_shadow_v].reports = reports;
+
+ connect_to_targets(new_shadow_v, targets);
+
+ if (shadow_v == helper_v) {
+ continue;
+ }
+ if (needs_cloning) {
+ new_helper_v = clone_vertex(g, helper_v);
+ DEBUG_PRINTF("New helper node ID: %zu (level %u)\n",
+ g[new_helper_v].index, d);
+ clones[helper_v] = new_helper_v;
+ } else {
+ new_helper_v = clones[helper_v];
+ }
+ g[new_helper_v].reports = reports;
+
+ connect_to_targets(new_helper_v, targets);
+ }
+ }
+
+ void write_reports(NFAVertex v, const flat_set<ReportID> &reports,
+ unsigned max_edit_distance,
+ const flat_set<NFAVertex> &targets) {
+ // we're overwriting reports, but we're not losing any
+ // information as we already cached all the different report
+ // sets, so vertices having different reports will be cloned and set up
+ // with the correct report set
+
+ // go through all shadows and helpers, including original
+ // vertex
+ for (unsigned d = 0; d < max_edit_distance; d++) {
+ auto shadow_v = shadow_map[make_pair(v, d)];
+ auto helper_v = helper_map[make_pair(v, d)];
+ DEBUG_PRINTF("Setting up reports for shadow node: %zu "
+ "(level %u)\n",
+ g[shadow_v].index, d);
+ DEBUG_PRINTF("Setting up reports for helper node: %zu "
+ "(level %u)\n",
+ g[helper_v].index, d);
+ g[shadow_v].reports = reports;
+ g[helper_v].reports = reports;
+
+ connect_to_targets(shadow_v, targets);
+ connect_to_targets(helper_v, targets);
+ }
+ }
+
+ /*
+ * we may have multiple report sets per graph. that means, whenever we
+ * construct additional paths through the graph (alternations, removals), we
+ * have to account for the fact that some vertices are predecessors to
+ * vertices with different report sets.
+ *
+ * whenever that happens, we have to clone the paths for both report sets,
+ * and set up these new vertices with their respective report sets as well.
+ *
+ * in order to do that, we first have to get all the predecessors for accept
+ * and acceptEod vertices. then, go through them one by one, and take note
+ * of the report lists. the first report set we find, wins, the rest we
+ * clone.
+ *
+ * we also have to do this in two passes, because there may be vertices that
+ * are predecessors to vertices with different report sets, so to avoid
+ * overwriting reports we will be caching reports info instead.
+ */
+ void create_reports() {
+ map<flat_set<ReportID>, flat_set<NFAVertex>> reports_to_vertices;
+ flat_set<NFAVertex> accepts{g.accept, g.acceptEod};
+
+ // gather reports info from all vertices connected to accept
+ for (auto accept : accepts) {
+ for (auto src : inv_adjacent_vertices_range(accept, g)) {
+ // skip special vertices
+ if (is_special(src, g)) {
+ continue;
+ }
+ reports_to_vertices[g[src].reports].insert(src);
+ }
+ }
+
+ // we expect to see at most two report sets
+ assert(reports_to_vertices.size() > 0 &&
+ reports_to_vertices.size() <= 2);
+
+ // set up all reports
+ bool clone = false;
+ for (auto &pair : reports_to_vertices) {
+ const auto &reports = pair.first;
+ const auto &vertices = pair.second;
+
+ for (auto src : vertices) {
+ // get all predecessors up to edit distance
+ auto src_vertices_by_depth =
+ gatherPredecessorsByDepth(g, src, edit_distance);
+
+ // find which accepts source vertex connects to
+ flat_set<NFAVertex> targets;
+ for (const auto &accept : accepts) {
+ NFAEdge e = edge(src, accept, g);
+ if (e) {
+ targets.insert(accept);
+ }
+ }
+ assert(targets.size());
+
+ for (unsigned d = 0; d < src_vertices_by_depth.size(); d++) {
+ const auto &preds = src_vertices_by_depth[d];
+ for (auto v : preds) {
+ // only clone a node if it already contains reports
+ if (clone && !g[v].reports.empty()) {
+ create_clone(v, reports, edit_distance - d,
+ targets);
+ } else {
+ write_reports(v, reports, edit_distance - d,
+ targets);
+ }
+ }
+ }
+ }
+ // clone vertices only if it's not our first report set
+ clone = true;
+ }
+ }
+};
+
+// check if we will edit our way into a vacuous pattern
+static
+bool will_turn_vacuous(const NGHolder &g, u32 edit_distance) {
+ auto depths = calcRevDepths(g);
+
+ depth min_depth = depth::infinity();
+ auto idx = g[g.start].index;
+
+ // check distance from start to accept/acceptEod
+ if (depths[idx].toAccept.min.is_finite()) {
+ min_depth = min(depths[idx].toAccept.min, min_depth);
+ }
+ if (depths[idx].toAcceptEod.min.is_finite()) {
+ min_depth = min(depths[idx].toAcceptEod.min, min_depth);
+ }
+
+ idx = g[g.startDs].index;
+
+ // check distance from startDs to accept/acceptEod
+ if (depths[idx].toAccept.min.is_finite()) {
+ min_depth = min(depths[idx].toAccept.min, min_depth);
+ }
+ if (depths[idx].toAcceptEod.min.is_finite()) {
+ min_depth = min(depths[idx].toAcceptEod.min, min_depth);
+ }
+
+ assert(min_depth.is_finite());
+
+ // now, check if we can edit our way into a vacuous pattern
+ if (min_depth <= (u64a) edit_distance + 1) {
+ DEBUG_PRINTF("Pattern will turn vacuous if approximately matched\n");
+ return true;
+ }
+ return false;
+}
+
+void validate_fuzzy_compile(const NGHolder &g, u32 edit_distance, bool hamming,
+ bool utf8, const Grey &grey) {
+ if (edit_distance == 0) {
+ return;
+ }
+ if (!grey.allowApproximateMatching) {
+ throw CompileError("Approximate matching is disabled.");
+ }
+ if (edit_distance > grey.maxEditDistance) {
+ throw CompileError("Edit distance is too big.");
+ }
+ if (utf8) {
+ throw CompileError("UTF-8 is disallowed for approximate matching.");
+ }
+ // graph isn't fuzzable if there are edge assertions anywhere in the graph
+ for (auto e : edges_range(g)) {
+ if (g[e].assert_flags) {
+ throw CompileError("Zero-width assertions are disallowed for "
+ "approximate matching.");
+ }
+ }
+ if (!hamming && will_turn_vacuous(g, edit_distance)) {
+ throw CompileError("Approximate matching patterns that reduce to "
+ "vacuous patterns are disallowed.");
+ }
+}
+
+void make_fuzzy(NGHolder &g, u32 edit_distance, bool hamming,
+ const Grey &grey) {
+ if (edit_distance == 0) {
+ return;
+ }
+
+ assert(grey.allowApproximateMatching);
+ assert(grey.maxEditDistance >= edit_distance);
+
+ ShadowGraph sg(g, edit_distance, hamming);
+ sg.fuzz_graph();
+
+ // For safety, enforce limit on actual vertex count.
+ if (num_vertices(g) > grey.limitApproxMatchingVertices) {
+ DEBUG_PRINTF("built %zu vertices > limit of %u\n", num_vertices(g),
+ grey.limitApproxMatchingVertices);
+ throw ResourceLimitError();
+ }
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.h b/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.h
index 4093768cd63..a99767d87c5 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_fuzzy.h
@@ -1,49 +1,49 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Graph fuzzer for approximate matching
- */
-
-#ifndef NG_FUZZY_H
-#define NG_FUZZY_H
-
-#include "ue2common.h"
-
-namespace ue2 {
-struct Grey;
-class NGHolder;
-class ReportManager;
-
-void validate_fuzzy_compile(const NGHolder &g, u32 edit_distance, bool hamming,
- bool utf8, const Grey &grey);
-
-void make_fuzzy(NGHolder &g, u32 edit_distance, bool hamming, const Grey &grey);
-}
-
-#endif // NG_FUZZY_H
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Graph fuzzer for approximate matching
+ */
+
+#ifndef NG_FUZZY_H
+#define NG_FUZZY_H
+
+#include "ue2common.h"
+
+namespace ue2 {
+struct Grey;
+class NGHolder;
+class ReportManager;
+
+void validate_fuzzy_compile(const NGHolder &g, u32 edit_distance, bool hamming,
+ bool utf8, const Grey &grey);
+
+void make_fuzzy(NGHolder &g, u32 edit_distance, bool hamming, const Grey &grey);
+}
+
+#endif // NG_FUZZY_H
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_haig.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_haig.cpp
index 26889f89462..80545447727 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_haig.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_haig.cpp
@@ -40,12 +40,12 @@
#include "util/bitfield.h"
#include "util/container.h"
#include "util/determinise.h"
-#include "util/flat_containers.h"
-#include "util/graph.h"
+#include "util/flat_containers.h"
+#include "util/graph.h"
#include "util/graph_range.h"
-#include "util/hash_dynamic_bitset.h"
+#include "util/hash_dynamic_bitset.h"
#include "util/make_unique.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <algorithm>
#include <functional>
@@ -70,15 +70,15 @@ struct haig_too_wide {
template<typename stateset>
static
-void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
stateset *init, stateset *initDS,
vector<NFAVertex> *v_by_index) {
DEBUG_PRINTF("graph kind: %s\n", to_string(g.kind).c_str());
for (auto v : vertices_range(g)) {
- if (contains(unused, v)) {
+ if (contains(unused, v)) {
continue;
}
- u32 v_index = g[v].index;
+ u32 v_index = g[v].index;
if (is_any_start(v, g)) {
init->set(v_index);
if (hasSelfLoop(v, g) || is_triggered(g)) {
@@ -90,11 +90,11 @@ void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
}
v_by_index->clear();
- v_by_index->resize(num_vertices(g), NGHolder::null_vertex());
+ v_by_index->resize(num_vertices(g), NGHolder::null_vertex());
for (auto v : vertices_range(g)) {
u32 v_index = g[v].index;
- assert((*v_by_index)[v_index] == NGHolder::null_vertex());
+ assert((*v_by_index)[v_index] == NGHolder::null_vertex());
(*v_by_index)[v_index] = v;
}
}
@@ -112,29 +112,29 @@ void populateAccepts(const NGHolder &g, StateSet *accept, StateSet *acceptEod) {
}
}
-template<typename Automaton_Traits>
+template<typename Automaton_Traits>
class Automaton_Base {
-public:
- using StateSet = typename Automaton_Traits::StateSet;
- using StateMap = typename Automaton_Traits::StateMap;
-
+public:
+ using StateSet = typename Automaton_Traits::StateSet;
+ using StateMap = typename Automaton_Traits::StateMap;
+
protected:
- Automaton_Base(const NGHolder &graph_in, som_type som,
- const vector<vector<CharReach>> &triggers,
- bool unordered_som)
- : graph(graph_in), numStates(num_vertices(graph)),
- unused(getRedundantStarts(graph_in)),
- init(Automaton_Traits::init_states(numStates)),
- initDS(Automaton_Traits::init_states(numStates)),
- squash(Automaton_Traits::init_states(numStates)),
- accept(Automaton_Traits::init_states(numStates)),
- acceptEod(Automaton_Traits::init_states(numStates)),
- toppable(Automaton_Traits::init_states(numStates)),
- dead(Automaton_Traits::init_states(numStates)) {
+ Automaton_Base(const NGHolder &graph_in, som_type som,
+ const vector<vector<CharReach>> &triggers,
+ bool unordered_som)
+ : graph(graph_in), numStates(num_vertices(graph)),
+ unused(getRedundantStarts(graph_in)),
+ init(Automaton_Traits::init_states(numStates)),
+ initDS(Automaton_Traits::init_states(numStates)),
+ squash(Automaton_Traits::init_states(numStates)),
+ accept(Automaton_Traits::init_states(numStates)),
+ acceptEod(Automaton_Traits::init_states(numStates)),
+ toppable(Automaton_Traits::init_states(numStates)),
+ dead(Automaton_Traits::init_states(numStates)) {
calculateAlphabet(graph, alpha, unalpha, &alphasize);
assert(alphasize <= ALPHABET_SIZE);
- populateInit(graph, unused, &init, &initDS, &v_by_index);
+ populateInit(graph, unused, &init, &initDS, &v_by_index);
populateAccepts(graph, &accept, &acceptEod);
start_anchored = DEAD_STATE + 1;
@@ -146,8 +146,8 @@ protected:
start_floating = DEAD_STATE;
}
- cr_by_index = populateCR(graph, v_by_index, alpha);
-
+ cr_by_index = populateCR(graph, v_by_index, alpha);
+
if (!unordered_som) {
for (const auto &sq : findSquashers(graph, som)) {
NFAVertex v = sq.first;
@@ -158,16 +158,16 @@ protected:
}
if (is_triggered(graph)) {
- dynamic_bitset<> temp(numStates);
- markToppableStarts(graph, unused, false, triggers, &temp);
- toppable = Automaton_Traits::copy_states(temp, numStates);
+ dynamic_bitset<> temp(numStates);
+ markToppableStarts(graph, unused, false, triggers, &temp);
+ toppable = Automaton_Traits::copy_states(temp, numStates);
}
}
private:
// Convert an NFAStateSet (as used by the squash code) into a StateSet.
StateSet shrinkStateSet(const NFAStateSet &in) const {
- StateSet out = Automaton_Traits::init_states(numStates);
+ StateSet out = Automaton_Traits::init_states(numStates);
for (size_t i = in.find_first(); i != in.npos && i < out.size();
i = in.find_next(i)) {
out.set(i);
@@ -175,24 +175,24 @@ private:
return out;
}
- void reports_i(const StateSet &in, bool eod, flat_set<ReportID> &rv) {
- StateSet acc = in & (eod ? acceptEod : accept);
- for (size_t i = acc.find_first(); i != StateSet::npos;
- i = acc.find_next(i)) {
- NFAVertex v = v_by_index[i];
- DEBUG_PRINTF("marking report\n");
- const auto &my_reports = graph[v].reports;
- rv.insert(my_reports.begin(), my_reports.end());
- }
- }
-
+ void reports_i(const StateSet &in, bool eod, flat_set<ReportID> &rv) {
+ StateSet acc = in & (eod ? acceptEod : accept);
+ for (size_t i = acc.find_first(); i != StateSet::npos;
+ i = acc.find_next(i)) {
+ NFAVertex v = v_by_index[i];
+ DEBUG_PRINTF("marking report\n");
+ const auto &my_reports = graph[v].reports;
+ rv.insert(my_reports.begin(), my_reports.end());
+ }
+ }
+
public:
void transition(const StateSet &in, StateSet *next) {
transition_graph(*this, v_by_index, in, next);
}
const vector<StateSet> initial() {
- vector<StateSet> rv = {init};
+ vector<StateSet> rv = {init};
if (start_floating != DEAD_STATE && start_floating != start_anchored) {
rv.push_back(initDS);
}
@@ -202,27 +202,27 @@ public:
void reports(const StateSet &in, flat_set<ReportID> &rv) {
reports_i(in, false, rv);
}
-
+
void reportsEod(const StateSet &in, flat_set<ReportID> &rv) {
reports_i(in, true, rv);
}
- static bool canPrune(const flat_set<ReportID> &) { return false; }
-
- const NGHolder &graph;
- const u32 numStates;
- const flat_set<NFAVertex> unused;
-
- array<u16, ALPHABET_SIZE> alpha;
- array<u16, ALPHABET_SIZE> unalpha;
- u16 alphasize;
-
- set<dstate_id_t> done_a;
- set<dstate_id_t> done_b;
-
- u16 start_anchored;
- u16 start_floating;
-
+ static bool canPrune(const flat_set<ReportID> &) { return false; }
+
+ const NGHolder &graph;
+ const u32 numStates;
+ const flat_set<NFAVertex> unused;
+
+ array<u16, ALPHABET_SIZE> alpha;
+ array<u16, ALPHABET_SIZE> unalpha;
+ u16 alphasize;
+
+ set<dstate_id_t> done_a;
+ set<dstate_id_t> done_b;
+
+ u16 start_anchored;
+ u16 start_floating;
+
vector<NFAVertex> v_by_index;
vector<CharReach> cr_by_index; /* pre alpha'ed */
StateSet init;
@@ -236,58 +236,58 @@ public:
StateSet dead;
};
-struct Big_Traits {
- using StateSet = dynamic_bitset<>;
- using StateMap = unordered_map<StateSet, dstate_id_t, hash_dynamic_bitset>;
-
- static StateSet init_states(u32 num) {
- return StateSet(num);
- }
-
- static StateSet copy_states(const dynamic_bitset<> &in, UNUSED u32 num) {
- assert(in.size() == num);
- return in;
- }
-};
-
-class Automaton_Big : public Automaton_Base<Big_Traits> {
-public:
- Automaton_Big(const NGHolder &graph_in, som_type som,
- const vector<vector<CharReach>> &triggers, bool unordered_som)
- : Automaton_Base(graph_in, som, triggers, unordered_som) {}
-};
-
-struct Graph_Traits {
- using StateSet = bitfield<NFA_STATE_LIMIT>;
- using StateMap = unordered_map<StateSet, dstate_id_t>;
-
- static StateSet init_states(UNUSED u32 num) {
- assert(num <= NFA_STATE_LIMIT);
- return StateSet();
- }
-
- static StateSet copy_states(const dynamic_bitset<> &in, u32 num) {
- StateSet out = init_states(num);
+struct Big_Traits {
+ using StateSet = dynamic_bitset<>;
+ using StateMap = unordered_map<StateSet, dstate_id_t, hash_dynamic_bitset>;
+
+ static StateSet init_states(u32 num) {
+ return StateSet(num);
+ }
+
+ static StateSet copy_states(const dynamic_bitset<> &in, UNUSED u32 num) {
+ assert(in.size() == num);
+ return in;
+ }
+};
+
+class Automaton_Big : public Automaton_Base<Big_Traits> {
+public:
+ Automaton_Big(const NGHolder &graph_in, som_type som,
+ const vector<vector<CharReach>> &triggers, bool unordered_som)
+ : Automaton_Base(graph_in, som, triggers, unordered_som) {}
+};
+
+struct Graph_Traits {
+ using StateSet = bitfield<NFA_STATE_LIMIT>;
+ using StateMap = unordered_map<StateSet, dstate_id_t>;
+
+ static StateSet init_states(UNUSED u32 num) {
+ assert(num <= NFA_STATE_LIMIT);
+ return StateSet();
+ }
+
+ static StateSet copy_states(const dynamic_bitset<> &in, u32 num) {
+ StateSet out = init_states(num);
for (size_t i = in.find_first(); i != in.npos && i < out.size();
i = in.find_next(i)) {
out.set(i);
}
return out;
}
-};
+};
-class Automaton_Graph : public Automaton_Base<Graph_Traits> {
+class Automaton_Graph : public Automaton_Base<Graph_Traits> {
public:
- Automaton_Graph(const NGHolder &graph_in, som_type som,
- const vector<vector<CharReach>> &triggers,
- bool unordered_som)
- : Automaton_Base(graph_in, som, triggers, unordered_som) {}
+ Automaton_Graph(const NGHolder &graph_in, som_type som,
+ const vector<vector<CharReach>> &triggers,
+ bool unordered_som)
+ : Automaton_Base(graph_in, som, triggers, unordered_som) {}
};
class Automaton_Haig_Merge {
public:
- using StateSet = vector<u16>;
- using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
+ using StateSet = vector<u16>;
+ using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
explicit Automaton_Haig_Merge(const vector<const raw_som_dfa *> &in)
: nfas(in.begin(), in.end()), dead(in.size()) {
@@ -430,10 +430,10 @@ bool is_any_start_inc_virtual(NFAVertex v, const NGHolder &g) {
}
static
-s32 getSlotID(const NGHolder &g, UNUSED const flat_set<NFAVertex> &unused,
+s32 getSlotID(const NGHolder &g, UNUSED const flat_set<NFAVertex> &unused,
NFAVertex v) {
if (is_triggered(g) && v == g.start) {
- assert(!contains(unused, v));
+ assert(!contains(unused, v));
} else if (is_any_start_inc_virtual(v, g)) {
return CREATE_NEW_SOM;
}
@@ -451,7 +451,7 @@ void haig_do_preds(const NGHolder &g, const stateset &nfa_states,
NFAVertex v = state_mapping[i];
s32 slot_id = g[v].index;
- DEBUG_PRINTF("d vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("d vertex %zu\n", g[v].index);
vector<u32> &out_map = preds[slot_id];
for (auto u : inv_adjacent_vertices_range(v, g)) {
out_map.push_back(g[u].index);
@@ -464,7 +464,7 @@ void haig_do_preds(const NGHolder &g, const stateset &nfa_states,
template<typename stateset>
static
-void haig_do_report(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void haig_do_report(const NGHolder &g, const flat_set<NFAVertex> &unused,
NFAVertex accept_v, const stateset &source_nfa_states,
const vector<NFAVertex> &state_mapping,
set<som_report> &out) {
@@ -475,7 +475,7 @@ void haig_do_report(const NGHolder &g, const flat_set<NFAVertex> &unused,
continue;
}
for (ReportID report_id : g[v].reports) {
- out.insert(som_report(report_id, getSlotID(g, unused, v)));
+ out.insert(som_report(report_id, getSlotID(g, unused, v)));
}
}
}
@@ -492,7 +492,7 @@ void haig_note_starts(const NGHolder &g, map<u32, u32> *out) {
for (auto v : vertices_range(g)) {
if (is_any_start_inc_virtual(v, g)) {
- DEBUG_PRINTF("%zu creates new som value\n", g[v].index);
+ DEBUG_PRINTF("%zu creates new som value\n", g[v].index);
out->emplace(g[v].index, 0U);
continue;
}
@@ -503,7 +503,7 @@ void haig_note_starts(const NGHolder &g, map<u32, u32> *out) {
const DepthMinMax &d = depths[g[v].index];
if (d.min == d.max && d.min.is_finite()) {
- DEBUG_PRINTF("%zu is fixed at %u\n", g[v].index, (u32)d.min);
+ DEBUG_PRINTF("%zu is fixed at %u\n", g[v].index, (u32)d.min);
out->emplace(g[v].index, d.min);
}
}
@@ -511,16 +511,16 @@ void haig_note_starts(const NGHolder &g, map<u32, u32> *out) {
template<class Auto>
static
-bool doHaig(const NGHolder &g, som_type som,
- const vector<vector<CharReach>> &triggers, bool unordered_som,
- raw_som_dfa *rdfa) {
+bool doHaig(const NGHolder &g, som_type som,
+ const vector<vector<CharReach>> &triggers, bool unordered_som,
+ raw_som_dfa *rdfa) {
u32 state_limit = HAIG_FINAL_DFA_STATE_LIMIT; /* haig never backs down from
a fight */
- using StateSet = typename Auto::StateSet;
+ using StateSet = typename Auto::StateSet;
vector<StateSet> nfa_state_map;
- Auto n(g, som, triggers, unordered_som);
+ Auto n(g, som, triggers, unordered_som);
try {
- if (!determinise(n, rdfa->states, state_limit, &nfa_state_map)) {
+ if (!determinise(n, rdfa->states, state_limit, &nfa_state_map)) {
DEBUG_PRINTF("state limit exceeded\n");
return false;
}
@@ -548,9 +548,9 @@ bool doHaig(const NGHolder &g, som_type som,
haig_do_preds(g, source_states, n.v_by_index,
rdfa->state_som.back().preds);
- haig_do_report(g, n.unused, g.accept, source_states, n.v_by_index,
+ haig_do_report(g, n.unused, g.accept, source_states, n.v_by_index,
rdfa->state_som.back().reports);
- haig_do_report(g, n.unused, g.acceptEod, source_states, n.v_by_index,
+ haig_do_report(g, n.unused, g.acceptEod, source_states, n.v_by_index,
rdfa->state_som.back().reports_eod);
}
@@ -559,10 +559,10 @@ bool doHaig(const NGHolder &g, som_type som,
return true;
}
-unique_ptr<raw_som_dfa>
-attemptToBuildHaig(const NGHolder &g, som_type som, u32 somPrecision,
- const vector<vector<CharReach>> &triggers, const Grey &grey,
- bool unordered_som) {
+unique_ptr<raw_som_dfa>
+attemptToBuildHaig(const NGHolder &g, som_type som, u32 somPrecision,
+ const vector<vector<CharReach>> &triggers, const Grey &grey,
+ bool unordered_som) {
assert(is_triggered(g) != triggers.empty());
assert(!unordered_som || is_triggered(g));
@@ -588,11 +588,11 @@ attemptToBuildHaig(const NGHolder &g, som_type som, u32 somPrecision,
bool rv;
if (numStates <= NFA_STATE_LIMIT) {
/* fast path */
- rv = doHaig<Automaton_Graph>(g, som, triggers, unordered_som,
+ rv = doHaig<Automaton_Graph>(g, som, triggers, unordered_som,
rdfa.get());
} else {
/* not the fast path */
- rv = doHaig<Automaton_Big>(g, som, triggers, unordered_som, rdfa.get());
+ rv = doHaig<Automaton_Big>(g, som, triggers, unordered_som, rdfa.get());
}
if (!rv) {
@@ -722,14 +722,14 @@ unique_ptr<raw_som_dfa> attemptToMergeHaig(const vector<const raw_som_dfa *> &df
}
}
- using StateSet = Automaton_Haig_Merge::StateSet;
+ using StateSet = Automaton_Haig_Merge::StateSet;
vector<StateSet> nfa_state_map;
auto rdfa = ue2::make_unique<raw_som_dfa>(dfas[0]->kind, unordered_som,
NODE_START,
dfas[0]->stream_som_loc_width);
- if (!determinise(n, rdfa->states, limit, &nfa_state_map)) {
- DEBUG_PRINTF("state limit (%u) exceeded\n", limit);
+ if (!determinise(n, rdfa->states, limit, &nfa_state_map)) {
+ DEBUG_PRINTF("state limit (%u) exceeded\n", limit);
return nullptr; /* over state limit */
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_haig.h b/contrib/libs/hyperscan/src/nfagraph/ng_haig.h
index a299ddb3773..baff2f5866c 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_haig.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_haig.h
@@ -54,10 +54,10 @@ struct raw_som_dfa;
* between)
*/
-std::unique_ptr<raw_som_dfa>
-attemptToBuildHaig(const NGHolder &g, som_type som, u32 somPrecision,
- const std::vector<std::vector<CharReach>> &triggers,
- const Grey &grey, bool unordered_som_triggers = false);
+std::unique_ptr<raw_som_dfa>
+attemptToBuildHaig(const NGHolder &g, som_type som, u32 somPrecision,
+ const std::vector<std::vector<CharReach>> &triggers,
+ const Grey &grey, bool unordered_som_triggers = false);
std::unique_ptr<raw_som_dfa>
attemptToMergeHaig(const std::vector<const raw_som_dfa *> &dfas,
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_holder.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_holder.cpp
index 85d3c03f0e7..a2fbb28863d 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_holder.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_holder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,27 +36,27 @@ using namespace std;
namespace ue2 {
// internal use only
-static NFAVertex addSpecialVertex(NGHolder &g, SpecialNodes id) {
- NFAVertex v(add_vertex(g));
+static NFAVertex addSpecialVertex(NGHolder &g, SpecialNodes id) {
+ NFAVertex v(add_vertex(g));
g[v].index = id;
return v;
}
NGHolder::NGHolder(nfa_kind k)
- : kind (k),
+ : kind (k),
// add initial special nodes
- start(addSpecialVertex(*this, NODE_START)),
- startDs(addSpecialVertex(*this, NODE_START_DOTSTAR)),
- accept(addSpecialVertex(*this, NODE_ACCEPT)),
- acceptEod(addSpecialVertex(*this, NODE_ACCEPT_EOD)) {
+ start(addSpecialVertex(*this, NODE_START)),
+ startDs(addSpecialVertex(*this, NODE_START_DOTSTAR)),
+ accept(addSpecialVertex(*this, NODE_ACCEPT)),
+ acceptEod(addSpecialVertex(*this, NODE_ACCEPT_EOD)) {
// wire up some fake edges for the stylized bits of the NFA
add_edge(start, startDs, *this);
add_edge(startDs, startDs, *this);
add_edge(accept, acceptEod, *this);
- (*this)[start].char_reach.setall();
- (*this)[startDs].char_reach.setall();
+ (*this)[start].char_reach.setall();
+ (*this)[startDs].char_reach.setall();
}
NGHolder::~NGHolder(void) {
@@ -64,7 +64,7 @@ NGHolder::~NGHolder(void) {
}
void clear_graph(NGHolder &h) {
- NGHolder::vertex_iterator vi, ve;
+ NGHolder::vertex_iterator vi, ve;
for (tie(vi, ve) = vertices(h); vi != ve;) {
NFAVertex v = *vi;
++vi;
@@ -76,8 +76,8 @@ void clear_graph(NGHolder &h) {
}
assert(num_vertices(h) == N_SPECIALS);
- renumber_vertices(h); /* ensure that we reset our next allocated index */
- renumber_edges(h);
+ renumber_vertices(h); /* ensure that we reset our next allocated index */
+ renumber_edges(h);
// Recreate special stylised edges.
add_edge(h.start, h.startDs, h);
@@ -87,11 +87,11 @@ void clear_graph(NGHolder &h) {
NFAVertex NGHolder::getSpecialVertex(u32 id) const {
switch (id) {
- case NODE_START: return start;
- case NODE_START_DOTSTAR: return startDs;
- case NODE_ACCEPT: return accept;
- case NODE_ACCEPT_EOD: return acceptEod;
- default: return null_vertex();
+ case NODE_START: return start;
+ case NODE_START_DOTSTAR: return startDs;
+ case NODE_ACCEPT: return accept;
+ case NODE_ACCEPT_EOD: return acceptEod;
+ default: return null_vertex();
}
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_holder.h b/contrib/libs/hyperscan/src/nfagraph/ng_holder.h
index 9281a76f30d..36cf62447b8 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_holder.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_holder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,75 +26,75 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/** \file
- * \brief Definition of the NGHolder type used for to represent general nfa
- * graphs as well as all associated types (vertex and edge properties, etc).
- *
- * The NGHolder also contains the special vertices used to represents starts and
- * accepts.
- */
-
+/** \file
+ * \brief Definition of the NGHolder type used for to represent general nfa
+ * graphs as well as all associated types (vertex and edge properties, etc).
+ *
+ * The NGHolder also contains the special vertices used to represents starts and
+ * accepts.
+ */
+
#ifndef NG_HOLDER_H
#define NG_HOLDER_H
#include "ue2common.h"
#include "nfa/nfa_kind.h"
-#include "util/charreach.h"
-#include "util/flat_containers.h"
-#include "util/ue2_graph.h"
+#include "util/charreach.h"
+#include "util/flat_containers.h"
+#include "util/ue2_graph.h"
namespace ue2 {
-/** \brief Properties associated with each vertex in an NFAGraph. */
-struct NFAGraphVertexProps {
- /** \brief Set of characters on which this vertex is reachable. */
- CharReach char_reach;
-
- /** \brief Set of reports raised by this vertex. */
- flat_set<ReportID> reports;
-
- /** \brief Unique index for this vertex, used for BGL algorithms. */
- size_t index = 0;
-
- /** \brief Flags associated with assertions. */
- u32 assert_flags = 0;
-};
-
-/** \brief Properties associated with each edge in an NFAGraph. */
-struct NFAGraphEdgeProps {
- /** \brief Unique index for this edge, used for BGL algorithms. */
- size_t index = 0;
-
- /** \brief For graphs that will be implemented as multi-top engines, this
- * specifies the top events. Only used on edges from the start vertex. */
- flat_set<u32> tops;
-
- /** \brief Flags associated with assertions. */
- u32 assert_flags = 0;
-};
-
-/** \brief vertex_index values for special nodes in the NFAGraph. */
-enum SpecialNodes {
- /** \brief Anchored start vertex. WARNING: this may be triggered at various
- * locations (not just zero) for triggered graphs. */
- NODE_START,
-
- /** \brief Unanchored start-dotstar vertex. WARNING: this may not have a
- * proper self-loop. */
- NODE_START_DOTSTAR,
-
- /** \brief Accept vertex. All vertices that can match at arbitrary offsets
- * must have an edge to this vertex. */
- NODE_ACCEPT,
-
- /** \brief Accept-EOD vertex. Vertices that must raise a match at EOD only
- * must have an edge to this vertex. */
- NODE_ACCEPT_EOD,
-
- /** \brief Sentinel, number of special vertices. */
- N_SPECIALS
-};
-
+/** \brief Properties associated with each vertex in an NFAGraph. */
+struct NFAGraphVertexProps {
+ /** \brief Set of characters on which this vertex is reachable. */
+ CharReach char_reach;
+
+ /** \brief Set of reports raised by this vertex. */
+ flat_set<ReportID> reports;
+
+ /** \brief Unique index for this vertex, used for BGL algorithms. */
+ size_t index = 0;
+
+ /** \brief Flags associated with assertions. */
+ u32 assert_flags = 0;
+};
+
+/** \brief Properties associated with each edge in an NFAGraph. */
+struct NFAGraphEdgeProps {
+ /** \brief Unique index for this edge, used for BGL algorithms. */
+ size_t index = 0;
+
+ /** \brief For graphs that will be implemented as multi-top engines, this
+ * specifies the top events. Only used on edges from the start vertex. */
+ flat_set<u32> tops;
+
+ /** \brief Flags associated with assertions. */
+ u32 assert_flags = 0;
+};
+
+/** \brief vertex_index values for special nodes in the NFAGraph. */
+enum SpecialNodes {
+ /** \brief Anchored start vertex. WARNING: this may be triggered at various
+ * locations (not just zero) for triggered graphs. */
+ NODE_START,
+
+ /** \brief Unanchored start-dotstar vertex. WARNING: this may not have a
+ * proper self-loop. */
+ NODE_START_DOTSTAR,
+
+ /** \brief Accept vertex. All vertices that can match at arbitrary offsets
+ * must have an edge to this vertex. */
+ NODE_ACCEPT,
+
+ /** \brief Accept-EOD vertex. Vertices that must raise a match at EOD only
+ * must have an edge to this vertex. */
+ NODE_ACCEPT_EOD,
+
+ /** \brief Sentinel, number of special vertices. */
+ N_SPECIALS
+};
+
/** \brief Encapsulates an NFAGraph, stores special vertices and other
* metadata.
*
@@ -105,31 +105,31 @@ enum SpecialNodes {
* - (startDs, startDs) (self-loop)
* - (accept, acceptEod)
*/
-class NGHolder : public ue2_graph<NGHolder, NFAGraphVertexProps,
- NFAGraphEdgeProps> {
+class NGHolder : public ue2_graph<NGHolder, NFAGraphVertexProps,
+ NFAGraphEdgeProps> {
public:
explicit NGHolder(nfa_kind kind);
- NGHolder(void) : NGHolder(NFA_OUTFIX) {};
+ NGHolder(void) : NGHolder(NFA_OUTFIX) {};
virtual ~NGHolder(void);
- nfa_kind kind; /* Role that this plays in Rose */
+ nfa_kind kind; /* Role that this plays in Rose */
- static const size_t N_SPECIAL_VERTICES = N_SPECIALS;
-public:
- const vertex_descriptor start; //!< Anchored start vertex.
- const vertex_descriptor startDs; //!< Unanchored start-dotstar vertex.
- const vertex_descriptor accept; //!< Accept vertex.
- const vertex_descriptor acceptEod; //!< Accept at EOD vertex.
+ static const size_t N_SPECIAL_VERTICES = N_SPECIALS;
+public:
+ const vertex_descriptor start; //!< Anchored start vertex.
+ const vertex_descriptor startDs; //!< Unanchored start-dotstar vertex.
+ const vertex_descriptor accept; //!< Accept vertex.
+ const vertex_descriptor acceptEod; //!< Accept at EOD vertex.
- vertex_descriptor getSpecialVertex(u32 id) const;
-};
+ vertex_descriptor getSpecialVertex(u32 id) const;
+};
-typedef NGHolder::vertex_descriptor NFAVertex;
-typedef NGHolder::edge_descriptor NFAEdge;
+typedef NGHolder::vertex_descriptor NFAVertex;
+typedef NGHolder::edge_descriptor NFAEdge;
/** \brief True if the vertex \p v is one of our special vertices. */
template <typename GraphT>
-bool is_special(const typename GraphT::vertex_descriptor v, const GraphT &g) {
+bool is_special(const typename GraphT::vertex_descriptor v, const GraphT &g) {
return g[v].index < N_SPECIALS;
}
@@ -167,8 +167,8 @@ void remove_vertices(Iter begin, Iter end, NGHolder &h, bool renumber = true) {
}
if (renumber) {
- renumber_edges(h);
- renumber_vertices(h);
+ renumber_edges(h);
+ renumber_vertices(h);
}
}
@@ -203,12 +203,12 @@ void remove_edges(Iter begin, Iter end, NGHolder &h, bool renumber = true) {
}
if (renumber) {
- renumber_edges(h);
+ renumber_edges(h);
}
}
-#define DEFAULT_TOP 0U
-
+#define DEFAULT_TOP 0U
+
/** \brief Clear and remove all of the edges pointed to by the edge descriptors
* in the given container.
*
@@ -219,26 +219,26 @@ void remove_edges(const Container &c, NGHolder &h, bool renumber = true) {
remove_edges(c.begin(), c.end(), h, renumber);
}
-inline
+inline
bool is_triggered(const NGHolder &g) {
return is_triggered(g.kind);
}
-inline
+inline
bool generates_callbacks(const NGHolder &g) {
return generates_callbacks(g.kind);
}
-
-inline
-bool has_managed_reports(const NGHolder &g) {
- return has_managed_reports(g.kind);
-}
-
-inline
-bool inspects_states_for_accepts(const NGHolder &g) {
- return inspects_states_for_accepts(g.kind);
-}
-
+
+inline
+bool has_managed_reports(const NGHolder &g) {
+ return has_managed_reports(g.kind);
+}
+
+inline
+bool inspects_states_for_accepts(const NGHolder &g) {
+ return inspects_states_for_accepts(g.kind);
+}
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.cpp
index 72b26b6f804..35a09d0ea25 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,7 +39,7 @@
#include "ng_util.h"
#include "ue2common.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/make_unique.h"
@@ -73,28 +73,28 @@ private:
ReportID a_rep;
ReportID b_rep;
};
-
-/** Comparison functor used to sort by vertex_index. */
-template<typename Graph>
-struct VertexIndexOrdering {
- explicit VertexIndexOrdering(const Graph &g_in) : g(g_in) {}
- bool operator()(typename Graph::vertex_descriptor a,
- typename Graph::vertex_descriptor b) const {
- assert(a == b || g[a].index != g[b].index);
- return g[a].index < g[b].index;
- }
-private:
- const Graph &g;
-};
-
-template<typename Graph>
-static
-VertexIndexOrdering<Graph> make_index_ordering(const Graph &g) {
- return VertexIndexOrdering<Graph>(g);
+
+/** Comparison functor used to sort by vertex_index. */
+template<typename Graph>
+struct VertexIndexOrdering {
+ explicit VertexIndexOrdering(const Graph &g_in) : g(g_in) {}
+ bool operator()(typename Graph::vertex_descriptor a,
+ typename Graph::vertex_descriptor b) const {
+ assert(a == b || g[a].index != g[b].index);
+ return g[a].index < g[b].index;
+ }
+private:
+ const Graph &g;
+};
+
+template<typename Graph>
+static
+VertexIndexOrdering<Graph> make_index_ordering(const Graph &g) {
+ return VertexIndexOrdering<Graph>(g);
+}
+
}
-}
-
static
bool is_equal_i(const NGHolder &a, const NGHolder &b,
const check_report &check_rep) {
@@ -125,7 +125,7 @@ bool is_equal_i(const NGHolder &a, const NGHolder &b,
for (size_t i = 0; i < vert_a.size(); i++) {
NFAVertex va = vert_a[i];
NFAVertex vb = vert_b[i];
- DEBUG_PRINTF("vertex %zu\n", a[va].index);
+ DEBUG_PRINTF("vertex %zu\n", a[va].index);
// Vertex index must be the same.
if (a[va].index != b[vb].index) {
@@ -169,14 +169,14 @@ bool is_equal_i(const NGHolder &a, const NGHolder &b,
}
/* check top for edges out of start */
- vector<pair<u32, flat_set<u32>>> top_a;
- vector<pair<u32, flat_set<u32>>> top_b;
+ vector<pair<u32, flat_set<u32>>> top_a;
+ vector<pair<u32, flat_set<u32>>> top_b;
for (const auto &e : out_edges_range(a.start, a)) {
- top_a.emplace_back(a[target(e, a)].index, a[e].tops);
+ top_a.emplace_back(a[target(e, a)].index, a[e].tops);
}
for (const auto &e : out_edges_range(b.start, b)) {
- top_b.emplace_back(b[target(e, b)].index, b[e].tops);
+ top_b.emplace_back(b[target(e, b)].index, b[e].tops);
}
sort(top_a.begin(), top_a.end());
@@ -196,11 +196,11 @@ u64a hash_holder(const NGHolder &g) {
size_t rv = 0;
for (auto v : vertices_range(g)) {
- hash_combine(rv, g[v].index);
- hash_combine(rv, g[v].char_reach);
+ hash_combine(rv, g[v].index);
+ hash_combine(rv, g[v].char_reach);
for (auto w : adjacent_vertices_range(v, g)) {
- hash_combine(rv, g[w].index);
+ hash_combine(rv, g[w].index);
}
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.h b/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.h
index 4dd4fd34b71..d8046270ff9 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_is_equal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_lbr.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_lbr.cpp
index b511e5f290f..d8ba503ce6d 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_lbr.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_lbr.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Large Bounded Repeat (LBR) engine build code.
*/
@@ -37,19 +37,19 @@
#include "ng_holder.h"
#include "ng_repeat.h"
#include "ng_reports.h"
-#include "nfa/castlecompile.h"
+#include "nfa/castlecompile.h"
#include "nfa/lbr_internal.h"
#include "nfa/nfa_internal.h"
#include "nfa/repeatcompile.h"
-#include "nfa/shufticompile.h"
-#include "nfa/trufflecompile.h"
+#include "nfa/shufticompile.h"
+#include "nfa/trufflecompile.h"
#include "util/alloc.h"
#include "util/bitutils.h" // for lg2
#include "util/compile_context.h"
#include "util/container.h"
#include "util/depth.h"
#include "util/dump_charclass.h"
-#include "util/report_manager.h"
+#include "util/report_manager.h"
#include "util/verify_types.h"
using namespace std;
@@ -129,31 +129,31 @@ void fillNfa(NFA *nfa, lbr_common *c, ReportID report, const depth &repeatMin,
}
template <class LbrStruct> static
-bytecode_ptr<NFA> makeLbrNfa(NFAEngineType nfa_type, enum RepeatType rtype,
- const depth &repeatMax) {
+bytecode_ptr<NFA> makeLbrNfa(NFAEngineType nfa_type, enum RepeatType rtype,
+ const depth &repeatMax) {
size_t tableLen = 0;
if (rtype == REPEAT_SPARSE_OPTIMAL_P) {
tableLen = sizeof(u64a) * (repeatMax + 1);
}
size_t len = sizeof(NFA) + sizeof(LbrStruct) + sizeof(RepeatInfo) +
tableLen + sizeof(u64a);
- auto nfa = make_zeroed_bytecode_ptr<NFA>(len);
+ auto nfa = make_zeroed_bytecode_ptr<NFA>(len);
nfa->type = verify_u8(nfa_type);
nfa->length = verify_u32(len);
return nfa;
}
static
-bytecode_ptr<NFA> buildLbrDot(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> buildLbrDot(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
if (!cr.all()) {
return nullptr;
}
enum RepeatType rtype = chooseRepeatType(repeatMin, repeatMax, minPeriod,
is_reset);
- auto nfa = makeLbrNfa<lbr_dot>(LBR_NFA_DOT, rtype, repeatMax);
+ auto nfa = makeLbrNfa<lbr_dot>(LBR_NFA_DOT, rtype, repeatMax);
struct lbr_dot *ld = (struct lbr_dot *)getMutableImplNfa(nfa.get());
fillNfa<lbr_dot>(nfa.get(), &ld->common, report, repeatMin, repeatMax,
@@ -164,9 +164,9 @@ bytecode_ptr<NFA> buildLbrDot(const CharReach &cr, const depth &repeatMin,
}
static
-bytecode_ptr<NFA> buildLbrVerm(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> buildLbrVerm(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
const CharReach escapes(~cr);
if (escapes.count() != 1) {
@@ -175,7 +175,7 @@ bytecode_ptr<NFA> buildLbrVerm(const CharReach &cr, const depth &repeatMin,
enum RepeatType rtype = chooseRepeatType(repeatMin, repeatMax, minPeriod,
is_reset);
- auto nfa = makeLbrNfa<lbr_verm>(LBR_NFA_VERM, rtype, repeatMax);
+ auto nfa = makeLbrNfa<lbr_verm>(LBR_NFA_VERM, rtype, repeatMax);
struct lbr_verm *lv = (struct lbr_verm *)getMutableImplNfa(nfa.get());
lv->c = escapes.find_first();
@@ -187,9 +187,9 @@ bytecode_ptr<NFA> buildLbrVerm(const CharReach &cr, const depth &repeatMin,
}
static
-bytecode_ptr<NFA> buildLbrNVerm(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> buildLbrNVerm(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
const CharReach escapes(cr);
if (escapes.count() != 1) {
@@ -198,7 +198,7 @@ bytecode_ptr<NFA> buildLbrNVerm(const CharReach &cr, const depth &repeatMin,
enum RepeatType rtype = chooseRepeatType(repeatMin, repeatMax, minPeriod,
is_reset);
- auto nfa = makeLbrNfa<lbr_verm>(LBR_NFA_NVERM, rtype, repeatMax);
+ auto nfa = makeLbrNfa<lbr_verm>(LBR_NFA_NVERM, rtype, repeatMax);
struct lbr_verm *lv = (struct lbr_verm *)getMutableImplNfa(nfa.get());
lv->c = escapes.find_first();
@@ -210,18 +210,18 @@ bytecode_ptr<NFA> buildLbrNVerm(const CharReach &cr, const depth &repeatMin,
}
static
-bytecode_ptr<NFA> buildLbrShuf(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> buildLbrShuf(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
enum RepeatType rtype = chooseRepeatType(repeatMin, repeatMax, minPeriod,
is_reset);
- auto nfa = makeLbrNfa<lbr_shuf>(LBR_NFA_SHUF, rtype, repeatMax);
+ auto nfa = makeLbrNfa<lbr_shuf>(LBR_NFA_SHUF, rtype, repeatMax);
struct lbr_shuf *ls = (struct lbr_shuf *)getMutableImplNfa(nfa.get());
fillNfa<lbr_shuf>(nfa.get(), &ls->common, report, repeatMin, repeatMax,
minPeriod, rtype);
- if (shuftiBuildMasks(~cr, (u8 *)&ls->mask_lo, (u8 *)&ls->mask_hi) == -1) {
+ if (shuftiBuildMasks(~cr, (u8 *)&ls->mask_lo, (u8 *)&ls->mask_hi) == -1) {
return nullptr;
}
@@ -230,27 +230,27 @@ bytecode_ptr<NFA> buildLbrShuf(const CharReach &cr, const depth &repeatMin,
}
static
-bytecode_ptr<NFA> buildLbrTruf(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> buildLbrTruf(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
enum RepeatType rtype = chooseRepeatType(repeatMin, repeatMax, minPeriod,
is_reset);
- auto nfa = makeLbrNfa<lbr_truf>(LBR_NFA_TRUF, rtype, repeatMax);
+ auto nfa = makeLbrNfa<lbr_truf>(LBR_NFA_TRUF, rtype, repeatMax);
struct lbr_truf *lc = (struct lbr_truf *)getMutableImplNfa(nfa.get());
fillNfa<lbr_truf>(nfa.get(), &lc->common, report, repeatMin, repeatMax,
minPeriod, rtype);
- truffleBuildMasks(~cr, (u8 *)&lc->mask1, (u8 *)&lc->mask2);
+ truffleBuildMasks(~cr, (u8 *)&lc->mask1, (u8 *)&lc->mask2);
DEBUG_PRINTF("built truffle lbr\n");
return nfa;
}
static
-bytecode_ptr<NFA> constructLBR(const CharReach &cr, const depth &repeatMin,
- const depth &repeatMax, u32 minPeriod,
- bool is_reset, ReportID report) {
+bytecode_ptr<NFA> constructLBR(const CharReach &cr, const depth &repeatMin,
+ const depth &repeatMax, u32 minPeriod,
+ bool is_reset, ReportID report) {
DEBUG_PRINTF("bounds={%s,%s}, cr=%s (count %zu), report=%u\n",
repeatMin.str().c_str(), repeatMax.str().c_str(),
describeClass(cr, 20, CC_OUT_TEXT).c_str(), cr.count(),
@@ -258,8 +258,8 @@ bytecode_ptr<NFA> constructLBR(const CharReach &cr, const depth &repeatMin,
assert(repeatMin <= repeatMax);
assert(repeatMax.is_reachable());
- auto nfa =
- buildLbrDot(cr, repeatMin, repeatMax, minPeriod, is_reset, report);
+ auto nfa =
+ buildLbrDot(cr, repeatMin, repeatMax, minPeriod, is_reset, report);
if (!nfa) {
nfa = buildLbrVerm(cr, repeatMin, repeatMax, minPeriod, is_reset,
@@ -286,19 +286,19 @@ bytecode_ptr<NFA> constructLBR(const CharReach &cr, const depth &repeatMin,
return nfa;
}
-bytecode_ptr<NFA> constructLBR(const CastleProto &proto,
- const vector<vector<CharReach>> &triggers,
- const CompileContext &cc,
- const ReportManager &rm) {
+bytecode_ptr<NFA> constructLBR(const CastleProto &proto,
+ const vector<vector<CharReach>> &triggers,
+ const CompileContext &cc,
+ const ReportManager &rm) {
if (!cc.grey.allowLbr) {
return nullptr;
}
- if (proto.repeats.size() != 1) {
- return nullptr;
- }
-
- const PureRepeat &repeat = proto.repeats.begin()->second;
+ if (proto.repeats.size() != 1) {
+ return nullptr;
+ }
+
+ const PureRepeat &repeat = proto.repeats.begin()->second;
assert(!repeat.reach.none());
if (repeat.reports.size() != 1) {
@@ -315,9 +315,9 @@ bytecode_ptr<NFA> constructLBR(const CastleProto &proto,
}
ReportID report = *repeat.reports.begin();
- if (has_managed_reports(proto.kind)) {
- report = rm.getProgramOffset(report);
- }
+ if (has_managed_reports(proto.kind)) {
+ report = rm.getProgramOffset(report);
+ }
DEBUG_PRINTF("building LBR %s\n", repeat.bounds.str().c_str());
return constructLBR(repeat.reach, repeat.bounds.min, repeat.bounds.max,
@@ -325,10 +325,10 @@ bytecode_ptr<NFA> constructLBR(const CastleProto &proto,
}
/** \brief Construct an LBR engine from the given graph \p g. */
-bytecode_ptr<NFA> constructLBR(const NGHolder &g,
- const vector<vector<CharReach>> &triggers,
- const CompileContext &cc,
- const ReportManager &rm) {
+bytecode_ptr<NFA> constructLBR(const NGHolder &g,
+ const vector<vector<CharReach>> &triggers,
+ const CompileContext &cc,
+ const ReportManager &rm) {
if (!cc.grey.allowLbr) {
return nullptr;
}
@@ -339,11 +339,11 @@ bytecode_ptr<NFA> constructLBR(const NGHolder &g,
}
if (repeat.reports.size() != 1) {
DEBUG_PRINTF("too many reports\n");
- return nullptr;
+ return nullptr;
}
- CastleProto proto(g.kind, repeat);
- return constructLBR(proto, triggers, cc, rm);
+ CastleProto proto(g.kind, repeat);
+ return constructLBR(proto, triggers, cc, rm);
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_lbr.h b/contrib/libs/hyperscan/src/nfagraph/ng_lbr.h
index 3fa67dd9182..c181dbb9e70 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_lbr.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_lbr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Large Bounded Repeat (LBR) engine build code.
*/
@@ -35,7 +35,7 @@
#define NG_LBR_H
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include <memory>
#include <vector>
@@ -47,24 +47,24 @@ namespace ue2 {
class CharReach;
class NGHolder;
class ReportManager;
-struct CastleProto;
+struct CastleProto;
struct CompileContext;
struct Grey;
/** \brief Construct an LBR engine from the given graph \p g. */
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
constructLBR(const NGHolder &g,
const std::vector<std::vector<CharReach>> &triggers,
- const CompileContext &cc, const ReportManager &rm);
+ const CompileContext &cc, const ReportManager &rm);
-/**
- * \brief Construct an LBR engine from the given CastleProto, which should
- * contain only one repeat.
- */
-bytecode_ptr<NFA>
-constructLBR(const CastleProto &proto,
+/**
+ * \brief Construct an LBR engine from the given CastleProto, which should
+ * contain only one repeat.
+ */
+bytecode_ptr<NFA>
+constructLBR(const CastleProto &proto,
const std::vector<std::vector<CharReach>> &triggers,
- const CompileContext &cc, const ReportManager &rm);
+ const CompileContext &cc, const ReportManager &rm);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_limex.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_limex.cpp
index 87756df4933..2f0a55eab9a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_limex.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_limex.cpp
@@ -26,11 +26,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Limex NFA construction code.
*/
-
+
#include "ng_limex.h"
#include "grey.h"
@@ -52,21 +52,21 @@
#include "util/compile_context.h"
#include "util/container.h"
#include "util/graph_range.h"
-#include "util/report_manager.h"
-#include "util/flat_containers.h"
+#include "util/report_manager.h"
+#include "util/flat_containers.h"
#include "util/verify_types.h"
-#include <algorithm>
+#include <algorithm>
#include <map>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
-#include <boost/range/adaptor/map.hpp>
-
+#include <boost/range/adaptor/map.hpp>
+
using namespace std;
-using boost::adaptors::map_values;
-using boost::adaptors::map_keys;
+using boost::adaptors::map_values;
+using boost::adaptors::map_keys;
namespace ue2 {
@@ -75,39 +75,39 @@ namespace ue2 {
// Only used in assertions.
static
bool sanityCheckGraph(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &state_ids) {
- unordered_set<u32> seen_states;
+ const unordered_map<NFAVertex, u32> &state_ids) {
+ unordered_set<u32> seen_states;
for (auto v : vertices_range(g)) {
// Non-specials should have non-empty reachability.
if (!is_special(v, g)) {
if (g[v].char_reach.none()) {
- DEBUG_PRINTF("vertex %zu has empty reach\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has empty reach\n", g[v].index);
return false;
}
}
- // Vertices with edges to accept or acceptEod must have reports and
- // other vertices must not have them.
+ // Vertices with edges to accept or acceptEod must have reports and
+ // other vertices must not have them.
if (is_match_vertex(v, g) && v != g.accept) {
if (g[v].reports.empty()) {
- DEBUG_PRINTF("vertex %zu has no reports\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has no reports\n", g[v].index);
return false;
}
- } else if (!g[v].reports.empty()) {
- DEBUG_PRINTF("vertex %zu has reports but no accept edge\n",
- g[v].index);
- return false;
+ } else if (!g[v].reports.empty()) {
+ DEBUG_PRINTF("vertex %zu has reports but no accept edge\n",
+ g[v].index);
+ return false;
}
// Participant vertices should have distinct state indices.
if (!contains(state_ids, v)) {
- DEBUG_PRINTF("vertex %zu has no state index!\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has no state index!\n", g[v].index);
return false;
}
u32 s = state_ids.at(v);
if (s != NO_STATE && !seen_states.insert(s).second) {
- DEBUG_PRINTF("vertex %zu has dupe state %u\n", g[v].index, s);
+ DEBUG_PRINTF("vertex %zu has dupe state %u\n", g[v].index, s);
return false;
}
}
@@ -117,20 +117,20 @@ bool sanityCheckGraph(const NGHolder &g,
#endif
static
-unordered_map<NFAVertex, NFAStateSet> findSquashStates(const NGHolder &g,
- const vector<BoundedRepeatData> &repeats) {
- auto squashMap = findSquashers(g);
+unordered_map<NFAVertex, NFAStateSet> findSquashStates(const NGHolder &g,
+ const vector<BoundedRepeatData> &repeats) {
+ auto squashMap = findSquashers(g);
filterSquashers(g, squashMap);
/* We also filter out the cyclic states representing bounded repeats, as
- * they are not really cyclic -- they may turn off unexpectedly. */
+ * they are not really cyclic -- they may turn off unexpectedly. */
for (const auto &br : repeats) {
- if (br.repeatMax.is_finite()) {
- squashMap.erase(br.cyclic);
- }
+ if (br.repeatMax.is_finite()) {
+ squashMap.erase(br.cyclic);
+ }
}
-
- return squashMap;
+
+ return squashMap;
}
/**
@@ -153,315 +153,315 @@ void dropRedundantStartEdges(NGHolder &g) {
}
static
-CharReach calcTopVertexReach(const flat_set<u32> &tops,
- const map<u32, CharReach> &top_reach) {
- CharReach top_cr;
- for (u32 t : tops) {
+CharReach calcTopVertexReach(const flat_set<u32> &tops,
+ const map<u32, CharReach> &top_reach) {
+ CharReach top_cr;
+ for (u32 t : tops) {
if (contains(top_reach, t)) {
- top_cr |= top_reach.at(t);
+ top_cr |= top_reach.at(t);
} else {
top_cr = CharReach::dot();
- break;
+ break;
+ }
+ }
+ return top_cr;
+}
+
+static
+NFAVertex makeTopStartVertex(NGHolder &g, const flat_set<u32> &tops,
+ const flat_set<NFAVertex> &succs,
+ const map<u32, CharReach> &top_reach) {
+ assert(!succs.empty());
+ assert(!tops.empty());
+
+ bool reporter = false;
+
+ NFAVertex u = add_vertex(g[g.start], g);
+ CharReach top_cr = calcTopVertexReach(tops, top_reach);
+ g[u].char_reach = top_cr;
+
+ for (auto v : succs) {
+ if (v == g.accept || v == g.acceptEod) {
+ reporter = true;
}
- }
- return top_cr;
-}
-
-static
-NFAVertex makeTopStartVertex(NGHolder &g, const flat_set<u32> &tops,
- const flat_set<NFAVertex> &succs,
- const map<u32, CharReach> &top_reach) {
- assert(!succs.empty());
- assert(!tops.empty());
-
- bool reporter = false;
-
- NFAVertex u = add_vertex(g[g.start], g);
- CharReach top_cr = calcTopVertexReach(tops, top_reach);
- g[u].char_reach = top_cr;
-
- for (auto v : succs) {
- if (v == g.accept || v == g.acceptEod) {
- reporter = true;
- }
- add_edge(u, v, g);
- }
-
- // Only retain reports (which we copied on add_vertex above) for new top
- // vertices connected to accepts.
- if (!reporter) {
- g[u].reports.clear();
- }
-
- return u;
-}
-
-static
-void pickNextTopStateToHandle(const map<u32, flat_set<NFAVertex>> &top_succs,
- const map<NFAVertex, flat_set<u32>> &succ_tops,
- flat_set<u32> *picked_tops,
- flat_set<NFAVertex> *picked_succs) {
- /* pick top or vertex we want to handle */
- if (top_succs.size() < succ_tops.size()) {
- auto best = top_succs.end();
- for (auto it = top_succs.begin(); it != top_succs.end(); ++it) {
- if (best == top_succs.end()
- || it->second.size() < best->second.size()) {
- best = it;
+ add_edge(u, v, g);
+ }
+
+ // Only retain reports (which we copied on add_vertex above) for new top
+ // vertices connected to accepts.
+ if (!reporter) {
+ g[u].reports.clear();
+ }
+
+ return u;
+}
+
+static
+void pickNextTopStateToHandle(const map<u32, flat_set<NFAVertex>> &top_succs,
+ const map<NFAVertex, flat_set<u32>> &succ_tops,
+ flat_set<u32> *picked_tops,
+ flat_set<NFAVertex> *picked_succs) {
+ /* pick top or vertex we want to handle */
+ if (top_succs.size() < succ_tops.size()) {
+ auto best = top_succs.end();
+ for (auto it = top_succs.begin(); it != top_succs.end(); ++it) {
+ if (best == top_succs.end()
+ || it->second.size() < best->second.size()) {
+ best = it;
}
}
- assert(best != top_succs.end());
- assert(!best->second.empty()); /* should already been pruned */
-
- *picked_tops = { best->first };
- *picked_succs = best->second;
- } else {
- auto best = succ_tops.end();
- for (auto it = succ_tops.begin(); it != succ_tops.end(); ++it) {
- /* have to worry about determinism for this one */
- if (best == succ_tops.end()
- || it->second.size() < best->second.size()
- || (it->second.size() == best->second.size()
- && it->second < best->second)) {
- best = it;
+ assert(best != top_succs.end());
+ assert(!best->second.empty()); /* should already been pruned */
+
+ *picked_tops = { best->first };
+ *picked_succs = best->second;
+ } else {
+ auto best = succ_tops.end();
+ for (auto it = succ_tops.begin(); it != succ_tops.end(); ++it) {
+ /* have to worry about determinism for this one */
+ if (best == succ_tops.end()
+ || it->second.size() < best->second.size()
+ || (it->second.size() == best->second.size()
+ && it->second < best->second)) {
+ best = it;
}
}
- assert(best != succ_tops.end());
- assert(!best->second.empty()); /* should already been pruned */
-
- *picked_succs = { best->first };
- *picked_tops = best->second;
- }
-}
-
-static
-void expandCbsByTops(const map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
- const map<u32, flat_set<NFAVertex>> &top_succs,
- const map<NFAVertex, flat_set<u32>> &succ_tops,
- flat_set<u32> &picked_tops,
- flat_set<NFAVertex> &picked_succs) {
- NFAVertex v = *picked_succs.begin(); /* arbitrary successor - all equiv */
- const auto &cand_tops = succ_tops.at(v);
-
- for (u32 t : cand_tops) {
- if (!contains(unhandled_top_succs, t)) {
- continue;
- }
- if (!has_intersection(unhandled_top_succs.at(t), picked_succs)) {
- continue; /* not adding any useful work that hasn't already been
- * done */
- }
- if (!is_subset_of(picked_succs, top_succs.at(t))) {
- continue; /* will not form a cbs */
- }
- picked_tops.insert(t);
- }
-}
-
-static
-void expandCbsBySuccs(const map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
- const map<u32, flat_set<NFAVertex>> &top_succs,
- const map<NFAVertex, flat_set<u32>> &succ_tops,
- flat_set<u32> &picked_tops,
- flat_set<NFAVertex> &picked_succs) {
- u32 t = *picked_tops.begin(); /* arbitrary top - all equiv */
- const auto &cand_succs = top_succs.at(t);
-
- for (NFAVertex v : cand_succs) {
- if (!contains(unhandled_succ_tops, v)) {
- continue;
- }
- if (!has_intersection(unhandled_succ_tops.at(v), picked_tops)) {
- continue; /* not adding any useful work that hasn't already been
- * done */
- }
- if (!is_subset_of(picked_tops, succ_tops.at(v))) {
- continue; /* will not form a cbs */
- }
- picked_succs.insert(v);
- }
-}
-
-/* See if we can expand the complete bipartite subgraph (cbs) specified by the
- * picked tops/succs by adding more to either of the tops or succs.
- */
-static
-void expandTopSuccCbs(const map<u32, flat_set<NFAVertex>> &top_succs,
- const map<NFAVertex, flat_set<u32>> &succ_tops,
- const map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
- const map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
- flat_set<u32> &picked_tops,
- flat_set<NFAVertex> &picked_succs) {
- /* Note: all picked (tops|succs) are equivalent */
-
- /* Try to expand first (as we are more likely to succeed) on the side
- * with fewest remaining things to be handled */
-
- if (unhandled_top_succs.size() < unhandled_succ_tops.size()) {
- expandCbsByTops(unhandled_top_succs, top_succs, succ_tops,
- picked_tops, picked_succs);
- expandCbsBySuccs(unhandled_succ_tops, top_succs, succ_tops,
- picked_tops, picked_succs);
- } else {
- expandCbsBySuccs(unhandled_succ_tops, top_succs, succ_tops,
- picked_tops, picked_succs);
- expandCbsByTops(unhandled_top_succs, top_succs, succ_tops,
- picked_tops, picked_succs);
- }
-}
-
-static
-void markTopSuccAsHandled(NFAVertex start_v,
- const flat_set<u32> &handled_tops,
- const flat_set<NFAVertex> &handled_succs,
- map<u32, set<NFAVertex>> &tops_out,
- map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
- map<NFAVertex, flat_set<u32>> &unhandled_succ_tops) {
- for (u32 t : handled_tops) {
- tops_out[t].insert(start_v);
- assert(contains(unhandled_top_succs, t));
- erase_all(&unhandled_top_succs[t], handled_succs);
- if (unhandled_top_succs[t].empty()) {
- unhandled_top_succs.erase(t);
- }
- }
-
- for (NFAVertex v : handled_succs) {
- assert(contains(unhandled_succ_tops, v));
- erase_all(&unhandled_succ_tops[v], handled_tops);
- if (unhandled_succ_tops[v].empty()) {
- unhandled_succ_tops.erase(v);
- }
- }
-}
-
-static
-void attemptToUseAsStart(const NGHolder &g, NFAVertex u,
- const map<u32, CharReach> &top_reach,
- map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
- map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
- map<u32, set<NFAVertex>> &tops_out) {
- flat_set<u32> top_inter = unhandled_succ_tops.at(u);
- flat_set<NFAVertex> succs;
- for (NFAVertex v : adjacent_vertices_range(u, g)) {
- if (!contains(unhandled_succ_tops, v)) {
- return;
- }
- /* if it has vacuous reports we need to make sure that the report sets
- * are the same */
- if ((v == g.accept || v == g.acceptEod)
- && g[g.start].reports != g[u].reports) {
- DEBUG_PRINTF("different report behaviour\n");
- return;
- }
- const flat_set<u32> &v_tops = unhandled_succ_tops.at(v);
- flat_set<u32> new_inter;
- auto ni_inserter = inserter(new_inter, new_inter.end());
- set_intersection(top_inter.begin(), top_inter.end(),
- v_tops.begin(), v_tops.end(), ni_inserter);
- top_inter = std::move(new_inter);
- succs.insert(v);
- }
-
- if (top_inter.empty()) {
- return;
- }
-
- auto top_cr = calcTopVertexReach(top_inter, top_reach);
- if (!top_cr.isSubsetOf(g[u].char_reach)) {
- return;
- }
-
- DEBUG_PRINTF("reusing %zu is a start vertex\n", g[u].index);
- markTopSuccAsHandled(u, top_inter, succs, tops_out, unhandled_top_succs,
- unhandled_succ_tops);
-}
-
-/* We may have cases where a top triggers something that starts with a .* (or
- * similar state). In these cases we can make use of that state as a start
- * state.
- */
-static
-void reusePredsAsStarts(const NGHolder &g, const map<u32, CharReach> &top_reach,
- map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
- map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
- map<u32, set<NFAVertex>> &tops_out) {
- /* create list of candidates first, to avoid issues of iter invalidation */
- DEBUG_PRINTF("attempting to reuse vertices for top starts\n");
- vector<NFAVertex> cand_starts;
- for (NFAVertex u : unhandled_succ_tops | map_keys) {
- if (hasSelfLoop(u, g)) {
- cand_starts.push_back(u);
- }
- }
-
- for (NFAVertex u : cand_starts) {
- if (!contains(unhandled_succ_tops, u)) {
- continue;
- }
- attemptToUseAsStart(g, u, top_reach, unhandled_top_succs,
- unhandled_succ_tops, tops_out);
- }
-}
-
-static
-void makeTopStates(NGHolder &g, map<u32, set<NFAVertex>> &tops_out,
- const map<u32, CharReach> &top_reach) {
- /* Ideally, we want to add the smallest number of states to the graph for
- * tops to turn on so that they can accurately trigger their successors.
- *
- * The relationships between tops and their successors forms a bipartite
- * graph. Finding the optimal number of start states to add is equivalent to
- * finding a minimal biclique coverings. Unfortunately, this is known to be
- * NP-complete.
- *
- * Given this, we will just do something simple to avoid creating something
- * truly wasteful:
- * 1) Try to find any cyclic states which can act as their own start states
- * 2) Pick a top or a succ to create a start state for and then try to find
- * the largest complete bipartite subgraph that it is part of.
- */
-
- map<u32, flat_set<NFAVertex>> top_succs;
- map<NFAVertex, flat_set<u32>> succ_tops;
- for (const auto &e : out_edges_range(g.start, g)) {
- NFAVertex v = target(e, g);
- for (u32 t : g[e].tops) {
- top_succs[t].insert(v);
- succ_tops[v].insert(t);
- }
- }
-
- auto unhandled_top_succs = top_succs;
- auto unhandled_succ_tops = succ_tops;
-
- reusePredsAsStarts(g, top_reach, unhandled_top_succs, unhandled_succ_tops,
- tops_out);
-
- /* Note: there may be successors which are equivalent (in terms of
- top-triggering), it may be more efficient to discover this and treat them
- as a unit. TODO */
-
- while (!unhandled_succ_tops.empty()) {
- assert(!unhandled_top_succs.empty());
- DEBUG_PRINTF("creating top start vertex\n");
- flat_set<u32> u_tops;
- flat_set<NFAVertex> u_succs;
- pickNextTopStateToHandle(unhandled_top_succs, unhandled_succ_tops,
- &u_tops, &u_succs);
-
- expandTopSuccCbs(top_succs, succ_tops, unhandled_top_succs,
- unhandled_succ_tops, u_tops, u_succs);
-
- /* create start vertex to handle this top/succ combination */
- NFAVertex u = makeTopStartVertex(g, u_tops, u_succs, top_reach);
-
- /* update maps */
- markTopSuccAsHandled(u, u_tops, u_succs, tops_out, unhandled_top_succs,
- unhandled_succ_tops);
- }
- assert(unhandled_top_succs.empty());
-
+ assert(best != succ_tops.end());
+ assert(!best->second.empty()); /* should already been pruned */
+
+ *picked_succs = { best->first };
+ *picked_tops = best->second;
+ }
+}
+
+static
+void expandCbsByTops(const map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
+ const map<u32, flat_set<NFAVertex>> &top_succs,
+ const map<NFAVertex, flat_set<u32>> &succ_tops,
+ flat_set<u32> &picked_tops,
+ flat_set<NFAVertex> &picked_succs) {
+ NFAVertex v = *picked_succs.begin(); /* arbitrary successor - all equiv */
+ const auto &cand_tops = succ_tops.at(v);
+
+ for (u32 t : cand_tops) {
+ if (!contains(unhandled_top_succs, t)) {
+ continue;
+ }
+ if (!has_intersection(unhandled_top_succs.at(t), picked_succs)) {
+ continue; /* not adding any useful work that hasn't already been
+ * done */
+ }
+ if (!is_subset_of(picked_succs, top_succs.at(t))) {
+ continue; /* will not form a cbs */
+ }
+ picked_tops.insert(t);
+ }
+}
+
+static
+void expandCbsBySuccs(const map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
+ const map<u32, flat_set<NFAVertex>> &top_succs,
+ const map<NFAVertex, flat_set<u32>> &succ_tops,
+ flat_set<u32> &picked_tops,
+ flat_set<NFAVertex> &picked_succs) {
+ u32 t = *picked_tops.begin(); /* arbitrary top - all equiv */
+ const auto &cand_succs = top_succs.at(t);
+
+ for (NFAVertex v : cand_succs) {
+ if (!contains(unhandled_succ_tops, v)) {
+ continue;
+ }
+ if (!has_intersection(unhandled_succ_tops.at(v), picked_tops)) {
+ continue; /* not adding any useful work that hasn't already been
+ * done */
+ }
+ if (!is_subset_of(picked_tops, succ_tops.at(v))) {
+ continue; /* will not form a cbs */
+ }
+ picked_succs.insert(v);
+ }
+}
+
+/* See if we can expand the complete bipartite subgraph (cbs) specified by the
+ * picked tops/succs by adding more to either of the tops or succs.
+ */
+static
+void expandTopSuccCbs(const map<u32, flat_set<NFAVertex>> &top_succs,
+ const map<NFAVertex, flat_set<u32>> &succ_tops,
+ const map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
+ const map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
+ flat_set<u32> &picked_tops,
+ flat_set<NFAVertex> &picked_succs) {
+ /* Note: all picked (tops|succs) are equivalent */
+
+ /* Try to expand first (as we are more likely to succeed) on the side
+ * with fewest remaining things to be handled */
+
+ if (unhandled_top_succs.size() < unhandled_succ_tops.size()) {
+ expandCbsByTops(unhandled_top_succs, top_succs, succ_tops,
+ picked_tops, picked_succs);
+ expandCbsBySuccs(unhandled_succ_tops, top_succs, succ_tops,
+ picked_tops, picked_succs);
+ } else {
+ expandCbsBySuccs(unhandled_succ_tops, top_succs, succ_tops,
+ picked_tops, picked_succs);
+ expandCbsByTops(unhandled_top_succs, top_succs, succ_tops,
+ picked_tops, picked_succs);
+ }
+}
+
+static
+void markTopSuccAsHandled(NFAVertex start_v,
+ const flat_set<u32> &handled_tops,
+ const flat_set<NFAVertex> &handled_succs,
+ map<u32, set<NFAVertex>> &tops_out,
+ map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
+ map<NFAVertex, flat_set<u32>> &unhandled_succ_tops) {
+ for (u32 t : handled_tops) {
+ tops_out[t].insert(start_v);
+ assert(contains(unhandled_top_succs, t));
+ erase_all(&unhandled_top_succs[t], handled_succs);
+ if (unhandled_top_succs[t].empty()) {
+ unhandled_top_succs.erase(t);
+ }
+ }
+
+ for (NFAVertex v : handled_succs) {
+ assert(contains(unhandled_succ_tops, v));
+ erase_all(&unhandled_succ_tops[v], handled_tops);
+ if (unhandled_succ_tops[v].empty()) {
+ unhandled_succ_tops.erase(v);
+ }
+ }
+}
+
+static
+void attemptToUseAsStart(const NGHolder &g, NFAVertex u,
+ const map<u32, CharReach> &top_reach,
+ map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
+ map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
+ map<u32, set<NFAVertex>> &tops_out) {
+ flat_set<u32> top_inter = unhandled_succ_tops.at(u);
+ flat_set<NFAVertex> succs;
+ for (NFAVertex v : adjacent_vertices_range(u, g)) {
+ if (!contains(unhandled_succ_tops, v)) {
+ return;
+ }
+ /* if it has vacuous reports we need to make sure that the report sets
+ * are the same */
+ if ((v == g.accept || v == g.acceptEod)
+ && g[g.start].reports != g[u].reports) {
+ DEBUG_PRINTF("different report behaviour\n");
+ return;
+ }
+ const flat_set<u32> &v_tops = unhandled_succ_tops.at(v);
+ flat_set<u32> new_inter;
+ auto ni_inserter = inserter(new_inter, new_inter.end());
+ set_intersection(top_inter.begin(), top_inter.end(),
+ v_tops.begin(), v_tops.end(), ni_inserter);
+ top_inter = std::move(new_inter);
+ succs.insert(v);
+ }
+
+ if (top_inter.empty()) {
+ return;
+ }
+
+ auto top_cr = calcTopVertexReach(top_inter, top_reach);
+ if (!top_cr.isSubsetOf(g[u].char_reach)) {
+ return;
+ }
+
+ DEBUG_PRINTF("reusing %zu is a start vertex\n", g[u].index);
+ markTopSuccAsHandled(u, top_inter, succs, tops_out, unhandled_top_succs,
+ unhandled_succ_tops);
+}
+
+/* We may have cases where a top triggers something that starts with a .* (or
+ * similar state). In these cases we can make use of that state as a start
+ * state.
+ */
+static
+void reusePredsAsStarts(const NGHolder &g, const map<u32, CharReach> &top_reach,
+ map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
+ map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
+ map<u32, set<NFAVertex>> &tops_out) {
+ /* create list of candidates first, to avoid issues of iter invalidation */
+ DEBUG_PRINTF("attempting to reuse vertices for top starts\n");
+ vector<NFAVertex> cand_starts;
+ for (NFAVertex u : unhandled_succ_tops | map_keys) {
+ if (hasSelfLoop(u, g)) {
+ cand_starts.push_back(u);
+ }
+ }
+
+ for (NFAVertex u : cand_starts) {
+ if (!contains(unhandled_succ_tops, u)) {
+ continue;
+ }
+ attemptToUseAsStart(g, u, top_reach, unhandled_top_succs,
+ unhandled_succ_tops, tops_out);
+ }
+}
+
+static
+void makeTopStates(NGHolder &g, map<u32, set<NFAVertex>> &tops_out,
+ const map<u32, CharReach> &top_reach) {
+ /* Ideally, we want to add the smallest number of states to the graph for
+ * tops to turn on so that they can accurately trigger their successors.
+ *
+ * The relationships between tops and their successors forms a bipartite
+ * graph. Finding the optimal number of start states to add is equivalent to
+ * finding a minimal biclique coverings. Unfortunately, this is known to be
+ * NP-complete.
+ *
+ * Given this, we will just do something simple to avoid creating something
+ * truly wasteful:
+ * 1) Try to find any cyclic states which can act as their own start states
+ * 2) Pick a top or a succ to create a start state for and then try to find
+ * the largest complete bipartite subgraph that it is part of.
+ */
+
+ map<u32, flat_set<NFAVertex>> top_succs;
+ map<NFAVertex, flat_set<u32>> succ_tops;
+ for (const auto &e : out_edges_range(g.start, g)) {
+ NFAVertex v = target(e, g);
+ for (u32 t : g[e].tops) {
+ top_succs[t].insert(v);
+ succ_tops[v].insert(t);
+ }
+ }
+
+ auto unhandled_top_succs = top_succs;
+ auto unhandled_succ_tops = succ_tops;
+
+ reusePredsAsStarts(g, top_reach, unhandled_top_succs, unhandled_succ_tops,
+ tops_out);
+
+ /* Note: there may be successors which are equivalent (in terms of
+ top-triggering), it may be more efficient to discover this and treat them
+ as a unit. TODO */
+
+ while (!unhandled_succ_tops.empty()) {
+ assert(!unhandled_top_succs.empty());
+ DEBUG_PRINTF("creating top start vertex\n");
+ flat_set<u32> u_tops;
+ flat_set<NFAVertex> u_succs;
+ pickNextTopStateToHandle(unhandled_top_succs, unhandled_succ_tops,
+ &u_tops, &u_succs);
+
+ expandTopSuccCbs(top_succs, succ_tops, unhandled_top_succs,
+ unhandled_succ_tops, u_tops, u_succs);
+
+ /* create start vertex to handle this top/succ combination */
+ NFAVertex u = makeTopStartVertex(g, u_tops, u_succs, top_reach);
+
+ /* update maps */
+ markTopSuccAsHandled(u, u_tops, u_succs, tops_out, unhandled_top_succs,
+ unhandled_succ_tops);
+ }
+ assert(unhandled_top_succs.empty());
+
// We are completely replacing the start vertex, so clear its reports.
clear_out_edges(g.start, g);
add_edge(g.start, g.startDs, g);
@@ -471,7 +471,7 @@ void makeTopStates(NGHolder &g, map<u32, set<NFAVertex>> &tops_out,
static
set<NFAVertex> findZombies(const NGHolder &h,
const map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
- const unordered_map<NFAVertex, u32> &state_ids,
+ const unordered_map<NFAVertex, u32> &state_ids,
const CompileContext &cc) {
set<NFAVertex> zombies;
if (!cc.grey.allowZombies) {
@@ -484,7 +484,7 @@ set<NFAVertex> findZombies(const NGHolder &h,
}
if (in_degree(h.acceptEod, h) != 1 || all_reports(h).size() != 1) {
- DEBUG_PRINTF("cannot be made undead - bad reports\n");
+ DEBUG_PRINTF("cannot be made undead - bad reports\n");
return zombies;
}
@@ -519,7 +519,7 @@ set<NFAVertex> findZombies(const NGHolder &h,
}
static
-void reverseStateOrdering(unordered_map<NFAVertex, u32> &state_ids) {
+void reverseStateOrdering(unordered_map<NFAVertex, u32> &state_ids) {
vector<NFAVertex> ordering;
for (auto &e : state_ids) {
if (e.second == NO_STATE) {
@@ -572,9 +572,9 @@ prepareGraph(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
bool impl_test_only, const CompileContext &cc,
- unordered_map<NFAVertex, u32> &state_ids,
- vector<BoundedRepeatData> &repeats,
- map<u32, set<NFAVertex>> &tops) {
+ unordered_map<NFAVertex, u32> &state_ids,
+ vector<BoundedRepeatData> &repeats,
+ map<u32, set<NFAVertex>> &tops) {
assert(is_triggered(h_in) || fixed_depth_tops.empty());
unique_ptr<NGHolder> h = cloneHolder(h_in);
@@ -584,19 +584,19 @@ prepareGraph(const NGHolder &h_in, const ReportManager *rm,
impl_test_only, cc.grey);
// If we're building a rose/suffix, do the top dance.
- flat_set<NFAVertex> topVerts;
+ flat_set<NFAVertex> topVerts;
if (is_triggered(*h)) {
makeTopStates(*h, tops, findTopReach(triggers));
-
- for (const auto &vv : tops | map_values) {
- insert(&topVerts, vv);
- }
+
+ for (const auto &vv : tops | map_values) {
+ insert(&topVerts, vv);
+ }
}
dropRedundantStartEdges(*h);
// Do state numbering
- state_ids = numberStates(*h, topVerts);
+ state_ids = numberStates(*h, topVerts);
// In debugging, we sometimes like to reverse the state numbering to stress
// the NFA construction code.
@@ -609,47 +609,47 @@ prepareGraph(const NGHolder &h_in, const ReportManager *rm,
}
static
-void remapReportsToPrograms(NGHolder &h, const ReportManager &rm) {
- for (const auto &v : vertices_range(h)) {
- auto &reports = h[v].reports;
- if (reports.empty()) {
- continue;
- }
- auto old_reports = reports;
- reports.clear();
- for (const ReportID &id : old_reports) {
- u32 program = rm.getProgramOffset(id);
- reports.insert(program);
- }
- DEBUG_PRINTF("vertex %zu: remapped reports {%s} to programs {%s}\n",
- h[v].index, as_string_list(old_reports).c_str(),
- as_string_list(reports).c_str());
- }
-}
-
-static
-bytecode_ptr<NFA>
+void remapReportsToPrograms(NGHolder &h, const ReportManager &rm) {
+ for (const auto &v : vertices_range(h)) {
+ auto &reports = h[v].reports;
+ if (reports.empty()) {
+ continue;
+ }
+ auto old_reports = reports;
+ reports.clear();
+ for (const ReportID &id : old_reports) {
+ u32 program = rm.getProgramOffset(id);
+ reports.insert(program);
+ }
+ DEBUG_PRINTF("vertex %zu: remapped reports {%s} to programs {%s}\n",
+ h[v].index, as_string_list(old_reports).c_str(),
+ as_string_list(reports).c_str());
+ }
+}
+
+static
+bytecode_ptr<NFA>
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
bool compress_state, bool do_accel, bool impl_test_only,
bool &fast, u32 hint, const CompileContext &cc) {
- if (!has_managed_reports(h_in)) {
+ if (!has_managed_reports(h_in)) {
rm = nullptr;
} else {
assert(rm);
}
- unordered_map<NFAVertex, u32> state_ids;
+ unordered_map<NFAVertex, u32> state_ids;
vector<BoundedRepeatData> repeats;
- map<u32, set<NFAVertex>> tops;
+ map<u32, set<NFAVertex>> tops;
unique_ptr<NGHolder> h
= prepareGraph(h_in, rm, fixed_depth_tops, triggers, impl_test_only, cc,
state_ids, repeats, tops);
// Quick exit: if we've got an embarrassment of riches, i.e. more states
// than we can implement in our largest NFA model, bail here.
- u32 numStates = countStates(state_ids);
+ u32 numStates = countStates(state_ids);
if (numStates > NFA_MAX_STATES) {
DEBUG_PRINTF("Can't build an NFA with %u states\n", numStates);
return nullptr;
@@ -660,12 +660,12 @@ constructNFA(const NGHolder &h_in, const ReportManager *rm,
br_cyclic[br.cyclic] = BoundedRepeatSummary(br.repeatMin, br.repeatMax);
}
- unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
- unordered_map<NFAVertex, NFAStateSet> squashMap;
+ unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
+ unordered_map<NFAVertex, NFAStateSet> squashMap;
// build map of squashed and squashers
if (cc.grey.squashNFA) {
- squashMap = findSquashStates(*h, repeats);
+ squashMap = findSquashStates(*h, repeats);
if (rm && cc.grey.highlanderSquash) {
reportSquashMap = findHighlanderSquashers(*h, *rm);
@@ -674,11 +674,11 @@ constructNFA(const NGHolder &h_in, const ReportManager *rm,
set<NFAVertex> zombies = findZombies(*h, br_cyclic, state_ids, cc);
- if (has_managed_reports(*h)) {
- assert(rm);
- remapReportsToPrograms(*h, *rm);
- }
-
+ if (has_managed_reports(*h)) {
+ assert(rm);
+ remapReportsToPrograms(*h, *rm);
+ }
+
if (!cc.streaming || !cc.grey.compressNFAState) {
compress_state = false;
}
@@ -687,7 +687,7 @@ constructNFA(const NGHolder &h_in, const ReportManager *rm,
zombies, do_accel, compress_state, fast, hint, cc);
}
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
@@ -701,7 +701,7 @@ constructNFA(const NGHolder &h_in, const ReportManager *rm,
#ifndef RELEASE_BUILD
// Variant that allows a hint to be specified.
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
@@ -714,19 +714,19 @@ constructNFA(const NGHolder &h_in, const ReportManager *rm,
#endif // RELEASE_BUILD
static
-bytecode_ptr<NFA> constructReversedNFA_i(const NGHolder &h_in, u32 hint,
- const CompileContext &cc) {
+bytecode_ptr<NFA> constructReversedNFA_i(const NGHolder &h_in, u32 hint,
+ const CompileContext &cc) {
// Make a mutable copy of the graph that we can renumber etc.
NGHolder h;
cloneHolder(h, h_in);
assert(h.kind == NFA_REV_PREFIX); /* triggered, raises internal callbacks */
// Do state numbering.
- auto state_ids = numberStates(h, {});
+ auto state_ids = numberStates(h, {});
// Quick exit: if we've got an embarrassment of riches, i.e. more states
// than we can implement in our largest NFA model, bail here.
- u32 numStates = countStates(state_ids);
+ u32 numStates = countStates(state_ids);
if (numStates > NFA_MAX_STATES) {
DEBUG_PRINTF("Can't build an NFA with %u states\n", numStates);
return nullptr;
@@ -734,47 +734,47 @@ bytecode_ptr<NFA> constructReversedNFA_i(const NGHolder &h_in, u32 hint,
assert(sanityCheckGraph(h, state_ids));
- map<u32, set<NFAVertex>> tops; /* only the standards tops for nfas */
+ map<u32, set<NFAVertex>> tops; /* only the standards tops for nfas */
set<NFAVertex> zombies;
vector<BoundedRepeatData> repeats;
- unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
- unordered_map<NFAVertex, NFAStateSet> squashMap;
+ unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
+ unordered_map<NFAVertex, NFAStateSet> squashMap;
UNUSED bool fast = false;
return generate(h, state_ids, repeats, reportSquashMap, squashMap, tops,
zombies, false, false, fast, hint, cc);
}
-bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h_in,
- const CompileContext &cc) {
+bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h_in,
+ const CompileContext &cc) {
u32 hint = INVALID_NFA; // no hint
return constructReversedNFA_i(h_in, hint, cc);
}
#ifndef RELEASE_BUILD
// Variant that allows a hint to be specified.
-bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h_in, u32 hint,
- const CompileContext &cc) {
+bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h_in, u32 hint,
+ const CompileContext &cc) {
return constructReversedNFA_i(h_in, hint, cc);
}
#endif // RELEASE_BUILD
u32 isImplementableNFA(const NGHolder &g, const ReportManager *rm,
const CompileContext &cc) {
- if (!cc.grey.allowLimExNFA) {
- return false;
- }
-
- assert(!can_never_match(g));
-
+ if (!cc.grey.allowLimExNFA) {
+ return false;
+ }
+
+ assert(!can_never_match(g));
+
// Quick check: we can always implement an NFA with less than NFA_MAX_STATES
// states. Note that top masks can generate extra states, so we account for
// those here too.
- if (num_vertices(g) + getTops(g).size() < NFA_MAX_STATES) {
+ if (num_vertices(g) + getTops(g).size() < NFA_MAX_STATES) {
return true;
}
- if (!has_managed_reports(g)) {
+ if (!has_managed_reports(g)) {
rm = nullptr;
} else {
assert(rm);
@@ -789,14 +789,14 @@ u32 isImplementableNFA(const NGHolder &g, const ReportManager *rm,
* resultant NGHolder has <= NFA_MAX_STATES. If it does, we know we can
* implement it as an NFA. */
- unordered_map<NFAVertex, u32> state_ids;
+ unordered_map<NFAVertex, u32> state_ids;
vector<BoundedRepeatData> repeats;
- map<u32, set<NFAVertex>> tops;
+ map<u32, set<NFAVertex>> tops;
unique_ptr<NGHolder> h
= prepareGraph(g, rm, fixed_depth_tops, triggers, impl_test_only, cc,
state_ids, repeats, tops);
assert(h);
- u32 numStates = countStates(state_ids);
+ u32 numStates = countStates(state_ids);
if (numStates <= NFA_MAX_STATES) {
return numStates;
}
@@ -813,7 +813,7 @@ void reduceImplementableGraph(NGHolder &g, som_type som, const ReportManager *rm
removeRedundancy(g, som);
- if (rm && has_managed_reports(g)) {
+ if (rm && has_managed_reports(g)) {
pruneHighlanderDominated(g, *rm);
}
@@ -826,7 +826,7 @@ void reduceImplementableGraph(NGHolder &g, som_type som, const ReportManager *rm
u32 countAccelStates(const NGHolder &g, const ReportManager *rm,
const CompileContext &cc) {
- if (!has_managed_reports(g)) {
+ if (!has_managed_reports(g)) {
rm = nullptr;
} else {
assert(rm);
@@ -836,14 +836,14 @@ u32 countAccelStates(const NGHolder &g, const ReportManager *rm,
const map<u32, u32> fixed_depth_tops; // empty
const map<u32, vector<vector<CharReach>>> triggers; // empty
- unordered_map<NFAVertex, u32> state_ids;
+ unordered_map<NFAVertex, u32> state_ids;
vector<BoundedRepeatData> repeats;
- map<u32, set<NFAVertex>> tops;
+ map<u32, set<NFAVertex>> tops;
unique_ptr<NGHolder> h
= prepareGraph(g, rm, fixed_depth_tops, triggers, impl_test_only, cc,
state_ids, repeats, tops);
- if (!h || countStates(state_ids) > NFA_MAX_STATES) {
+ if (!h || countStates(state_ids) > NFA_MAX_STATES) {
DEBUG_PRINTF("not constructible\n");
return NFA_MAX_ACCEL_STATES + 1;
}
@@ -852,8 +852,8 @@ u32 countAccelStates(const NGHolder &g, const ReportManager *rm,
// Should have no bearing on accel calculation, so we leave these empty.
const set<NFAVertex> zombies;
- unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
- unordered_map<NFAVertex, NFAStateSet> squashMap;
+ unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
+ unordered_map<NFAVertex, NFAStateSet> squashMap;
return countAccelStates(*h, state_ids, repeats, reportSquashMap, squashMap,
tops, zombies, cc);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_limex.h b/contrib/libs/hyperscan/src/nfagraph/ng_limex.h
index 7c9de044d05..7eba2eff065 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_limex.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_limex.h
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Limex NFA construction code.
*/
@@ -36,7 +36,7 @@
#include "ue2common.h"
#include "som/som.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include <map>
#include <memory>
@@ -52,8 +52,8 @@ class NGHolder;
class ReportManager;
struct CompileContext;
-/**
- * \brief Determine if the given graph is implementable as an NFA.
+/**
+ * \brief Determine if the given graph is implementable as an NFA.
*
* Returns zero if the NFA is not implementable (usually because it has too
* many states for any of our models). Otherwise returns the number of states.
@@ -64,14 +64,14 @@ struct CompileContext;
u32 isImplementableNFA(const NGHolder &g, const ReportManager *rm,
const CompileContext &cc);
-/**
- * \brief Late-stage graph reductions.
+/**
+ * \brief Late-stage graph reductions.
*
* This will call \ref removeRedundancy and apply its changes to the given
- * holder only if it is implementable afterwards.
- */
-void reduceImplementableGraph(NGHolder &g, som_type som,
- const ReportManager *rm,
+ * holder only if it is implementable afterwards.
+ */
+void reduceImplementableGraph(NGHolder &g, som_type som,
+ const ReportManager *rm,
const CompileContext &cc);
/**
@@ -84,8 +84,8 @@ void reduceImplementableGraph(NGHolder &g, som_type som,
u32 countAccelStates(const NGHolder &g, const ReportManager *rm,
const CompileContext &cc);
-/**
- * \brief Construct an NFA from the given graph.
+/**
+ * \brief Construct an NFA from the given graph.
*
* Returns zero if the NFA is not implementable (usually because it has too
* many states for any of our models). Otherwise returns the number of states.
@@ -96,25 +96,25 @@ u32 countAccelStates(const NGHolder &g, const ReportManager *rm,
* Note: this variant of the function allows a model to be specified with the
* \a hint parameter.
*/
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
constructNFA(const NGHolder &g, const ReportManager *rm,
const std::map<u32, u32> &fixed_depth_tops,
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
bool compress_state, bool &fast, const CompileContext &cc);
-/**
- * \brief Build a reverse NFA from the graph given, which should have already
+/**
+ * \brief Build a reverse NFA from the graph given, which should have already
* been reversed.
*
* Used for reverse NFAs used in SOM mode.
*/
-bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h,
- const CompileContext &cc);
+bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h,
+ const CompileContext &cc);
#ifndef RELEASE_BUILD
-/**
- * \brief Construct an NFA (with model type hint) from the given graph.
+/**
+ * \brief Construct an NFA (with model type hint) from the given graph.
*
* Returns zero if the NFA is not implementable (usually because it has too
* many states for any of our models). Otherwise returns the number of states.
@@ -125,20 +125,20 @@ bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h,
* Note: this variant of the function allows a model to be specified with the
* \a hint parameter.
*/
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
constructNFA(const NGHolder &g, const ReportManager *rm,
const std::map<u32, u32> &fixed_depth_tops,
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
bool compress_state, bool &fast, u32 hint, const CompileContext &cc);
-/**
- * \brief Build a reverse NFA (with model type hint) from the graph given,
+/**
+ * \brief Build a reverse NFA (with model type hint) from the graph given,
* which should have already been reversed.
*
* Used for reverse NFAs used in SOM mode.
*/
-bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h, u32 hint,
- const CompileContext &cc);
+bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h, u32 hint,
+ const CompileContext &cc);
#endif // RELEASE_BUILD
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.cpp
index 271e14fb9c3..f1f829f2c11 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,20 +40,20 @@
#include "util/bitutils.h" // for CASE_CLEAR
#include "util/charreach.h"
-#include "util/compile_context.h"
+#include "util/compile_context.h"
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
-#include "util/small_vector.h"
-#include "util/target_info.h"
+#include "util/small_vector.h"
+#include "util/target_info.h"
#include <algorithm>
#include <map>
-#include <boost/range/adaptor/map.hpp>
-
+#include <boost/range/adaptor/map.hpp>
+
using namespace std;
-using boost::adaptors::map_keys;
+using boost::adaptors::map_keys;
namespace ue2 {
@@ -72,7 +72,7 @@ void findAccelFriendGeneration(const NGHolder &g, const CharReach &cr,
}
const CharReach &acr = g[v].char_reach;
- DEBUG_PRINTF("checking %zu\n", g[v].index);
+ DEBUG_PRINTF("checking %zu\n", g[v].index);
if (acr.count() < WIDE_FRIEND_MIN || !acr.isSubsetOf(cr)) {
DEBUG_PRINTF("bad reach %zu\n", acr.count());
@@ -89,7 +89,7 @@ void findAccelFriendGeneration(const NGHolder &g, const CharReach &cr,
next_preds->insert(v);
insert(next_cands, adjacent_vertices(v, g));
- DEBUG_PRINTF("%zu is a friend indeed\n", g[v].index);
+ DEBUG_PRINTF("%zu is a friend indeed\n", g[v].index);
friends->insert(v);
next_cand:;
}
@@ -136,321 +136,321 @@ void findAccelFriends(const NGHolder &g, NFAVertex v,
}
static
-void findPaths(const NGHolder &g, NFAVertex v,
- const vector<CharReach> &refined_cr,
- vector<vector<CharReach>> *paths,
- const flat_set<NFAVertex> &forbidden, u32 depth) {
- static const u32 MAGIC_TOO_WIDE_NUMBER = 16;
- if (!depth) {
- paths->push_back({});
- return;
- }
- if (v == g.accept || v == g.acceptEod) {
- paths->push_back({});
- if (!generates_callbacks(g) || v == g.acceptEod) {
- paths->back().push_back(CharReach()); /* red tape options */
- }
- return;
- }
-
- /* for the escape 'literals' we want to use the minimal cr so we
- * can be more selective */
- const CharReach &cr = refined_cr[g[v].index];
-
- if (out_degree(v, g) >= MAGIC_TOO_WIDE_NUMBER
- || hasSelfLoop(v, g)) {
- /* give up on pushing past this point */
- paths->push_back({cr});
- return;
- }
-
- vector<vector<CharReach>> curr;
+void findPaths(const NGHolder &g, NFAVertex v,
+ const vector<CharReach> &refined_cr,
+ vector<vector<CharReach>> *paths,
+ const flat_set<NFAVertex> &forbidden, u32 depth) {
+ static const u32 MAGIC_TOO_WIDE_NUMBER = 16;
+ if (!depth) {
+ paths->push_back({});
+ return;
+ }
+ if (v == g.accept || v == g.acceptEod) {
+ paths->push_back({});
+ if (!generates_callbacks(g) || v == g.acceptEod) {
+ paths->back().push_back(CharReach()); /* red tape options */
+ }
+ return;
+ }
+
+ /* for the escape 'literals' we want to use the minimal cr so we
+ * can be more selective */
+ const CharReach &cr = refined_cr[g[v].index];
+
+ if (out_degree(v, g) >= MAGIC_TOO_WIDE_NUMBER
+ || hasSelfLoop(v, g)) {
+ /* give up on pushing past this point */
+ paths->push_back({cr});
+ return;
+ }
+
+ vector<vector<CharReach>> curr;
for (auto w : adjacent_vertices_range(v, g)) {
- if (contains(forbidden, w)) {
- /* path has looped back to one of the active+boring acceleration
- * states. We can ignore this path if we have sufficient back-
- * off. */
+ if (contains(forbidden, w)) {
+ /* path has looped back to one of the active+boring acceleration
+ * states. We can ignore this path if we have sufficient back-
+ * off. */
paths->push_back({cr});
continue;
}
-
- u32 new_depth = depth - 1;
- do {
- curr.clear();
- findPaths(g, w, refined_cr, &curr, forbidden, new_depth);
- } while (new_depth-- && curr.size() >= MAGIC_TOO_WIDE_NUMBER);
-
- for (auto &c : curr) {
- c.push_back(cr);
- paths->push_back(std::move(c));
+
+ u32 new_depth = depth - 1;
+ do {
+ curr.clear();
+ findPaths(g, w, refined_cr, &curr, forbidden, new_depth);
+ } while (new_depth-- && curr.size() >= MAGIC_TOO_WIDE_NUMBER);
+
+ for (auto &c : curr) {
+ c.push_back(cr);
+ paths->push_back(std::move(c));
}
}
}
-namespace {
-struct SAccelScheme {
- SAccelScheme(CharReach cr_in, u32 offset_in)
- : cr(std::move(cr_in)), offset(offset_in) {
- assert(offset <= MAX_ACCEL_DEPTH);
+namespace {
+struct SAccelScheme {
+ SAccelScheme(CharReach cr_in, u32 offset_in)
+ : cr(std::move(cr_in)), offset(offset_in) {
+ assert(offset <= MAX_ACCEL_DEPTH);
}
- SAccelScheme() {}
+ SAccelScheme() {}
+
+ bool operator<(const SAccelScheme &b) const {
+ const SAccelScheme &a = *this;
- bool operator<(const SAccelScheme &b) const {
- const SAccelScheme &a = *this;
-
- const size_t a_count = cr.count(), b_count = b.cr.count();
- if (a_count != b_count) {
- return a_count < b_count;
+ const size_t a_count = cr.count(), b_count = b.cr.count();
+ if (a_count != b_count) {
+ return a_count < b_count;
}
- /* TODO: give bonus if one is a 'caseless' character */
- ORDER_CHECK(offset);
- ORDER_CHECK(cr);
+ /* TODO: give bonus if one is a 'caseless' character */
+ ORDER_CHECK(offset);
+ ORDER_CHECK(cr);
return false;
}
- CharReach cr = CharReach::dot();
- u32 offset = MAX_ACCEL_DEPTH + 1;
-};
+ CharReach cr = CharReach::dot();
+ u32 offset = MAX_ACCEL_DEPTH + 1;
+};
}
-/**
- * \brief Limit on the number of (recursive) calls to findBestInternal().
- */
-static constexpr size_t MAX_FINDBEST_CALLS = 1000000;
-
+/**
+ * \brief Limit on the number of (recursive) calls to findBestInternal().
+ */
+static constexpr size_t MAX_FINDBEST_CALLS = 1000000;
+
static
-void findBestInternal(vector<vector<CharReach>>::const_iterator pb,
- vector<vector<CharReach>>::const_iterator pe,
- size_t *num_calls, const SAccelScheme &curr,
- SAccelScheme *best) {
- assert(curr.offset <= MAX_ACCEL_DEPTH);
-
- if (++(*num_calls) > MAX_FINDBEST_CALLS) {
- DEBUG_PRINTF("hit num_calls limit %zu\n", *num_calls);
- return;
- }
-
- DEBUG_PRINTF("paths left %zu\n", pe - pb);
- if (pb == pe) {
- if (curr < *best) {
- *best = curr;
- DEBUG_PRINTF("new best: count=%zu, class=%s, offset=%u\n",
- best->cr.count(), describeClass(best->cr).c_str(),
- best->offset);
- }
- return;
- }
-
- DEBUG_PRINTF("p len %zu\n", pb->end() - pb->begin());
-
- small_vector<SAccelScheme, 10> priority_path;
- priority_path.reserve(pb->size());
- u32 i = 0;
- for (auto p = pb->begin(); p != pb->end(); ++p, i++) {
- SAccelScheme as(*p | curr.cr, max(i, curr.offset));
- if (*best < as) {
- DEBUG_PRINTF("worse\n");
- continue;
- }
- priority_path.push_back(move(as));
- }
-
- sort(priority_path.begin(), priority_path.end());
- for (auto it = priority_path.begin(); it != priority_path.end(); ++it) {
- auto jt = next(it);
- for (; jt != priority_path.end(); ++jt) {
- if (!it->cr.isSubsetOf(jt->cr)) {
- break;
- }
- }
- priority_path.erase(next(it), jt);
- DEBUG_PRINTF("||%zu\n", it->cr.count());
- }
- DEBUG_PRINTF("---\n");
-
- for (const SAccelScheme &in : priority_path) {
- DEBUG_PRINTF("in: count %zu\n", in.cr.count());
- if (*best < in) {
- DEBUG_PRINTF("worse\n");
- continue;
- }
- findBestInternal(pb + 1, pe, num_calls, in, best);
-
- if (curr.cr == best->cr) {
- return; /* could only get better by offset */
- }
+void findBestInternal(vector<vector<CharReach>>::const_iterator pb,
+ vector<vector<CharReach>>::const_iterator pe,
+ size_t *num_calls, const SAccelScheme &curr,
+ SAccelScheme *best) {
+ assert(curr.offset <= MAX_ACCEL_DEPTH);
+
+ if (++(*num_calls) > MAX_FINDBEST_CALLS) {
+ DEBUG_PRINTF("hit num_calls limit %zu\n", *num_calls);
+ return;
+ }
+
+ DEBUG_PRINTF("paths left %zu\n", pe - pb);
+ if (pb == pe) {
+ if (curr < *best) {
+ *best = curr;
+ DEBUG_PRINTF("new best: count=%zu, class=%s, offset=%u\n",
+ best->cr.count(), describeClass(best->cr).c_str(),
+ best->offset);
+ }
+ return;
+ }
+
+ DEBUG_PRINTF("p len %zu\n", pb->end() - pb->begin());
+
+ small_vector<SAccelScheme, 10> priority_path;
+ priority_path.reserve(pb->size());
+ u32 i = 0;
+ for (auto p = pb->begin(); p != pb->end(); ++p, i++) {
+ SAccelScheme as(*p | curr.cr, max(i, curr.offset));
+ if (*best < as) {
+ DEBUG_PRINTF("worse\n");
+ continue;
+ }
+ priority_path.push_back(move(as));
+ }
+
+ sort(priority_path.begin(), priority_path.end());
+ for (auto it = priority_path.begin(); it != priority_path.end(); ++it) {
+ auto jt = next(it);
+ for (; jt != priority_path.end(); ++jt) {
+ if (!it->cr.isSubsetOf(jt->cr)) {
+ break;
+ }
+ }
+ priority_path.erase(next(it), jt);
+ DEBUG_PRINTF("||%zu\n", it->cr.count());
+ }
+ DEBUG_PRINTF("---\n");
+
+ for (const SAccelScheme &in : priority_path) {
+ DEBUG_PRINTF("in: count %zu\n", in.cr.count());
+ if (*best < in) {
+ DEBUG_PRINTF("worse\n");
+ continue;
+ }
+ findBestInternal(pb + 1, pe, num_calls, in, best);
+
+ if (curr.cr == best->cr) {
+ return; /* could only get better by offset */
+ }
}
}
static
-SAccelScheme findBest(const vector<vector<CharReach>> &paths,
- const CharReach &terminating) {
- SAccelScheme curr(terminating, 0U);
- SAccelScheme best;
- size_t num_calls = 0;
- findBestInternal(paths.begin(), paths.end(), &num_calls, curr, &best);
- DEBUG_PRINTF("findBest completed, num_calls=%zu\n", num_calls);
- DEBUG_PRINTF("selected scheme: count=%zu, class=%s, offset=%u\n",
- best.cr.count(), describeClass(best.cr).c_str(), best.offset);
- return best;
-}
-
-namespace {
-struct DAccelScheme {
- DAccelScheme(CharReach cr_in, u32 offset_in)
- : double_cr(std::move(cr_in)), double_offset(offset_in) {
- assert(double_offset <= MAX_ACCEL_DEPTH);
- }
-
- bool operator<(const DAccelScheme &b) const {
- const DAccelScheme &a = *this;
-
- size_t a_dcount = a.double_cr.count();
- size_t b_dcount = b.double_cr.count();
-
- assert(!a.double_byte.empty() || a_dcount || a.double_offset);
- assert(!b.double_byte.empty() || b_dcount || b.double_offset);
-
- if (a_dcount != b_dcount) {
- return a_dcount < b_dcount;
- }
-
- if (!a_dcount) {
- bool cd_a = buildDvermMask(a.double_byte);
- bool cd_b = buildDvermMask(b.double_byte);
- if (cd_a != cd_b) {
- return cd_a > cd_b;
+SAccelScheme findBest(const vector<vector<CharReach>> &paths,
+ const CharReach &terminating) {
+ SAccelScheme curr(terminating, 0U);
+ SAccelScheme best;
+ size_t num_calls = 0;
+ findBestInternal(paths.begin(), paths.end(), &num_calls, curr, &best);
+ DEBUG_PRINTF("findBest completed, num_calls=%zu\n", num_calls);
+ DEBUG_PRINTF("selected scheme: count=%zu, class=%s, offset=%u\n",
+ best.cr.count(), describeClass(best.cr).c_str(), best.offset);
+ return best;
+}
+
+namespace {
+struct DAccelScheme {
+ DAccelScheme(CharReach cr_in, u32 offset_in)
+ : double_cr(std::move(cr_in)), double_offset(offset_in) {
+ assert(double_offset <= MAX_ACCEL_DEPTH);
+ }
+
+ bool operator<(const DAccelScheme &b) const {
+ const DAccelScheme &a = *this;
+
+ size_t a_dcount = a.double_cr.count();
+ size_t b_dcount = b.double_cr.count();
+
+ assert(!a.double_byte.empty() || a_dcount || a.double_offset);
+ assert(!b.double_byte.empty() || b_dcount || b.double_offset);
+
+ if (a_dcount != b_dcount) {
+ return a_dcount < b_dcount;
+ }
+
+ if (!a_dcount) {
+ bool cd_a = buildDvermMask(a.double_byte);
+ bool cd_b = buildDvermMask(b.double_byte);
+ if (cd_a != cd_b) {
+ return cd_a > cd_b;
}
}
- ORDER_CHECK(double_byte.size());
- ORDER_CHECK(double_offset);
+ ORDER_CHECK(double_byte.size());
+ ORDER_CHECK(double_offset);
- /* TODO: give bonus if one is a 'caseless' character */
- ORDER_CHECK(double_byte);
- ORDER_CHECK(double_cr);
+ /* TODO: give bonus if one is a 'caseless' character */
+ ORDER_CHECK(double_byte);
+ ORDER_CHECK(double_cr);
- return false;
+ return false;
}
- flat_set<pair<u8, u8>> double_byte;
- CharReach double_cr;
- u32 double_offset = 0;
-};
+ flat_set<pair<u8, u8>> double_byte;
+ CharReach double_cr;
+ u32 double_offset = 0;
+};
}
static
-DAccelScheme make_double_accel(DAccelScheme as, CharReach cr_1,
- const CharReach &cr_2_in, u32 offset_in) {
- cr_1 &= ~as.double_cr;
- CharReach cr_2 = cr_2_in & ~as.double_cr;
- u32 offset = offset_in;
-
- if (cr_1.none()) {
- DEBUG_PRINTF("empty first element\n");
- ENSURE_AT_LEAST(&as.double_offset, offset);
- return as;
- }
-
- if (cr_2_in != cr_2 || cr_2.none()) {
- offset = offset_in + 1;
- }
-
- size_t two_count = cr_1.count() * cr_2.count();
-
- DEBUG_PRINTF("will generate raw %zu pairs\n", two_count);
-
- if (!two_count) {
- DEBUG_PRINTF("empty element\n");
- ENSURE_AT_LEAST(&as.double_offset, offset);
- return as;
- }
-
- if (two_count > DOUBLE_SHUFTI_LIMIT) {
- if (cr_2.count() < cr_1.count()) {
- as.double_cr |= cr_2;
- offset = offset_in + 1;
- } else {
- as.double_cr |= cr_1;
- }
- } else {
- for (auto i = cr_1.find_first(); i != CharReach::npos;
- i = cr_1.find_next(i)) {
- for (auto j = cr_2.find_first(); j != CharReach::npos;
- j = cr_2.find_next(j)) {
- as.double_byte.emplace(i, j);
- }
- }
- }
-
- ENSURE_AT_LEAST(&as.double_offset, offset);
- DEBUG_PRINTF("construct da %zu pairs, %zu singles, offset %u\n",
- as.double_byte.size(), as.double_cr.count(), as.double_offset);
- return as;
+DAccelScheme make_double_accel(DAccelScheme as, CharReach cr_1,
+ const CharReach &cr_2_in, u32 offset_in) {
+ cr_1 &= ~as.double_cr;
+ CharReach cr_2 = cr_2_in & ~as.double_cr;
+ u32 offset = offset_in;
+
+ if (cr_1.none()) {
+ DEBUG_PRINTF("empty first element\n");
+ ENSURE_AT_LEAST(&as.double_offset, offset);
+ return as;
+ }
+
+ if (cr_2_in != cr_2 || cr_2.none()) {
+ offset = offset_in + 1;
+ }
+
+ size_t two_count = cr_1.count() * cr_2.count();
+
+ DEBUG_PRINTF("will generate raw %zu pairs\n", two_count);
+
+ if (!two_count) {
+ DEBUG_PRINTF("empty element\n");
+ ENSURE_AT_LEAST(&as.double_offset, offset);
+ return as;
+ }
+
+ if (two_count > DOUBLE_SHUFTI_LIMIT) {
+ if (cr_2.count() < cr_1.count()) {
+ as.double_cr |= cr_2;
+ offset = offset_in + 1;
+ } else {
+ as.double_cr |= cr_1;
+ }
+ } else {
+ for (auto i = cr_1.find_first(); i != CharReach::npos;
+ i = cr_1.find_next(i)) {
+ for (auto j = cr_2.find_first(); j != CharReach::npos;
+ j = cr_2.find_next(j)) {
+ as.double_byte.emplace(i, j);
+ }
+ }
+ }
+
+ ENSURE_AT_LEAST(&as.double_offset, offset);
+ DEBUG_PRINTF("construct da %zu pairs, %zu singles, offset %u\n",
+ as.double_byte.size(), as.double_cr.count(), as.double_offset);
+ return as;
}
static
-void findDoubleBest(vector<vector<CharReach> >::const_iterator pb,
+void findDoubleBest(vector<vector<CharReach> >::const_iterator pb,
vector<vector<CharReach> >::const_iterator pe,
- const DAccelScheme &curr, DAccelScheme *best) {
- assert(curr.double_offset <= MAX_ACCEL_DEPTH);
+ const DAccelScheme &curr, DAccelScheme *best) {
+ assert(curr.double_offset <= MAX_ACCEL_DEPTH);
DEBUG_PRINTF("paths left %zu\n", pe - pb);
- DEBUG_PRINTF("current base: %zu pairs, %zu singles, offset %u\n",
- curr.double_byte.size(), curr.double_cr.count(),
- curr.double_offset);
+ DEBUG_PRINTF("current base: %zu pairs, %zu singles, offset %u\n",
+ curr.double_byte.size(), curr.double_cr.count(),
+ curr.double_offset);
if (pb == pe) {
- if (curr < *best) {
- *best = curr;
- DEBUG_PRINTF("new best: %zu pairs, %zu singles, offset %u\n",
- best->double_byte.size(), best->double_cr.count(),
- best->double_offset);
- }
+ if (curr < *best) {
+ *best = curr;
+ DEBUG_PRINTF("new best: %zu pairs, %zu singles, offset %u\n",
+ best->double_byte.size(), best->double_cr.count(),
+ best->double_offset);
+ }
return;
}
DEBUG_PRINTF("p len %zu\n", pb->end() - pb->begin());
- small_vector<DAccelScheme, 10> priority_path;
- priority_path.reserve(pb->size());
+ small_vector<DAccelScheme, 10> priority_path;
+ priority_path.reserve(pb->size());
u32 i = 0;
- for (auto p = pb->begin(); p != pb->end() && next(p) != pb->end();
+ for (auto p = pb->begin(); p != pb->end() && next(p) != pb->end();
++p, i++) {
- DAccelScheme as = make_double_accel(curr, *p, *next(p), i);
- if (*best < as) {
- DEBUG_PRINTF("worse\n");
- continue;
- }
- priority_path.push_back(move(as));
+ DAccelScheme as = make_double_accel(curr, *p, *next(p), i);
+ if (*best < as) {
+ DEBUG_PRINTF("worse\n");
+ continue;
+ }
+ priority_path.push_back(move(as));
}
sort(priority_path.begin(), priority_path.end());
- DEBUG_PRINTF("%zu candidates for this path\n", priority_path.size());
- DEBUG_PRINTF("input best: %zu pairs, %zu singles, offset %u\n",
- best->double_byte.size(), best->double_cr.count(),
- best->double_offset);
-
- for (const DAccelScheme &in : priority_path) {
- DEBUG_PRINTF("in: %zu pairs, %zu singles, offset %u\n",
- in.double_byte.size(), in.double_cr.count(),
- in.double_offset);
- if (*best < in) {
+ DEBUG_PRINTF("%zu candidates for this path\n", priority_path.size());
+ DEBUG_PRINTF("input best: %zu pairs, %zu singles, offset %u\n",
+ best->double_byte.size(), best->double_cr.count(),
+ best->double_offset);
+
+ for (const DAccelScheme &in : priority_path) {
+ DEBUG_PRINTF("in: %zu pairs, %zu singles, offset %u\n",
+ in.double_byte.size(), in.double_cr.count(),
+ in.double_offset);
+ if (*best < in) {
DEBUG_PRINTF("worse\n");
continue;
}
- findDoubleBest(pb + 1, pe, in, best);
+ findDoubleBest(pb + 1, pe, in, best);
}
}
#ifdef DEBUG
static
-void dumpPaths(const vector<vector<CharReach>> &paths) {
- for (const auto &path : paths) {
+void dumpPaths(const vector<vector<CharReach>> &paths) {
+ for (const auto &path : paths) {
DEBUG_PRINTF("path: [");
- for (const auto &cr : path) {
+ for (const auto &cr : path) {
printf(" [");
- describeClass(stdout, cr, 20, CC_OUT_TEXT);
+ describeClass(stdout, cr, 20, CC_OUT_TEXT);
printf("]");
}
printf(" ]\n");
@@ -459,13 +459,13 @@ void dumpPaths(const vector<vector<CharReach>> &paths) {
#endif
static
-void blowoutPathsLessStrictSegment(vector<vector<CharReach> > &paths) {
+void blowoutPathsLessStrictSegment(vector<vector<CharReach> > &paths) {
/* paths segments which are a superset of an earlier segment should never be
* picked as an acceleration segment -> to improve processing just replace
* with dot */
- for (auto &p : paths) {
- for (auto it = p.begin(); it != p.end(); ++it) {
- for (auto jt = next(it); jt != p.end(); ++jt) {
+ for (auto &p : paths) {
+ for (auto it = p.begin(); it != p.end(); ++it) {
+ for (auto jt = next(it); jt != p.end(); ++jt) {
if (it->isSubsetOf(*jt)) {
*jt = CharReach::dot();
}
@@ -475,10 +475,10 @@ void blowoutPathsLessStrictSegment(vector<vector<CharReach> > &paths) {
}
static
-void unifyPathsLastSegment(vector<vector<CharReach> > &paths) {
+void unifyPathsLastSegment(vector<vector<CharReach> > &paths) {
/* try to unify paths which only differ in the last segment */
- for (vector<vector<CharReach> >::iterator p = paths.begin();
- p != paths.end() && p + 1 != paths.end();) {
+ for (vector<vector<CharReach> >::iterator p = paths.begin();
+ p != paths.end() && p + 1 != paths.end();) {
vector<CharReach> &a = *p;
vector<CharReach> &b = *(p + 1);
@@ -496,7 +496,7 @@ void unifyPathsLastSegment(vector<vector<CharReach> > &paths) {
if (i == a.size() - 1) {
/* we can unify these paths */
a[i] |= b[i];
- paths.erase(p + 1);
+ paths.erase(p + 1);
} else {
++p;
}
@@ -504,117 +504,117 @@ void unifyPathsLastSegment(vector<vector<CharReach> > &paths) {
}
static
-void improvePaths(vector<vector<CharReach> > &paths) {
+void improvePaths(vector<vector<CharReach> > &paths) {
#ifdef DEBUG
DEBUG_PRINTF("orig paths\n");
- dumpPaths(paths);
+ dumpPaths(paths);
#endif
blowoutPathsLessStrictSegment(paths);
- sort(paths.begin(), paths.end());
+ sort(paths.begin(), paths.end());
unifyPathsLastSegment(paths);
#ifdef DEBUG
DEBUG_PRINTF("opt paths\n");
- dumpPaths(paths);
+ dumpPaths(paths);
#endif
}
-#define MAX_DOUBLE_ACCEL_PATHS 10
-
-static
-DAccelScheme findBestDoubleAccelScheme(vector<vector<CharReach> > paths,
- const CharReach &terminating) {
- DEBUG_PRINTF("looking for double accel, %zu terminating symbols\n",
- terminating.count());
- unifyPathsLastSegment(paths);
-
-#ifdef DEBUG
- DEBUG_PRINTF("paths:\n");
- dumpPaths(paths);
-#endif
-
- /* if there are too many paths, shorten the paths to reduce the number of
- * distinct paths we have to consider */
- while (paths.size() > MAX_DOUBLE_ACCEL_PATHS) {
- for (auto &p : paths) {
- if (p.empty()) {
- return DAccelScheme(terminating, 0U);
- }
- p.pop_back();
- }
- unifyPathsLastSegment(paths);
- }
-
- if (paths.empty()) {
- return DAccelScheme(terminating, 0U);
- }
-
- DAccelScheme curr(terminating, 0U);
- DAccelScheme best(CharReach::dot(), 0U);
- findDoubleBest(paths.begin(), paths.end(), curr, &best);
- DEBUG_PRINTF("da %zu pairs, %zu singles\n", best.double_byte.size(),
- best.double_cr.count());
- return best;
-}
-
-#define MAX_EXPLORE_PATHS 40
-
-AccelScheme findBestAccelScheme(vector<vector<CharReach>> paths,
- const CharReach &terminating,
- bool look_for_double_byte) {
- AccelScheme rv;
- if (look_for_double_byte) {
- DAccelScheme da = findBestDoubleAccelScheme(paths, terminating);
- if (da.double_byte.size() <= DOUBLE_SHUFTI_LIMIT) {
- rv.double_byte = std::move(da.double_byte);
- rv.double_cr = move(da.double_cr);
- rv.double_offset = da.double_offset;
- }
- }
-
- improvePaths(paths);
-
- DEBUG_PRINTF("we have %zu paths\n", paths.size());
- if (paths.size() > MAX_EXPLORE_PATHS) {
- return rv; /* too many paths to explore */
- }
-
- /* if we were smart we would do something netflowy on the paths to find the
- * best cut. But we aren't, so we will just brute force it.
- */
- SAccelScheme best = findBest(paths, terminating);
-
- /* find best is a bit lazy in terms of minimising the offset, see if we can
- * make it better. need to find the min max offset that we need.*/
- u32 offset = 0;
- for (const auto &path : paths) {
- u32 i = 0;
- for (const auto &cr : path) {
- if (cr.isSubsetOf(best.cr)) {
- break;
- }
- i++;
- }
- offset = MAX(offset, i);
- }
- assert(offset <= best.offset);
- best.offset = offset;
-
- rv.offset = best.offset;
- rv.cr = best.cr;
- if (rv.cr.count() < rv.double_cr.count()) {
- rv.double_byte.clear();
- }
-
- return rv;
-}
-
+#define MAX_DOUBLE_ACCEL_PATHS 10
+
+static
+DAccelScheme findBestDoubleAccelScheme(vector<vector<CharReach> > paths,
+ const CharReach &terminating) {
+ DEBUG_PRINTF("looking for double accel, %zu terminating symbols\n",
+ terminating.count());
+ unifyPathsLastSegment(paths);
+
+#ifdef DEBUG
+ DEBUG_PRINTF("paths:\n");
+ dumpPaths(paths);
+#endif
+
+ /* if there are too many paths, shorten the paths to reduce the number of
+ * distinct paths we have to consider */
+ while (paths.size() > MAX_DOUBLE_ACCEL_PATHS) {
+ for (auto &p : paths) {
+ if (p.empty()) {
+ return DAccelScheme(terminating, 0U);
+ }
+ p.pop_back();
+ }
+ unifyPathsLastSegment(paths);
+ }
+
+ if (paths.empty()) {
+ return DAccelScheme(terminating, 0U);
+ }
+
+ DAccelScheme curr(terminating, 0U);
+ DAccelScheme best(CharReach::dot(), 0U);
+ findDoubleBest(paths.begin(), paths.end(), curr, &best);
+ DEBUG_PRINTF("da %zu pairs, %zu singles\n", best.double_byte.size(),
+ best.double_cr.count());
+ return best;
+}
+
+#define MAX_EXPLORE_PATHS 40
+
+AccelScheme findBestAccelScheme(vector<vector<CharReach>> paths,
+ const CharReach &terminating,
+ bool look_for_double_byte) {
+ AccelScheme rv;
+ if (look_for_double_byte) {
+ DAccelScheme da = findBestDoubleAccelScheme(paths, terminating);
+ if (da.double_byte.size() <= DOUBLE_SHUFTI_LIMIT) {
+ rv.double_byte = std::move(da.double_byte);
+ rv.double_cr = move(da.double_cr);
+ rv.double_offset = da.double_offset;
+ }
+ }
+
+ improvePaths(paths);
+
+ DEBUG_PRINTF("we have %zu paths\n", paths.size());
+ if (paths.size() > MAX_EXPLORE_PATHS) {
+ return rv; /* too many paths to explore */
+ }
+
+ /* if we were smart we would do something netflowy on the paths to find the
+ * best cut. But we aren't, so we will just brute force it.
+ */
+ SAccelScheme best = findBest(paths, terminating);
+
+ /* find best is a bit lazy in terms of minimising the offset, see if we can
+ * make it better. need to find the min max offset that we need.*/
+ u32 offset = 0;
+ for (const auto &path : paths) {
+ u32 i = 0;
+ for (const auto &cr : path) {
+ if (cr.isSubsetOf(best.cr)) {
+ break;
+ }
+ i++;
+ }
+ offset = MAX(offset, i);
+ }
+ assert(offset <= best.offset);
+ best.offset = offset;
+
+ rv.offset = best.offset;
+ rv.cr = best.cr;
+ if (rv.cr.count() < rv.double_cr.count()) {
+ rv.double_byte.clear();
+ }
+
+ return rv;
+}
+
AccelScheme nfaFindAccel(const NGHolder &g, const vector<NFAVertex> &verts,
const vector<CharReach> &refined_cr,
const map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
- bool allow_wide, bool look_for_double_byte) {
+ bool allow_wide, bool look_for_double_byte) {
CharReach terminating;
for (auto v : verts) {
if (!hasSelfLoop(v, g)) {
@@ -633,15 +633,15 @@ AccelScheme nfaFindAccel(const NGHolder &g, const vector<NFAVertex> &verts,
return AccelScheme(); /* invalid scheme */
}
- vector<vector<CharReach>> paths;
+ vector<vector<CharReach>> paths;
flat_set<NFAVertex> ignore_vert_set(verts.begin(), verts.end());
/* Note: we can not in general (TODO: ignore when possible) ignore entries
* into the bounded repeat cyclic states as that is when the magic happens
*/
- for (auto v : br_cyclic | map_keys) {
+ for (auto v : br_cyclic | map_keys) {
/* TODO: can allow if repeatMin <= 1 ? */
- ignore_vert_set.erase(v);
+ ignore_vert_set.erase(v);
}
for (auto v : verts) {
@@ -654,12 +654,12 @@ AccelScheme nfaFindAccel(const NGHolder &g, const vector<NFAVertex> &verts,
}
/* paths built wrong: reverse them */
- for (auto &path : paths) {
- reverse(path.begin(), path.end());
+ for (auto &path : paths) {
+ reverse(path.begin(), path.end());
}
- return findBestAccelScheme(std::move(paths), terminating,
- look_for_double_byte);
+ return findBestAccelScheme(std::move(paths), terminating,
+ look_for_double_byte);
}
NFAVertex get_sds_or_proxy(const NGHolder &g) {
@@ -668,7 +668,7 @@ NFAVertex get_sds_or_proxy(const NGHolder &g) {
return g.startDs;
}
- NFAVertex v = NGHolder::null_vertex();
+ NFAVertex v = NGHolder::null_vertex();
for (auto w : adjacent_vertices_range(g.start, g)) {
if (w != g.startDs) {
if (!v) {
@@ -685,7 +685,7 @@ NFAVertex get_sds_or_proxy(const NGHolder &g) {
while (true) {
if (hasSelfLoop(v, g)) {
- DEBUG_PRINTF("woot %zu\n", g[v].index);
+ DEBUG_PRINTF("woot %zu\n", g[v].index);
return v;
}
if (out_degree(v, g) != 1) {
@@ -719,7 +719,7 @@ bool nfaCheckAccel(const NGHolder &g, NFAVertex v,
CharReach terminating = g[v].char_reach;
terminating.flip();
- DEBUG_PRINTF("vertex %zu is cyclic and has %zu stop chars%s\n",
+ DEBUG_PRINTF("vertex %zu is cyclic and has %zu stop chars%s\n",
g[v].index, terminating.count(),
allow_wide ? " (w)" : "");
@@ -789,9 +789,9 @@ depth_done:
for (unsigned int i = 0; i < depth; i++) {
if (depthReach[i].none()) {
DEBUG_PRINTF("red tape acceleration engine depth %u\n", i);
- *as = AccelScheme();
- as->offset = i;
- as->cr = CharReach();
+ *as = AccelScheme();
+ as->offset = i;
+ as->cr = CharReach();
return true;
}
}
@@ -806,8 +806,8 @@ depth_done:
|| (cra.count() == 2 && crb.count() == 2
&& cra.isBit5Insensitive() && crb.isBit5Insensitive())) {
DEBUG_PRINTF("two-byte vermicelli, depth %u\n", i);
- *as = AccelScheme();
- as->offset = i;
+ *as = AccelScheme();
+ as->offset = i;
return true;
}
}
@@ -817,19 +817,19 @@ depth_done:
// literals)
if (depth > 1) {
for (unsigned int i = 0; i < (depth - 1); i++) {
- if (depthReach[i].count() * depthReach[i+1].count()
- <= DOUBLE_SHUFTI_LIMIT) {
+ if (depthReach[i].count() * depthReach[i+1].count()
+ <= DOUBLE_SHUFTI_LIMIT) {
DEBUG_PRINTF("two-byte shufti, depth %u\n", i);
- *as = AccelScheme();
- as->offset = i;
+ *as = AccelScheme();
+ as->offset = i;
return true;
}
}
}
- // Look for offset accel schemes verm/shufti;
+ // Look for offset accel schemes verm/shufti;
vector<NFAVertex> verts(1, v);
- *as = nfaFindAccel(g, verts, refined_cr, br_cyclic, allow_wide, true);
+ *as = nfaFindAccel(g, verts, refined_cr, br_cyclic, allow_wide, true);
DEBUG_PRINTF("as width %zu\n", as->cr.count());
return as->cr.count() <= ACCEL_MAX_STOP_CHAR || allow_wide;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.h b/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.h
index c6eed0d1688..f6f7f1b3cb7 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_limex_accel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,10 +36,10 @@
#include "ng_holder.h"
#include "ng_misc_opt.h"
#include "ue2common.h"
-#include "nfa/accelcompile.h"
-#include "util/accel_scheme.h"
+#include "nfa/accelcompile.h"
+#include "util/accel_scheme.h"
#include "util/charreach.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/order_check.h"
#include <map>
@@ -52,35 +52,35 @@ namespace ue2 {
#define ACCEL_MAX_STOP_CHAR 24
#define ACCEL_MAX_FLOATING_STOP_CHAR 192 /* accelerating sds is important */
-// forward-declaration of CompileContext
-struct CompileContext;
-
+// forward-declaration of CompileContext
+struct CompileContext;
+
void findAccelFriends(const NGHolder &g, NFAVertex v,
const std::map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
- u32 offset, flat_set<NFAVertex> *friends);
+ u32 offset, flat_set<NFAVertex> *friends);
-#define DOUBLE_SHUFTI_LIMIT 20
+#define DOUBLE_SHUFTI_LIMIT 20
NFAVertex get_sds_or_proxy(const NGHolder &g);
AccelScheme nfaFindAccel(const NGHolder &g, const std::vector<NFAVertex> &verts,
const std::vector<CharReach> &refined_cr,
const std::map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
- bool allow_wide, bool look_for_double_byte = false);
-
-AccelScheme findBestAccelScheme(std::vector<std::vector<CharReach> > paths,
- const CharReach &terminating,
- bool look_for_double_byte = false);
-
-/** \brief Check if vertex \a v is an accelerable state (for a limex NFA). If a
- * single byte accel scheme is found it is placed into *as
- */
+ bool allow_wide, bool look_for_double_byte = false);
+
+AccelScheme findBestAccelScheme(std::vector<std::vector<CharReach> > paths,
+ const CharReach &terminating,
+ bool look_for_double_byte = false);
+
+/** \brief Check if vertex \a v is an accelerable state (for a limex NFA). If a
+ * single byte accel scheme is found it is placed into *as
+ */
bool nfaCheckAccel(const NGHolder &g, NFAVertex v,
const std::vector<CharReach> &refined_cr,
const std::map<NFAVertex, BoundedRepeatSummary> &br_cyclic,
AccelScheme *as, bool allow_wide);
-
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.cpp
index e7b9db416f9..d25ac43e875 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,8 +40,8 @@
#include "util/depth.h"
#include "util/graph.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
-#include "util/ue2_graph.h"
+#include "util/graph_small_color_map.h"
+#include "util/ue2_graph.h"
#include "util/ue2string.h"
#include <algorithm>
@@ -66,31 +66,31 @@ namespace {
* compressAndScore. */
struct LitGraphVertexProps {
- LitGraphVertexProps() = default;
- explicit LitGraphVertexProps(ue2_literal::elem c_in) : c(move(c_in)) {}
+ LitGraphVertexProps() = default;
+ explicit LitGraphVertexProps(ue2_literal::elem c_in) : c(move(c_in)) {}
ue2_literal::elem c; // string element (char + bool)
size_t index = 0; // managed by ue2_graph
};
struct LitGraphEdgeProps {
- LitGraphEdgeProps() = default;
+ LitGraphEdgeProps() = default;
explicit LitGraphEdgeProps(u64a score_in) : score(score_in) {}
u64a score = NO_LITERAL_AT_EDGE_SCORE;
size_t index = 0; // managed by ue2_graph
};
-struct LitGraph
- : public ue2_graph<LitGraph, LitGraphVertexProps, LitGraphEdgeProps> {
-
- LitGraph() : root(add_vertex(*this)), sink(add_vertex(*this)) {}
-
- const vertex_descriptor root;
- const vertex_descriptor sink;
-};
-
-typedef LitGraph::vertex_descriptor LitVertex;
-typedef LitGraph::edge_descriptor LitEdge;
-
+struct LitGraph
+ : public ue2_graph<LitGraph, LitGraphVertexProps, LitGraphEdgeProps> {
+
+ LitGraph() : root(add_vertex(*this)), sink(add_vertex(*this)) {}
+
+ const vertex_descriptor root;
+ const vertex_descriptor sink;
+};
+
+typedef LitGraph::vertex_descriptor LitVertex;
+typedef LitGraph::edge_descriptor LitEdge;
+
typedef pair<LitVertex, NFAVertex> VertexPair;
typedef std::queue<VertexPair> LitVertexQ;
@@ -100,16 +100,16 @@ typedef std::queue<VertexPair> LitVertexQ;
/** \brief Dump the literal graph in Graphviz format. */
static UNUSED
-void dumpGraph(const char *filename, const LitGraph &lg) {
+void dumpGraph(const char *filename, const LitGraph &lg) {
ofstream fout(filename);
fout << "digraph G {" << endl;
for (auto v : vertices_range(lg)) {
- fout << lg[v].index;
- if (v == lg.root) {
+ fout << lg[v].index;
+ if (v == lg.root) {
fout << "[label=\"ROOT\"];";
- } else if (v == lg.sink) {
+ } else if (v == lg.sink) {
fout << "[label=\"SINK\"];";
} else {
ue2_literal s;
@@ -121,9 +121,9 @@ void dumpGraph(const char *filename, const LitGraph &lg) {
for (const auto &e : edges_range(lg)) {
LitVertex u = source(e, lg), v = target(e, lg);
- fout << lg[u].index << " -> " << lg[v].index << "[label=\""
- << lg[e].score << "\"]"
- << ";" << endl;
+ fout << lg[u].index << " -> " << lg[v].index << "[label=\""
+ << lg[e].score << "\"]"
+ << ";" << endl;
}
fout << "}" << endl;
@@ -145,11 +145,11 @@ bool allowExpand(size_t numItems, size_t totalPathsSoFar) {
}
static
-LitVertex addToLitGraph(LitGraph &lg, LitVertex pred,
- const ue2_literal::elem &c) {
+LitVertex addToLitGraph(LitGraph &lg, LitVertex pred,
+ const ue2_literal::elem &c) {
// Check if we already have this in the graph.
for (auto v : adjacent_vertices_range(pred, lg)) {
- if (v == lg.sink) {
+ if (v == lg.sink) {
continue;
}
if (lg[v].c == c) {
@@ -163,10 +163,10 @@ LitVertex addToLitGraph(LitGraph &lg, LitVertex pred,
}
static
-void addToQueue(LitVertexQ &workQ, LitGraph &lg, LitVertex pred,
- const CharReach &cr, NFAVertex v) {
- for (size_t i = cr.find_first(); i != CharReach::npos;
- i = cr.find_next(i)) {
+void addToQueue(LitVertexQ &workQ, LitGraph &lg, LitVertex pred,
+ const CharReach &cr, NFAVertex v) {
+ for (size_t i = cr.find_first(); i != CharReach::npos;
+ i = cr.find_next(i)) {
if (myisupper(i) && cr.test(mytolower(i))) {
// ignore upper half of a nocase pair
continue;
@@ -174,14 +174,14 @@ void addToQueue(LitVertexQ &workQ, LitGraph &lg, LitVertex pred,
bool nocase = myislower(i) && cr.test(mytoupper(i));
ue2_literal::elem c((char)i, nocase);
- LitVertex lv = addToLitGraph(lg, pred, c);
+ LitVertex lv = addToLitGraph(lg, pred, c);
workQ.push(VertexPair(lv, v));
}
}
static
-void initWorkQueue(LitVertexQ &workQ, LitGraph &lg, const NGHolder &g,
- const NFAEdge &e) {
+void initWorkQueue(LitVertexQ &workQ, LitGraph &lg, const NGHolder &g,
+ const NFAEdge &e) {
NFAVertex u = source(e, g);
NFAVertex v = target(e, g);
const CharReach &cr = g[v].char_reach;
@@ -190,7 +190,7 @@ void initWorkQueue(LitVertexQ &workQ, LitGraph &lg, const NGHolder &g,
return;
}
- addToQueue(workQ, lg, lg.root, cr, u);
+ addToQueue(workQ, lg, lg.root, cr, u);
}
static
@@ -202,8 +202,8 @@ u32 crCardinality(const CharReach &cr) {
}
u32 rv = 0;
- for (size_t i = cr.find_first(); i != CharReach::npos;
- i = cr.find_next(i)) {
+ for (size_t i = cr.find_first(); i != CharReach::npos;
+ i = cr.find_next(i)) {
if (myisupper(i) && cr.test(mytolower(i))) {
// ignore upper half of a nocase pair
continue;
@@ -218,10 +218,10 @@ u32 crCardinality(const CharReach &cr) {
* identifying vertices connected to the sink and removing their other
* out-edges. */
static
-void filterLitGraph(LitGraph &lg) {
- for (auto v : inv_adjacent_vertices_range(lg.sink, lg)) {
- remove_out_edge_if(v, [&lg](const LitEdge &e) {
- return target(e, lg) != lg.sink;
+void filterLitGraph(LitGraph &lg) {
+ for (auto v : inv_adjacent_vertices_range(lg.sink, lg)) {
+ remove_out_edge_if(v, [&lg](const LitEdge &e) {
+ return target(e, lg) != lg.sink;
}, lg);
}
@@ -234,12 +234,12 @@ void filterLitGraph(LitGraph &lg) {
* from each predecessor of the sink (note: it's a suffix tree except for this
* convenience) towards the source, storing each string as we go. */
static
-void extractLiterals(const LitGraph &lg, set<ue2_literal> &s) {
+void extractLiterals(const LitGraph &lg, set<ue2_literal> &s) {
ue2_literal lit;
- for (auto u : inv_adjacent_vertices_range(lg.sink, lg)) {
+ for (auto u : inv_adjacent_vertices_range(lg.sink, lg)) {
lit.clear();
- while (u != lg.root) {
+ while (u != lg.root) {
lit.push_back(lg[u].c);
assert(in_degree(u, lg) <= 1);
LitGraph::inv_adjacency_iterator ai2, ae2;
@@ -283,7 +283,7 @@ void processWorkQueue(const NGHolder &g, const NFAEdge &e,
LitGraph lg;
LitVertexQ workQ;
- initWorkQueue(workQ, lg, g, e);
+ initWorkQueue(workQ, lg, g, e);
while (!workQ.empty()) {
const LitVertex lv = workQ.front().first;
@@ -292,18 +292,18 @@ void processWorkQueue(const NGHolder &g, const NFAEdge &e,
u32 cr_card = crCardinality(cr);
size_t numItems = cr_card * in_degree(t, g);
- size_t committed_count = workQ.size() + in_degree(lg.sink, lg) - 1;
+ size_t committed_count = workQ.size() + in_degree(lg.sink, lg) - 1;
if (g[t].index == NODE_START) {
// reached start, add to literal set
- add_edge_if_not_present(lv, lg.sink, lg);
+ add_edge_if_not_present(lv, lg.sink, lg);
goto next_work_elem;
}
// Expand next vertex
if (allowExpand(numItems, committed_count)) {
for (auto u : inv_adjacent_vertices_range(t, g)) {
- addToQueue(workQ, lg, lv, cr, u);
+ addToQueue(workQ, lg, lv, cr, u);
}
goto next_work_elem;
}
@@ -319,35 +319,35 @@ void processWorkQueue(const NGHolder &g, const NFAEdge &e,
bool nocase = myislower(i) && cr.test(mytoupper(i));
ue2_literal::elem c((char)i, nocase);
- LitVertex lt = addToLitGraph(lg, lv, c);
- add_edge_if_not_present(lt, lg.sink, lg);
+ LitVertex lt = addToLitGraph(lg, lv, c);
+ add_edge_if_not_present(lt, lg.sink, lg);
}
goto next_work_elem;
}
// add to literal set
- add_edge_if_not_present(lv, lg.sink, lg);
+ add_edge_if_not_present(lv, lg.sink, lg);
next_work_elem:
workQ.pop();
}
- filterLitGraph(lg);
- //dumpGraph("litgraph.dot", lg);
- extractLiterals(lg, s);
+ filterLitGraph(lg);
+ //dumpGraph("litgraph.dot", lg);
+ extractLiterals(lg, s);
// Our literal set should contain no literal that is a suffix of another.
assert(!hasSuffixLiterals(s));
- DEBUG_PRINTF("edge %zu (%zu->%zu) produced %zu literals\n", g[e].index,
+ DEBUG_PRINTF("edge %zu (%zu->%zu) produced %zu literals\n", g[e].index,
g[source(e, g)].index, g[target(e, g)].index, s.size());
}
-bool bad_mixed_sensitivity(const ue2_literal &s) {
- /* TODO: if the mixed cases is entirely within MAX_MASK2_WIDTH of the end,
- * we should be able to handle it */
- return mixed_sensitivity(s) && s.length() > MAX_MASK2_WIDTH;
-}
-
+bool bad_mixed_sensitivity(const ue2_literal &s) {
+ /* TODO: if the mixed cases is entirely within MAX_MASK2_WIDTH of the end,
+ * we should be able to handle it */
+ return mixed_sensitivity(s) && s.length() > MAX_MASK2_WIDTH;
+}
+
static
u64a litUniqueness(const string &s) {
CharReach seen(s);
@@ -412,15 +412,15 @@ u64a calculateScore(const ue2_literal &s) {
/** Adds a literal in reverse order, building up a suffix tree. */
static
-void addReversedLiteral(const ue2_literal &lit, LitGraph &lg) {
+void addReversedLiteral(const ue2_literal &lit, LitGraph &lg) {
DEBUG_PRINTF("literal: '%s'\n", escapeString(lit).c_str());
ue2_literal suffix;
- LitVertex v = lg.root;
+ LitVertex v = lg.root;
for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) {
suffix.push_back(*it);
LitVertex w;
for (auto v2 : adjacent_vertices_range(v, lg)) {
- if (v2 != lg.sink && lg[v2].c == *it) {
+ if (v2 != lg.sink && lg[v2].c == *it) {
w = v2;
goto next_char;
}
@@ -432,18 +432,18 @@ next_char:
}
// Wire the last vertex to the sink.
- add_edge(v, lg.sink, lg);
+ add_edge(v, lg.sink, lg);
}
static
void extractLiterals(const vector<LitEdge> &cutset, const LitGraph &lg,
- set<ue2_literal> &s) {
+ set<ue2_literal> &s) {
for (const auto &e : cutset) {
- LitVertex u = source(e, lg);
- LitVertex v = target(e, lg);
+ LitVertex u = source(e, lg);
+ LitVertex v = target(e, lg);
ue2_literal lit;
lit.push_back(lg[v].c);
- while (u != lg.root) {
+ while (u != lg.root) {
lit.push_back(lg[u].c);
assert(in_degree(u, lg) == 1);
LitGraph::inv_adjacency_iterator ai, ae;
@@ -463,13 +463,13 @@ next_literal:
#ifdef DEBUG
static UNUSED
-const char *describeColor(small_color c) {
+const char *describeColor(small_color c) {
switch (c) {
- case small_color::white:
+ case small_color::white:
return "white";
- case small_color::gray:
+ case small_color::gray:
return "gray";
- case small_color::black:
+ case small_color::black:
return "black";
default:
return "unknown";
@@ -479,90 +479,90 @@ const char *describeColor(small_color c) {
/**
* The BGL's boykov_kolmogorov_max_flow requires that all edges have their
- * reverse edge in the graph. This function adds them, returning a vector
- * mapping edge index to reverse edge. Note: LitGraph should be a DAG so there
- * should be no existing reverse_edges.
+ * reverse edge in the graph. This function adds them, returning a vector
+ * mapping edge index to reverse edge. Note: LitGraph should be a DAG so there
+ * should be no existing reverse_edges.
*/
static
-vector<LitEdge> add_reverse_edges_and_index(LitGraph &lg) {
- const size_t edge_count = num_edges(lg);
- vector<LitEdge> fwd_edges;
- fwd_edges.reserve(edge_count);
- for (const auto &e : edges_range(lg)) {
- fwd_edges.push_back(e);
- }
+vector<LitEdge> add_reverse_edges_and_index(LitGraph &lg) {
+ const size_t edge_count = num_edges(lg);
+ vector<LitEdge> fwd_edges;
+ fwd_edges.reserve(edge_count);
+ for (const auto &e : edges_range(lg)) {
+ fwd_edges.push_back(e);
+ }
- vector<LitEdge> rev_map(2 * edge_count);
+ vector<LitEdge> rev_map(2 * edge_count);
- for (const auto &e : fwd_edges) {
- LitVertex u = source(e, lg);
- LitVertex v = target(e, lg);
+ for (const auto &e : fwd_edges) {
+ LitVertex u = source(e, lg);
+ LitVertex v = target(e, lg);
- assert(!edge(v, u, lg).second);
+ assert(!edge(v, u, lg).second);
- LitEdge rev = add_edge(v, u, LitGraphEdgeProps(0), lg).first;
- rev_map[lg[e].index] = rev;
- rev_map[lg[rev].index] = e;
+ LitEdge rev = add_edge(v, u, LitGraphEdgeProps(0), lg).first;
+ rev_map[lg[e].index] = rev;
+ rev_map[lg[rev].index] = e;
}
- return rev_map;
+ return rev_map;
}
static
-void findMinCut(LitGraph &lg, vector<LitEdge> &cutset) {
+void findMinCut(LitGraph &lg, vector<LitEdge> &cutset) {
cutset.clear();
- //dumpGraph("litgraph.dot", lg);
+ //dumpGraph("litgraph.dot", lg);
- assert(!in_degree(lg.root, lg));
- assert(!out_degree(lg.sink, lg));
- size_t num_real_edges = num_edges(lg);
+ assert(!in_degree(lg.root, lg));
+ assert(!out_degree(lg.sink, lg));
+ size_t num_real_edges = num_edges(lg);
// Add reverse edges for the convenience of the BGL's max flow algorithm.
- vector<LitEdge> rev_edges = add_reverse_edges_and_index(lg);
+ vector<LitEdge> rev_edges = add_reverse_edges_and_index(lg);
- const auto v_index_map = get(&LitGraphVertexProps::index, lg);
- const auto e_index_map = get(&LitGraphEdgeProps::index, lg);
+ const auto v_index_map = get(&LitGraphVertexProps::index, lg);
+ const auto e_index_map = get(&LitGraphEdgeProps::index, lg);
const size_t num_verts = num_vertices(lg);
- auto colors = make_small_color_map(lg);
+ auto colors = make_small_color_map(lg);
vector<s32> distances(num_verts);
vector<LitEdge> predecessors(num_verts);
- vector<u64a> residuals(num_edges(lg));
+ vector<u64a> residuals(num_edges(lg));
UNUSED u64a flow = boykov_kolmogorov_max_flow(lg,
get(&LitGraphEdgeProps::score, lg),
- make_iterator_property_map(residuals.begin(), e_index_map),
- make_iterator_property_map(rev_edges.begin(), e_index_map),
+ make_iterator_property_map(residuals.begin(), e_index_map),
+ make_iterator_property_map(rev_edges.begin(), e_index_map),
make_iterator_property_map(predecessors.begin(), v_index_map),
- colors,
+ colors,
make_iterator_property_map(distances.begin(), v_index_map),
- v_index_map, lg.root, lg.sink);
+ v_index_map, lg.root, lg.sink);
DEBUG_PRINTF("done, flow = %llu\n", flow);
- /* remove reverse edges */
- remove_edge_if([&](const LitEdge &e) {
- return lg[e].index >= num_real_edges;
- }, lg);
+ /* remove reverse edges */
+ remove_edge_if([&](const LitEdge &e) {
+ return lg[e].index >= num_real_edges;
+ }, lg);
vector<LitEdge> white_cut, black_cut;
u64a white_flow = 0, black_flow = 0;
for (const auto &e : edges_range(lg)) {
const LitVertex u = source(e, lg), v = target(e, lg);
- const auto ucolor = get(colors, u);
- const auto vcolor = get(colors, v);
+ const auto ucolor = get(colors, u);
+ const auto vcolor = get(colors, v);
- DEBUG_PRINTF("edge %zu:%s -> %zu:%s score %llu\n", lg[u].index,
- describeColor(ucolor), lg[v].index, describeColor(vcolor),
+ DEBUG_PRINTF("edge %zu:%s -> %zu:%s score %llu\n", lg[u].index,
+ describeColor(ucolor), lg[v].index, describeColor(vcolor),
lg[e].score);
- if (ucolor != small_color::white && vcolor == small_color::white) {
- assert(v != lg.sink);
+ if (ucolor != small_color::white && vcolor == small_color::white) {
+ assert(v != lg.sink);
white_cut.push_back(e);
white_flow += lg[e].score;
}
- if (ucolor == small_color::black && vcolor != small_color::black) {
- assert(v != lg.sink);
+ if (ucolor == small_color::black && vcolor != small_color::black) {
+ assert(v != lg.sink);
black_cut.push_back(e);
black_flow += lg[e].score;
}
@@ -604,17 +604,17 @@ u64a compressAndScore(set<ue2_literal> &s) {
LitGraph lg;
for (const auto &lit : s) {
- addReversedLiteral(lit, lg);
+ addReversedLiteral(lit, lg);
}
DEBUG_PRINTF("suffix tree has %zu vertices and %zu edges\n",
num_vertices(lg), num_edges(lg));
vector<LitEdge> cutset;
- findMinCut(lg, cutset);
+ findMinCut(lg, cutset);
s.clear();
- extractLiterals(cutset, lg, s);
+ extractLiterals(cutset, lg, s);
u64a score = scoreSet(s);
DEBUG_PRINTF("compressed score is %llu\n", score);
@@ -622,48 +622,48 @@ u64a compressAndScore(set<ue2_literal> &s) {
return score;
}
-/* like compressAndScore, but replaces long mixed sensitivity literals with
- * something weaker. */
-u64a sanitizeAndCompressAndScore(set<ue2_literal> &lits) {
- const size_t maxExploded = 8; // only case-explode this far
-
- /* TODO: the whole compression thing could be made better by systematically
- * considering replacing literal sets not just by common suffixes but also
- * by nocase literals. */
-
- vector<ue2_literal> replacements;
-
- for (auto it = lits.begin(); it != lits.end();) {
- auto jt = it;
- ++it;
-
- if (!bad_mixed_sensitivity(*jt)) {
- continue;
- }
-
- /* we have to replace *jt with something... */
- ue2_literal s = *jt;
- lits.erase(jt);
-
- vector<ue2_literal> exploded;
- for (auto cit = caseIterateBegin(s); cit != caseIterateEnd(); ++cit) {
- exploded.emplace_back(*cit, false);
- if (exploded.size() > maxExploded) {
- goto dont_explode;
- }
- }
- insert(&replacements, replacements.end(), exploded);
-
- continue;
- dont_explode:
- make_nocase(&s);
- replacements.push_back(s);
- }
-
- insert(&lits, replacements);
- return compressAndScore(lits);
-}
-
+/* like compressAndScore, but replaces long mixed sensitivity literals with
+ * something weaker. */
+u64a sanitizeAndCompressAndScore(set<ue2_literal> &lits) {
+ const size_t maxExploded = 8; // only case-explode this far
+
+ /* TODO: the whole compression thing could be made better by systematically
+ * considering replacing literal sets not just by common suffixes but also
+ * by nocase literals. */
+
+ vector<ue2_literal> replacements;
+
+ for (auto it = lits.begin(); it != lits.end();) {
+ auto jt = it;
+ ++it;
+
+ if (!bad_mixed_sensitivity(*jt)) {
+ continue;
+ }
+
+ /* we have to replace *jt with something... */
+ ue2_literal s = *jt;
+ lits.erase(jt);
+
+ vector<ue2_literal> exploded;
+ for (auto cit = caseIterateBegin(s); cit != caseIterateEnd(); ++cit) {
+ exploded.emplace_back(*cit, false);
+ if (exploded.size() > maxExploded) {
+ goto dont_explode;
+ }
+ }
+ insert(&replacements, replacements.end(), exploded);
+
+ continue;
+ dont_explode:
+ make_nocase(&s);
+ replacements.push_back(s);
+ }
+
+ insert(&lits, replacements);
+ return compressAndScore(lits);
+}
+
u64a scoreSet(const set<ue2_literal> &s) {
if (s.empty()) {
return NO_LITERAL_AT_EDGE_SCORE;
@@ -714,7 +714,7 @@ set<ue2_literal> getLiteralSet(const NGHolder &g, const NFAVertex &v,
return s;
}
-vector<u64a> scoreEdges(const NGHolder &g, const flat_set<NFAEdge> &known_bad) {
+vector<u64a> scoreEdges(const NGHolder &g, const flat_set<NFAEdge> &known_bad) {
assert(hasCorrectlyNumberedEdges(g));
vector<u64a> scores(num_edges(g));
@@ -722,43 +722,43 @@ vector<u64a> scoreEdges(const NGHolder &g, const flat_set<NFAEdge> &known_bad) {
for (const auto &e : edges_range(g)) {
u32 eidx = g[e].index;
assert(eidx < scores.size());
- if (contains(known_bad, e)) {
- scores[eidx] = NO_LITERAL_AT_EDGE_SCORE;
- } else {
- set<ue2_literal> ls = getLiteralSet(g, e);
- scores[eidx] = compressAndScore(ls);
- }
+ if (contains(known_bad, e)) {
+ scores[eidx] = NO_LITERAL_AT_EDGE_SCORE;
+ } else {
+ set<ue2_literal> ls = getLiteralSet(g, e);
+ scores[eidx] = compressAndScore(ls);
+ }
}
return scores;
}
-bool splitOffLeadingLiteral(const NGHolder &g, ue2_literal *lit_out,
- NGHolder *rhs) {
- DEBUG_PRINTF("looking for leading floating literal\n");
- set<NFAVertex> s_succ;
- insert(&s_succ, adjacent_vertices(g.start, g));
+bool splitOffLeadingLiteral(const NGHolder &g, ue2_literal *lit_out,
+ NGHolder *rhs) {
+ DEBUG_PRINTF("looking for leading floating literal\n");
+ set<NFAVertex> s_succ;
+ insert(&s_succ, adjacent_vertices(g.start, g));
- set<NFAVertex> sds_succ;
- insert(&sds_succ, adjacent_vertices(g.startDs, g));
+ set<NFAVertex> sds_succ;
+ insert(&sds_succ, adjacent_vertices(g.startDs, g));
- bool floating = is_subset_of(s_succ, sds_succ);
- if (!floating) {
- DEBUG_PRINTF("not floating\n");
- return false;
- }
+ bool floating = is_subset_of(s_succ, sds_succ);
+ if (!floating) {
+ DEBUG_PRINTF("not floating\n");
+ return false;
+ }
- sds_succ.erase(g.startDs);
- if (sds_succ.size() != 1) {
- DEBUG_PRINTF("branchy root\n");
- return false;
- }
+ sds_succ.erase(g.startDs);
+ if (sds_succ.size() != 1) {
+ DEBUG_PRINTF("branchy root\n");
+ return false;
+ }
- NFAVertex u = g.startDs;
- NFAVertex v = *sds_succ.begin();
+ NFAVertex u = g.startDs;
+ NFAVertex v = *sds_succ.begin();
while (true) {
- DEBUG_PRINTF("validating vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("validating vertex %zu\n", g[v].index);
assert(v != g.acceptEod && v != g.accept);
@@ -811,8 +811,8 @@ bool splitOffLeadingLiteral(const NGHolder &g, ue2_literal *lit_out,
}
assert(u != g.startDs);
- unordered_map<NFAVertex, NFAVertex> rhs_map;
- vector<NFAVertex> pivots = make_vector_from(adjacent_vertices(u, g));
+ unordered_map<NFAVertex, NFAVertex> rhs_map;
+ vector<NFAVertex> pivots = make_vector_from(adjacent_vertices(u, g));
splitRHS(g, pivots, rhs, &rhs_map);
DEBUG_PRINTF("literal is '%s' (len %zu)\n", dumpString(*lit_out).c_str(),
@@ -849,49 +849,49 @@ bool getTrailingLiteral(const NGHolder &g, ue2_literal *lit_out) {
return true;
}
-bool literalIsWholeGraph(const NGHolder &g, const ue2_literal &lit) {
- NFAVertex v = g.accept;
-
- for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) {
- NGHolder::inv_adjacency_iterator ai, ae;
- tie(ai, ae) = inv_adjacent_vertices(v, g);
- if (ai == ae) {
- assert(0); // no predecessors?
- return false;
- }
- v = *ai++;
- if (ai != ae) {
- DEBUG_PRINTF("branch, fail\n");
- return false;
- }
-
- if (is_special(v, g)) {
- DEBUG_PRINTF("special found, fail\n");
- return false;
- }
-
- const CharReach &cr_g = g[v].char_reach;
- const CharReach &cr_l = *it;
-
- if (!cr_l.isSubsetOf(cr_g)) {
- /* running over the prefix is needed to prevent false postives */
- DEBUG_PRINTF("reach fail\n");
- return false;
- }
- }
-
- // Our last value for v should have only start states for predecessors.
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (!is_any_start(u, g)) {
- DEBUG_PRINTF("pred is not start\n");
- return false;
- }
- }
-
- assert(num_vertices(g) == lit.length() + N_SPECIALS);
-
- DEBUG_PRINTF("ok\n");
- return true;
-}
-
+bool literalIsWholeGraph(const NGHolder &g, const ue2_literal &lit) {
+ NFAVertex v = g.accept;
+
+ for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) {
+ NGHolder::inv_adjacency_iterator ai, ae;
+ tie(ai, ae) = inv_adjacent_vertices(v, g);
+ if (ai == ae) {
+ assert(0); // no predecessors?
+ return false;
+ }
+ v = *ai++;
+ if (ai != ae) {
+ DEBUG_PRINTF("branch, fail\n");
+ return false;
+ }
+
+ if (is_special(v, g)) {
+ DEBUG_PRINTF("special found, fail\n");
+ return false;
+ }
+
+ const CharReach &cr_g = g[v].char_reach;
+ const CharReach &cr_l = *it;
+
+ if (!cr_l.isSubsetOf(cr_g)) {
+ /* running over the prefix is needed to prevent false postives */
+ DEBUG_PRINTF("reach fail\n");
+ return false;
+ }
+ }
+
+ // Our last value for v should have only start states for predecessors.
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (!is_any_start(u, g)) {
+ DEBUG_PRINTF("pred is not start\n");
+ return false;
+ }
+ }
+
+ assert(num_vertices(g) == lit.length() + N_SPECIALS);
+
+ DEBUG_PRINTF("ok\n");
+ return true;
+}
+
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.h b/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.h
index 96206a352d2..6bb87556102 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_literal_analysis.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,7 +42,7 @@
namespace ue2 {
#define NO_LITERAL_AT_EDGE_SCORE 10000000ULL
-#define INVALID_EDGE_CAP 100000000ULL /* special-to-special score */
+#define INVALID_EDGE_CAP 100000000ULL /* special-to-special score */
class NGHolder;
@@ -57,20 +57,20 @@ std::set<ue2_literal> getLiteralSet(const NGHolder &g, const NFAVertex &v,
bool only_first_encounter = true);
std::set<ue2_literal> getLiteralSet(const NGHolder &g, const NFAEdge &e);
-/**
- * Returns true if we are unable to use a mixed sensitivity literal in rose (as
- * our literal matchers are generally either case sensitive or not).
- *
- * Shortish mixed sensitivity literals can be handled by confirm checks in rose
- * and are not flagged as bad.
- */
-bool bad_mixed_sensitivity(const ue2_literal &s);
-
-/**
- * Score all the edges in the given graph, returning them in \p scores indexed
+/**
+ * Returns true if we are unable to use a mixed sensitivity literal in rose (as
+ * our literal matchers are generally either case sensitive or not).
+ *
+ * Shortish mixed sensitivity literals can be handled by confirm checks in rose
+ * and are not flagged as bad.
+ */
+bool bad_mixed_sensitivity(const ue2_literal &s);
+
+/**
+ * Score all the edges in the given graph, returning them in \p scores indexed
* by edge_index. */
-std::vector<u64a> scoreEdges(const NGHolder &h,
- const flat_set<NFAEdge> &known_bad = {});
+std::vector<u64a> scoreEdges(const NGHolder &h,
+ const flat_set<NFAEdge> &known_bad = {});
/** Returns a score for a literal set. Lower scores are better. */
u64a scoreSet(const std::set<ue2_literal> &s);
@@ -78,21 +78,21 @@ u64a scoreSet(const std::set<ue2_literal> &s);
/** Compress a literal set to fewer literals. */
u64a compressAndScore(std::set<ue2_literal> &s);
-/**
- * Compress a literal set to fewer literals and replace any long mixed
- * sensitivity literals with supported literals.
- */
-u64a sanitizeAndCompressAndScore(std::set<ue2_literal> &s);
-
+/**
+ * Compress a literal set to fewer literals and replace any long mixed
+ * sensitivity literals with supported literals.
+ */
+u64a sanitizeAndCompressAndScore(std::set<ue2_literal> &s);
+
bool splitOffLeadingLiteral(const NGHolder &g, ue2_literal *lit_out,
NGHolder *rhs);
bool getTrailingLiteral(const NGHolder &g, ue2_literal *lit_out);
-/** \brief Returns true if the given literal is the only thing in the graph,
- * from (start or startDs) to accept. */
-bool literalIsWholeGraph(const NGHolder &g, const ue2_literal &lit);
-
+/** \brief Returns true if the given literal is the only thing in the graph,
+ * from (start or startDs) to accept. */
+bool literalIsWholeGraph(const NGHolder &g, const ue2_literal &lit);
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.cpp
index 6dbd8d263c3..4d3965dfe24 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,30 +30,30 @@
* \brief Literal Component Splitting. Identifies literals that span the
* graph and moves them into Rose.
*/
-
-#include "ng_literal_component.h"
-
+
+#include "ng_literal_component.h"
+
#include "grey.h"
#include "ng.h"
#include "ng_prune.h"
#include "ng_util.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "rose/rose_build.h"
#include "util/container.h"
#include "util/graph.h"
#include "util/graph_range.h"
#include "util/ue2string.h"
-#include <unordered_set>
-
+#include <unordered_set>
+
using namespace std;
namespace ue2 {
static
-bool isLiteralChar(const NGHolder &g, NFAVertex v, bool &nocase,
- bool &casefixed) {
+bool isLiteralChar(const NGHolder &g, NFAVertex v, bool &nocase,
+ bool &casefixed) {
const CharReach &cr = g[v].char_reach;
const size_t num = cr.count();
if (num > 2) {
@@ -98,9 +98,9 @@ void addToString(string &s, const NGHolder &g, NFAVertex v) {
}
static
-bool splitOffLiteral(NG &ng, NGHolder &g, NFAVertex v, const bool anchored,
+bool splitOffLiteral(NG &ng, NGHolder &g, NFAVertex v, const bool anchored,
set<NFAVertex> &dead) {
- DEBUG_PRINTF("examine vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("examine vertex %zu\n", g[v].index);
bool nocase = false, casefixed = false;
assert(!is_special(v, g));
@@ -114,7 +114,7 @@ bool splitOffLiteral(NG &ng, NGHolder &g, NFAVertex v, const bool anchored,
assert(edge(g.start, v, g).second);
assert(edge(g.startDs, v, g).second);
}
- if (in_degree(v, g) > reqInDegree) {
+ if (in_degree(v, g) > reqInDegree) {
DEBUG_PRINTF("extra in-edges\n");
return false;
}
@@ -139,7 +139,7 @@ bool splitOffLiteral(NG &ng, NGHolder &g, NFAVertex v, const bool anchored,
u = v; // previous vertex
v = *(adjacent_vertices(v, g).first);
- DEBUG_PRINTF("loop, v=%zu\n", g[v].index);
+ DEBUG_PRINTF("loop, v=%zu\n", g[v].index);
if (is_special(v, g)) {
if (v == g.accept || v == g.acceptEod) {
@@ -190,15 +190,15 @@ bool splitOffLiteral(NG &ng, NGHolder &g, NFAVertex v, const bool anchored,
}
/** \brief Split off literals. True if any changes were made to the graph. */
-bool splitOffLiterals(NG &ng, NGHolder &g) {
- if (!ng.cc.grey.allowLiteral) {
+bool splitOffLiterals(NG &ng, NGHolder &g) {
+ if (!ng.cc.grey.allowLiteral) {
return false;
}
bool changed = false;
set<NFAVertex> dead;
- unordered_set<NFAVertex> unanchored; // for faster lookup.
+ unordered_set<NFAVertex> unanchored; // for faster lookup.
insert(&unanchored, adjacent_vertices(g.startDs, g));
// Anchored literals.
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.h b/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.h
index cc7ea38807d..1f284ce3672 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_literal_component.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,10 +37,10 @@
namespace ue2 {
class NG;
-class NGHolder;
+class NGHolder;
/** \brief Split off literals. True if any changes were made to the graph. */
-bool splitOffLiterals(NG &ng, NGHolder &g);
+bool splitOffLiterals(NG &ng, NGHolder &g);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_literal_decorated.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_literal_decorated.cpp
index fe46e60d55d..61a31dbf341 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_literal_decorated.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_literal_decorated.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -75,7 +75,7 @@ bool findPaths(const NGHolder &g, vector<Path> &paths) {
read_count[g[v].index] = out_degree(v, g);
- DEBUG_PRINTF("setting read_count to %zu for %zu\n",
+ DEBUG_PRINTF("setting read_count to %zu for %zu\n",
read_count[g[v].index], g[v].index);
if (v == g.start || v == g.startDs) {
@@ -115,7 +115,7 @@ bool findPaths(const NGHolder &g, vector<Path> &paths) {
read_count[g[u].index]--;
if (!read_count[g[u].index]) {
- DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index);
+ DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index);
built[g[u].index].clear();
built[g[u].index].shrink_to_fit();
}
@@ -136,9 +136,9 @@ bool hasLargeDegreeVertex(const NGHolder &g) {
if (is_special(v, g)) { // specials can have large degree
continue;
}
- if (degree(v, g) > MAX_VERTEX_DEGREE) {
- DEBUG_PRINTF("vertex %zu has degree %zu\n", g[v].index,
- degree(v, g));
+ if (degree(v, g) > MAX_VERTEX_DEGREE) {
+ DEBUG_PRINTF("vertex %zu has degree %zu\n", g[v].index,
+ degree(v, g));
return true;
}
}
@@ -186,13 +186,13 @@ struct PathMask {
}
// Reports are attached to the second-to-last vertex.
- NFAVertex u = *std::next(path.rbegin());
- reports = g[u].reports;
+ NFAVertex u = *std::next(path.rbegin());
+ reports = g[u].reports;
assert(!reports.empty());
}
vector<CharReach> mask;
- flat_set<ReportID> reports;
+ flat_set<ReportID> reports;
bool is_anchored;
bool is_eod;
};
@@ -208,11 +208,11 @@ bool handleDecoratedLiterals(RoseBuild &rose, const NGHolder &g,
return false;
}
- if (!hasNarrowReachVertex(g)) {
- DEBUG_PRINTF("no narrow reach vertices\n");
- return false;
- }
-
+ if (!hasNarrowReachVertex(g)) {
+ DEBUG_PRINTF("no narrow reach vertices\n");
+ return false;
+ }
+
if (hasLargeDegreeVertex(g)) {
DEBUG_PRINTF("large degree\n");
return false;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan.cpp
index 5a821a99f6f..4ce5dc153b1 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan.cpp
@@ -41,10 +41,10 @@
#include "ue2common.h"
#include "util/bitfield.h"
#include "util/determinise.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
-#include "util/hash.h"
-#include "util/hash_dynamic_bitset.h"
+#include "util/hash.h"
+#include "util/hash_dynamic_bitset.h"
#include "util/make_unique.h"
#include "util/report_manager.h"
@@ -52,7 +52,7 @@
#include <functional>
#include <map>
#include <set>
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
#include <boost/dynamic_bitset.hpp>
@@ -154,11 +154,11 @@ void getFullTransitionFromState(const raw_dfa &n, dstate_id_t state,
template<typename stateset>
static
-void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
stateset *init, stateset *init_deep,
vector<NFAVertex> *v_by_index) {
for (auto v : vertices_range(g)) {
- if (contains(unused, v)) {
+ if (contains(unused, v)) {
continue;
}
@@ -175,11 +175,11 @@ void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
}
v_by_index->clear();
- v_by_index->resize(num_vertices(g), NGHolder::null_vertex());
+ v_by_index->resize(num_vertices(g), NGHolder::null_vertex());
for (auto v : vertices_range(g)) {
u32 vert_id = g[v].index;
- assert((*v_by_index)[vert_id] == NGHolder::null_vertex());
+ assert((*v_by_index)[vert_id] == NGHolder::null_vertex());
(*v_by_index)[vert_id] = v;
}
@@ -189,22 +189,22 @@ void populateInit(const NGHolder &g, const flat_set<NFAVertex> &unused,
}
template<typename StateSet>
-void populateAccepts(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void populateAccepts(const NGHolder &g, const flat_set<NFAVertex> &unused,
StateSet *accept, StateSet *acceptEod) {
for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
- if (contains(unused, v)) {
- continue;
+ if (contains(unused, v)) {
+ continue;
}
- accept->set(g[v].index);
+ accept->set(g[v].index);
}
for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
if (v == g.accept) {
continue;
}
- if (contains(unused, v)) {
- continue;
+ if (contains(unused, v)) {
+ continue;
}
- acceptEod->set(g[v].index);
+ acceptEod->set(g[v].index);
}
}
@@ -284,8 +284,8 @@ static
bool triggerAllowed(const NGHolder &g, const NFAVertex v,
const vector<vector<CharReach> > &all_triggers,
const vector<CharReach> &trigger) {
- flat_set<NFAVertex> curr({v});
- flat_set<NFAVertex> next;
+ flat_set<NFAVertex> curr({v});
+ flat_set<NFAVertex> next;
for (auto it = trigger.rbegin(); it != trigger.rend(); ++it) {
next.clear();
@@ -315,7 +315,7 @@ bool triggerAllowed(const NGHolder &g, const NFAVertex v,
return true;
}
-void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
bool single_trigger,
const vector<vector<CharReach>> &triggers,
dynamic_bitset<> *out) {
@@ -324,13 +324,13 @@ void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
}
for (auto v : vertices_range(g)) {
- if (contains(unused, v)) {
+ if (contains(unused, v)) {
continue;
}
for (const auto &trigger : triggers) {
if (triggerAllowed(g, v, triggers, trigger)) {
- DEBUG_PRINTF("idx %zu is valid location for top\n", g[v].index);
- out->set(g[v].index);
+ DEBUG_PRINTF("idx %zu is valid location for top\n", g[v].index);
+ out->set(g[v].index);
break;
}
}
@@ -341,27 +341,27 @@ void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
namespace {
-template<typename Automaton_Traits>
-class Automaton_Base {
+template<typename Automaton_Traits>
+class Automaton_Base {
public:
- using StateSet = typename Automaton_Traits::StateSet;
- using StateMap = typename Automaton_Traits::StateMap;
-
- Automaton_Base(const ReportManager *rm_in, const NGHolder &graph_in,
- bool single_trigger,
- const vector<vector<CharReach>> &triggers, bool prunable_in)
- : rm(rm_in), graph(graph_in), numStates(num_vertices(graph)),
- unused(getRedundantStarts(graph_in)),
- init(Automaton_Traits::init_states(numStates)),
- initDS(Automaton_Traits::init_states(numStates)),
- squash(Automaton_Traits::init_states(numStates)),
- accept(Automaton_Traits::init_states(numStates)),
- acceptEod(Automaton_Traits::init_states(numStates)),
- toppable(Automaton_Traits::init_states(numStates)),
- dead(Automaton_Traits::init_states(numStates)),
- prunable(prunable_in) {
- populateInit(graph, unused, &init, &initDS, &v_by_index);
- populateAccepts(graph, unused, &accept, &acceptEod);
+ using StateSet = typename Automaton_Traits::StateSet;
+ using StateMap = typename Automaton_Traits::StateMap;
+
+ Automaton_Base(const ReportManager *rm_in, const NGHolder &graph_in,
+ bool single_trigger,
+ const vector<vector<CharReach>> &triggers, bool prunable_in)
+ : rm(rm_in), graph(graph_in), numStates(num_vertices(graph)),
+ unused(getRedundantStarts(graph_in)),
+ init(Automaton_Traits::init_states(numStates)),
+ initDS(Automaton_Traits::init_states(numStates)),
+ squash(Automaton_Traits::init_states(numStates)),
+ accept(Automaton_Traits::init_states(numStates)),
+ acceptEod(Automaton_Traits::init_states(numStates)),
+ toppable(Automaton_Traits::init_states(numStates)),
+ dead(Automaton_Traits::init_states(numStates)),
+ prunable(prunable_in) {
+ populateInit(graph, unused, &init, &initDS, &v_by_index);
+ populateAccepts(graph, unused, &accept, &acceptEod);
start_anchored = DEAD_STATE + 1;
if (initDS == init) {
@@ -378,18 +378,18 @@ public:
NFAVertex v = sq.first;
u32 vert_id = graph[v].index;
squash.set(vert_id);
- squash_mask[vert_id]
- = Automaton_Traits::copy_states(std::move(sq.second),
- numStates);
+ squash_mask[vert_id]
+ = Automaton_Traits::copy_states(std::move(sq.second),
+ numStates);
}
cr_by_index = populateCR(graph, v_by_index, alpha);
if (is_triggered(graph)) {
- dynamic_bitset<> temp(numStates);
- markToppableStarts(graph, unused, single_trigger, triggers,
- &temp);
- toppable = Automaton_Traits::copy_states(std::move(temp),
- numStates);
+ dynamic_bitset<> temp(numStates);
+ markToppableStarts(graph, unused, single_trigger, triggers,
+ &temp);
+ toppable = Automaton_Traits::copy_states(std::move(temp),
+ numStates);
}
}
@@ -399,7 +399,7 @@ public:
}
const vector<StateSet> initial() {
- vector<StateSet> rv = {init};
+ vector<StateSet> rv = {init};
if (start_floating != DEAD_STATE && start_floating != start_anchored) {
rv.push_back(initDS);
}
@@ -432,13 +432,13 @@ public:
}
return allExternalReports(*rm, test_reports);
}
-
+
private:
const ReportManager *rm;
public:
const NGHolder &graph;
u32 numStates;
- const flat_set<NFAVertex> unused;
+ const flat_set<NFAVertex> unused;
vector<NFAVertex> v_by_index;
vector<CharReach> cr_by_index; /* pre alpha'ed */
StateSet init;
@@ -448,7 +448,7 @@ public:
StateSet acceptEod;
StateSet toppable; /* states which are allowed to be on when a top arrives,
* triggered dfas only */
- StateSet dead;
+ StateSet dead;
map<u32, StateSet> squash_mask;
bool prunable;
array<u16, ALPHABET_SIZE> alpha;
@@ -459,83 +459,83 @@ public:
u16 start_floating;
};
-struct Big_Traits {
- using StateSet = dynamic_bitset<>;
- using StateMap = unordered_map<StateSet, dstate_id_t, hash_dynamic_bitset>;
+struct Big_Traits {
+ using StateSet = dynamic_bitset<>;
+ using StateMap = unordered_map<StateSet, dstate_id_t, hash_dynamic_bitset>;
- static StateSet init_states(u32 num) {
- return StateSet(num);
- }
+ static StateSet init_states(u32 num) {
+ return StateSet(num);
+ }
- static StateSet copy_states(dynamic_bitset<> in, UNUSED u32 num) {
- assert(in.size() == num);
- return in;
- }
-};
+ static StateSet copy_states(dynamic_bitset<> in, UNUSED u32 num) {
+ assert(in.size() == num);
+ return in;
+ }
+};
-class Automaton_Big : public Automaton_Base<Big_Traits> {
-public:
- Automaton_Big(const ReportManager *rm_in, const NGHolder &graph_in,
- bool single_trigger,
- const vector<vector<CharReach>> &triggers, bool prunable_in)
- : Automaton_Base(rm_in, graph_in, single_trigger, triggers,
- prunable_in) {}
-};
+class Automaton_Big : public Automaton_Base<Big_Traits> {
+public:
+ Automaton_Big(const ReportManager *rm_in, const NGHolder &graph_in,
+ bool single_trigger,
+ const vector<vector<CharReach>> &triggers, bool prunable_in)
+ : Automaton_Base(rm_in, graph_in, single_trigger, triggers,
+ prunable_in) {}
+};
-struct Graph_Traits {
- using StateSet = bitfield<NFA_STATE_LIMIT>;
- using StateMap = unordered_map<StateSet, dstate_id_t>;
+struct Graph_Traits {
+ using StateSet = bitfield<NFA_STATE_LIMIT>;
+ using StateMap = unordered_map<StateSet, dstate_id_t>;
- static StateSet init_states(UNUSED u32 num) {
- assert(num <= NFA_STATE_LIMIT);
- return StateSet();
+ static StateSet init_states(UNUSED u32 num) {
+ assert(num <= NFA_STATE_LIMIT);
+ return StateSet();
}
- static StateSet copy_states(const dynamic_bitset<> &in, u32 num) {
- StateSet out = init_states(num);
+ static StateSet copy_states(const dynamic_bitset<> &in, u32 num) {
+ StateSet out = init_states(num);
for (size_t i = in.find_first(); i != in.npos && i < out.size();
i = in.find_next(i)) {
out.set(i);
}
return out;
}
-};
+};
-class Automaton_Graph : public Automaton_Base<Graph_Traits> {
+class Automaton_Graph : public Automaton_Base<Graph_Traits> {
public:
- Automaton_Graph(const ReportManager *rm_in, const NGHolder &graph_in,
- bool single_trigger,
- const vector<vector<CharReach>> &triggers, bool prunable_in)
- : Automaton_Base(rm_in, graph_in, single_trigger, triggers,
- prunable_in) {}
-};
-
-} // namespace
-
-static
-bool startIsRedundant(const NGHolder &g) {
- set<NFAVertex> start;
- set<NFAVertex> startDs;
-
- insert(&start, adjacent_vertices(g.start, g));
- insert(&startDs, adjacent_vertices(g.startDs, g));
-
- return start == startDs;
-}
-
-flat_set<NFAVertex> getRedundantStarts(const NGHolder &g) {
- flat_set<NFAVertex> dead;
- if (startIsRedundant(g)) {
- dead.insert(g.start);
- }
- if (proper_out_degree(g.startDs, g) == 0) {
- dead.insert(g.startDs);
- }
- return dead;
-}
-
-unique_ptr<raw_dfa> buildMcClellan(const NGHolder &graph,
- const ReportManager *rm, bool single_trigger,
+ Automaton_Graph(const ReportManager *rm_in, const NGHolder &graph_in,
+ bool single_trigger,
+ const vector<vector<CharReach>> &triggers, bool prunable_in)
+ : Automaton_Base(rm_in, graph_in, single_trigger, triggers,
+ prunable_in) {}
+};
+
+} // namespace
+
+static
+bool startIsRedundant(const NGHolder &g) {
+ set<NFAVertex> start;
+ set<NFAVertex> startDs;
+
+ insert(&start, adjacent_vertices(g.start, g));
+ insert(&startDs, adjacent_vertices(g.startDs, g));
+
+ return start == startDs;
+}
+
+flat_set<NFAVertex> getRedundantStarts(const NGHolder &g) {
+ flat_set<NFAVertex> dead;
+ if (startIsRedundant(g)) {
+ dead.insert(g.start);
+ }
+ if (proper_out_degree(g.startDs, g) == 0) {
+ dead.insert(g.startDs);
+ }
+ return dead;
+}
+
+unique_ptr<raw_dfa> buildMcClellan(const NGHolder &graph,
+ const ReportManager *rm, bool single_trigger,
const vector<vector<CharReach>> &triggers,
const Grey &grey, bool finalChance) {
if (!grey.allowMcClellan) {
@@ -546,9 +546,9 @@ unique_ptr<raw_dfa> buildMcClellan(const NGHolder &graph,
to_string(graph.kind).c_str());
assert(allMatchStatesHaveReports(graph));
- bool prunable = grey.highlanderPruneDFA && has_managed_reports(graph);
- assert(rm || !has_managed_reports(graph));
- if (!has_managed_reports(graph)) {
+ bool prunable = grey.highlanderPruneDFA && has_managed_reports(graph);
+ assert(rm || !has_managed_reports(graph));
+ if (!has_managed_reports(graph)) {
rm = nullptr;
}
@@ -563,18 +563,18 @@ unique_ptr<raw_dfa> buildMcClellan(const NGHolder &graph,
const u32 numStates = num_vertices(graph);
DEBUG_PRINTF("determinising nfa with %u vertices\n", numStates);
- if (numStates > FINAL_DFA_STATE_LIMIT) {
- DEBUG_PRINTF("rejecting nfa as too many vertices\n");
- return nullptr;
- }
-
- auto rdfa = ue2::make_unique<raw_dfa>(graph.kind);
-
+ if (numStates > FINAL_DFA_STATE_LIMIT) {
+ DEBUG_PRINTF("rejecting nfa as too many vertices\n");
+ return nullptr;
+ }
+
+ auto rdfa = ue2::make_unique<raw_dfa>(graph.kind);
+
if (numStates <= NFA_STATE_LIMIT) {
/* Fast path. Automaton_Graph uses a bitfield internally to represent
* states and is quicker than Automaton_Big. */
- Automaton_Graph n(rm, graph, single_trigger, triggers, prunable);
- if (!determinise(n, rdfa->states, state_limit)) {
+ Automaton_Graph n(rm, graph, single_trigger, triggers, prunable);
+ if (!determinise(n, rdfa->states, state_limit)) {
DEBUG_PRINTF("state limit exceeded\n");
return nullptr; /* over state limit */
}
@@ -585,8 +585,8 @@ unique_ptr<raw_dfa> buildMcClellan(const NGHolder &graph,
rdfa->alpha_remap = n.alpha;
} else {
/* Slow path. Too many states to use Automaton_Graph. */
- Automaton_Big n(rm, graph, single_trigger, triggers, prunable);
- if (!determinise(n, rdfa->states, state_limit)) {
+ Automaton_Big n(rm, graph, single_trigger, triggers, prunable);
+ if (!determinise(n, rdfa->states, state_limit)) {
DEBUG_PRINTF("state limit exceeded\n");
return nullptr; /* over state limit */
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan_internal.h b/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan_internal.h
index a83e6b0b88b..f069d7336f9 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan_internal.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_mcclellan_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,7 +38,7 @@
#include "nfagraph/ng_holder.h"
#include "util/charreach.h"
#include "util/graph_range.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <boost/dynamic_bitset.hpp>
@@ -63,25 +63,25 @@ void getFullTransitionFromState(const raw_dfa &n, u16 state,
u16 *out_table);
/** produce a map of states on which it is valid to receive tops */
-void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
+void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &unused,
bool single_trigger,
const std::vector<std::vector<CharReach>> &triggers,
boost::dynamic_bitset<> *out);
-/**
- * \brief Returns a set of start vertices that will not participate in an
- * implementation of this graph. These are either starts with no successors or
- * starts which are redundant with startDs.
- */
-flat_set<NFAVertex> getRedundantStarts(const NGHolder &g);
-
+/**
+ * \brief Returns a set of start vertices that will not participate in an
+ * implementation of this graph. These are either starts with no successors or
+ * starts which are redundant with startDs.
+ */
+flat_set<NFAVertex> getRedundantStarts(const NGHolder &g);
+
template<typename autom>
void transition_graph(autom &nfa, const std::vector<NFAVertex> &vByStateId,
const typename autom::StateSet &in,
typename autom::StateSet *next) {
typedef typename autom::StateSet StateSet;
const NGHolder &graph = nfa.graph;
- const auto &unused = nfa.unused;
+ const auto &unused = nfa.unused;
const auto &alpha = nfa.alpha;
const StateSet &squash = nfa.squash;
const std::map<u32, StateSet> &squash_mask = nfa.squash_mask;
@@ -99,7 +99,7 @@ void transition_graph(autom &nfa, const std::vector<NFAVertex> &vByStateId,
NFAVertex u = vByStateId[i];
for (const auto &v : adjacent_vertices_range(u, graph)) {
- if (contains(unused, v)) {
+ if (contains(unused, v)) {
continue;
}
succ.set(graph[v].index);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.cpp
index e51307d2969..8aaaf99fdec 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -69,20 +69,20 @@
#include "util/charreach.h"
#include "util/container.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
-#include "util/flat_containers.h"
+#include "util/graph_small_color_map.h"
+#include "util/flat_containers.h"
#include "ue2common.h"
-#include <boost/dynamic_bitset.hpp>
-#include <boost/graph/depth_first_search.hpp>
-#include <boost/graph/filtered_graph.hpp>
-
+#include <boost/dynamic_bitset.hpp>
+#include <boost/graph/depth_first_search.hpp>
+#include <boost/graph/filtered_graph.hpp>
+
#include <map>
#include <set>
#include <vector>
using namespace std;
-using boost::make_filtered_graph;
+using boost::make_filtered_graph;
namespace ue2 {
@@ -101,8 +101,8 @@ void findCandidates(NGHolder &g, const vector<NFAVertex> &ordering,
// For `v' to be a candidate, its predecessors must all have the same
// successor set as `v'.
- auto succ_v = succs(v, g);
- flat_set<NFAVertex> succ_u;
+ auto succ_v = succs(v, g);
+ flat_set<NFAVertex> succ_u;
for (auto u : inv_adjacent_vertices_range(v, g)) {
succ_u.clear();
@@ -111,7 +111,7 @@ void findCandidates(NGHolder &g, const vector<NFAVertex> &ordering,
goto next_cand;
}
}
- DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index);
cand->push_back(v);
next_cand:;
}
@@ -132,8 +132,8 @@ void findCandidates_rev(NGHolder &g, const vector<NFAVertex> &ordering,
// For `v' to be a candidate, its predecessors must all have the same
// successor set as `v'.
- auto pred_v = preds(v, g);
- flat_set<NFAVertex> pred_u;
+ auto pred_v = preds(v, g);
+ flat_set<NFAVertex> pred_u;
for (auto u : adjacent_vertices_range(v, g)) {
pred_u.clear();
@@ -142,7 +142,7 @@ void findCandidates_rev(NGHolder &g, const vector<NFAVertex> &ordering,
goto next_cand;
}
}
- DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index);
cand->push_back(v);
next_cand:;
}
@@ -179,7 +179,7 @@ void succCRIntersection(const NGHolder &g, NFAVertex v, CharReach &add) {
static
set<NFAVertex> findSustainSet(const NGHolder &g, NFAVertex p,
bool ignore_starts, const CharReach &new_cr) {
- auto cand = preds<set<NFAVertex>>(p, g);
+ auto cand = preds<set<NFAVertex>>(p, g);
if (ignore_starts) {
cand.erase(g.startDs);
}
@@ -215,7 +215,7 @@ set<NFAVertex> findSustainSet(const NGHolder &g, NFAVertex p,
static
set<NFAVertex> findSustainSet_rev(const NGHolder &g, NFAVertex p,
const CharReach &new_cr) {
- auto cand = succs<set<NFAVertex>>(p, g);
+ auto cand = succs<set<NFAVertex>>(p, g);
/* remove elements from cand until the sustain set property holds */
bool changed;
do {
@@ -245,7 +245,7 @@ set<NFAVertex> findSustainSet_rev(const NGHolder &g, NFAVertex p,
static
bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) {
- DEBUG_PRINTF("considering vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("considering vertex %zu\n", g[v].index);
const CharReach &v_cr = g[v].char_reach;
CharReach add;
@@ -264,7 +264,7 @@ bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) {
if (p == v) {
continue;
}
- DEBUG_PRINTF("looking at pred %zu\n", g[p].index);
+ DEBUG_PRINTF("looking at pred %zu\n", g[p].index);
bool ignore_sds = som; /* if we are tracking som, entries into a state
from sds are significant. */
@@ -294,13 +294,13 @@ bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) {
/* the cr can be increased */
g[v].char_reach = add;
- DEBUG_PRINTF("vertex %zu was widened\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu was widened\n", g[v].index);
return true;
}
static
bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) {
- DEBUG_PRINTF("considering vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("considering vertex %zu\n", g[v].index);
const CharReach &v_cr = g[v].char_reach;
CharReach add;
@@ -319,7 +319,7 @@ bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) {
if (p == v) {
continue;
}
- DEBUG_PRINTF("looking at succ %zu\n", g[p].index);
+ DEBUG_PRINTF("looking at succ %zu\n", g[p].index);
set<NFAVertex> sustain = findSustainSet_rev(g, p, add);
DEBUG_PRINTF("sustain set is %zu\n", sustain.size());
@@ -344,7 +344,7 @@ bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) {
/* the cr can be increased */
g[v].char_reach = add;
- DEBUG_PRINTF("vertex %zu was widened\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu was widened\n", g[v].index);
return true;
}
@@ -393,7 +393,7 @@ bool improveGraph(NGHolder &g, som_type som) {
* enlargeCyclicCR. */
CharReach reduced_cr(NFAVertex v, const NGHolder &g,
const map<NFAVertex, BoundedRepeatSummary> &br_cyclic) {
- DEBUG_PRINTF("find minimal cr for %zu\n", g[v].index);
+ DEBUG_PRINTF("find minimal cr for %zu\n", g[v].index);
CharReach v_cr = g[v].char_reach;
if (proper_in_degree(v, g) != 1) {
return v_cr;
@@ -551,178 +551,178 @@ bool mergeCyclicDotStars(NGHolder &g) {
return true;
}
-struct PrunePathsInfo {
- explicit PrunePathsInfo(const NGHolder &g)
- : color_map(make_small_color_map(g)), bad(num_vertices(g)) {}
-
- void clear() {
- no_explore.clear();
- color_map.fill(small_color::white);
- bad.reset();
- }
-
- flat_set<NFAEdge> no_explore;
- using color_map_type = decltype(make_small_color_map(NGHolder()));
- color_map_type color_map;
- boost::dynamic_bitset<> bad;
-};
-
-/**
- * Finds the set of vertices that cannot be on if v is not on, setting their
- * indices in bitset PrunePathsInfo::bad.
- */
-static
-void findDependentVertices(const NGHolder &g, PrunePathsInfo &info,
- NFAVertex v) {
- /* We need to exclude any vertex that may be reached on a path which is
- * incompatible with the vertex v being on. */
-
- /* A vertex u is bad if:
- * 1) its reach may be incompatible with v (not a subset)
- * 2) it if there is an edge from a bad vertex b and there is either not an
- * edge v->u or not an edge b->v.
- * Note: 2) means v is never bad as it has a selfloop
- *
- * Can do this with a DFS from all the initial bad states with a conditional
- * check down edges. Alternately can just filter these edges out of the
- * graph first.
- */
- for (NFAVertex t : adjacent_vertices_range(v, g)) {
- for (NFAEdge e : in_edges_range(t, g)) {
- NFAVertex s = source(e, g);
- if (edge(s, v, g).second) {
- info.no_explore.insert(e);
- }
- }
- }
-
- auto filtered_g =
- make_filtered_graph(g, make_bad_edge_filter(&info.no_explore));
-
- // We use a bitset to track bad vertices, rather than filling a (potentially
- // very large) set structure.
- auto recorder = make_vertex_index_bitset_recorder(info.bad);
-
- for (NFAVertex b : vertices_range(g)) {
- if (b != g.start && g[b].char_reach.isSubsetOf(g[v].char_reach)) {
- continue;
- }
- boost::depth_first_visit(filtered_g, b, recorder, info.color_map);
- }
-}
-
-static
-bool willBeEnabledConcurrently(NFAVertex main_cyclic, NFAVertex v,
- const NGHolder &g) {
- return is_subset_of(preds(main_cyclic, g), preds(v, g));
-}
-
-static
-bool sometimesEnabledConcurrently(NFAVertex main_cyclic, NFAVertex v,
- const NGHolder &g) {
- return has_intersection(preds(main_cyclic, g), preds(v, g));
-}
-
-static
-bool pruneUsingSuccessors(NGHolder &g, PrunePathsInfo &info, NFAVertex u,
- som_type som) {
- if (som && (is_virtual_start(u, g) || u == g.startDs)) {
- return false;
- }
-
- bool changed = false;
- DEBUG_PRINTF("using cyclic %zu as base\n", g[u].index);
- info.clear();
- findDependentVertices(g, info, u);
- vector<NFAVertex> u_succs;
- for (NFAVertex v : adjacent_vertices_range(u, g)) {
- if (som && is_virtual_start(v, g)) {
- /* as v is virtual start, its som has been reset so can not override
- * existing in progress matches. */
- continue;
- }
- u_succs.push_back(v);
- }
-
- stable_sort(u_succs.begin(), u_succs.end(),
- [&](NFAVertex a, NFAVertex b) {
- return g[a].char_reach.count() > g[b].char_reach.count();
- });
-
- flat_set<NFAEdge> dead;
-
- for (NFAVertex v : u_succs) {
- DEBUG_PRINTF(" using %zu as killer\n", g[v].index);
- /* Need to distinguish between vertices that are switched on after the
- * cyclic vs vertices that are switched on concurrently with the cyclic
- * if (subject to a suitable reach) */
- bool v_peer_of_cyclic = willBeEnabledConcurrently(u, v, g);
- for (NFAVertex s : adjacent_vertices_range(v, g)) {
- DEBUG_PRINTF(" looking at preds of %zu\n", g[s].index);
- for (NFAEdge e : in_edges_range(s, g)) {
- NFAVertex p = source(e, g);
- if (info.bad.test(g[p].index) || p == v || p == u
- || p == g.accept) {
- DEBUG_PRINTF("%zu not a cand\n", g[p].index);
- continue;
- }
- if (is_any_accept(s, g) && g[p].reports != g[v].reports) {
- DEBUG_PRINTF("%zu bad reports\n", g[p].index);
- continue;
- }
- /* the out-edges of a vertex that may be enabled on the same
- * byte as the cyclic can only be killed by the out-edges of a
- * peer vertex which will be enabled with the cyclic (a non-peer
- * may not be switched on until another byte is processed). */
- if (!v_peer_of_cyclic
- && sometimesEnabledConcurrently(u, p, g)) {
- DEBUG_PRINTF("%zu can only be squashed by a proper peer\n",
- g[p].index);
- continue;
- }
-
- if (g[p].char_reach.isSubsetOf(g[v].char_reach)) {
- dead.insert(e);
- changed = true;
- DEBUG_PRINTF("removing edge %zu->%zu\n", g[p].index,
- g[s].index);
- } else if (is_subset_of(succs(p, g), succs(u, g))) {
- if (is_match_vertex(p, g)
- && !is_subset_of(g[p].reports, g[v].reports)) {
- continue;
- }
- DEBUG_PRINTF("updating reach on %zu\n", g[p].index);
- changed |= (g[p].char_reach & g[v].char_reach).any();
- g[p].char_reach &= ~g[v].char_reach;
- }
-
- }
- }
- remove_edges(dead, g);
- dead.clear();
- }
-
- DEBUG_PRINTF("changed %d\n", (int)changed);
- return changed;
-}
-
-bool prunePathsRedundantWithSuccessorOfCyclics(NGHolder &g, som_type som) {
- /* TODO: the reverse form of this is also possible */
- bool changed = false;
- PrunePathsInfo info(g);
-
- for (NFAVertex v : vertices_range(g)) {
- if (hasSelfLoop(v, g) && g[v].char_reach.all()) {
- changed |= pruneUsingSuccessors(g, info, v, som);
- }
- }
-
- if (changed) {
- pruneUseless(g);
- clearReports(g);
- }
-
- return changed;
-}
-
+struct PrunePathsInfo {
+ explicit PrunePathsInfo(const NGHolder &g)
+ : color_map(make_small_color_map(g)), bad(num_vertices(g)) {}
+
+ void clear() {
+ no_explore.clear();
+ color_map.fill(small_color::white);
+ bad.reset();
+ }
+
+ flat_set<NFAEdge> no_explore;
+ using color_map_type = decltype(make_small_color_map(NGHolder()));
+ color_map_type color_map;
+ boost::dynamic_bitset<> bad;
+};
+
+/**
+ * Finds the set of vertices that cannot be on if v is not on, setting their
+ * indices in bitset PrunePathsInfo::bad.
+ */
+static
+void findDependentVertices(const NGHolder &g, PrunePathsInfo &info,
+ NFAVertex v) {
+ /* We need to exclude any vertex that may be reached on a path which is
+ * incompatible with the vertex v being on. */
+
+ /* A vertex u is bad if:
+ * 1) its reach may be incompatible with v (not a subset)
+ * 2) it if there is an edge from a bad vertex b and there is either not an
+ * edge v->u or not an edge b->v.
+ * Note: 2) means v is never bad as it has a selfloop
+ *
+ * Can do this with a DFS from all the initial bad states with a conditional
+ * check down edges. Alternately can just filter these edges out of the
+ * graph first.
+ */
+ for (NFAVertex t : adjacent_vertices_range(v, g)) {
+ for (NFAEdge e : in_edges_range(t, g)) {
+ NFAVertex s = source(e, g);
+ if (edge(s, v, g).second) {
+ info.no_explore.insert(e);
+ }
+ }
+ }
+
+ auto filtered_g =
+ make_filtered_graph(g, make_bad_edge_filter(&info.no_explore));
+
+ // We use a bitset to track bad vertices, rather than filling a (potentially
+ // very large) set structure.
+ auto recorder = make_vertex_index_bitset_recorder(info.bad);
+
+ for (NFAVertex b : vertices_range(g)) {
+ if (b != g.start && g[b].char_reach.isSubsetOf(g[v].char_reach)) {
+ continue;
+ }
+ boost::depth_first_visit(filtered_g, b, recorder, info.color_map);
+ }
+}
+
+static
+bool willBeEnabledConcurrently(NFAVertex main_cyclic, NFAVertex v,
+ const NGHolder &g) {
+ return is_subset_of(preds(main_cyclic, g), preds(v, g));
+}
+
+static
+bool sometimesEnabledConcurrently(NFAVertex main_cyclic, NFAVertex v,
+ const NGHolder &g) {
+ return has_intersection(preds(main_cyclic, g), preds(v, g));
+}
+
+static
+bool pruneUsingSuccessors(NGHolder &g, PrunePathsInfo &info, NFAVertex u,
+ som_type som) {
+ if (som && (is_virtual_start(u, g) || u == g.startDs)) {
+ return false;
+ }
+
+ bool changed = false;
+ DEBUG_PRINTF("using cyclic %zu as base\n", g[u].index);
+ info.clear();
+ findDependentVertices(g, info, u);
+ vector<NFAVertex> u_succs;
+ for (NFAVertex v : adjacent_vertices_range(u, g)) {
+ if (som && is_virtual_start(v, g)) {
+ /* as v is virtual start, its som has been reset so can not override
+ * existing in progress matches. */
+ continue;
+ }
+ u_succs.push_back(v);
+ }
+
+ stable_sort(u_succs.begin(), u_succs.end(),
+ [&](NFAVertex a, NFAVertex b) {
+ return g[a].char_reach.count() > g[b].char_reach.count();
+ });
+
+ flat_set<NFAEdge> dead;
+
+ for (NFAVertex v : u_succs) {
+ DEBUG_PRINTF(" using %zu as killer\n", g[v].index);
+ /* Need to distinguish between vertices that are switched on after the
+ * cyclic vs vertices that are switched on concurrently with the cyclic
+ * if (subject to a suitable reach) */
+ bool v_peer_of_cyclic = willBeEnabledConcurrently(u, v, g);
+ for (NFAVertex s : adjacent_vertices_range(v, g)) {
+ DEBUG_PRINTF(" looking at preds of %zu\n", g[s].index);
+ for (NFAEdge e : in_edges_range(s, g)) {
+ NFAVertex p = source(e, g);
+ if (info.bad.test(g[p].index) || p == v || p == u
+ || p == g.accept) {
+ DEBUG_PRINTF("%zu not a cand\n", g[p].index);
+ continue;
+ }
+ if (is_any_accept(s, g) && g[p].reports != g[v].reports) {
+ DEBUG_PRINTF("%zu bad reports\n", g[p].index);
+ continue;
+ }
+ /* the out-edges of a vertex that may be enabled on the same
+ * byte as the cyclic can only be killed by the out-edges of a
+ * peer vertex which will be enabled with the cyclic (a non-peer
+ * may not be switched on until another byte is processed). */
+ if (!v_peer_of_cyclic
+ && sometimesEnabledConcurrently(u, p, g)) {
+ DEBUG_PRINTF("%zu can only be squashed by a proper peer\n",
+ g[p].index);
+ continue;
+ }
+
+ if (g[p].char_reach.isSubsetOf(g[v].char_reach)) {
+ dead.insert(e);
+ changed = true;
+ DEBUG_PRINTF("removing edge %zu->%zu\n", g[p].index,
+ g[s].index);
+ } else if (is_subset_of(succs(p, g), succs(u, g))) {
+ if (is_match_vertex(p, g)
+ && !is_subset_of(g[p].reports, g[v].reports)) {
+ continue;
+ }
+ DEBUG_PRINTF("updating reach on %zu\n", g[p].index);
+ changed |= (g[p].char_reach & g[v].char_reach).any();
+ g[p].char_reach &= ~g[v].char_reach;
+ }
+
+ }
+ }
+ remove_edges(dead, g);
+ dead.clear();
+ }
+
+ DEBUG_PRINTF("changed %d\n", (int)changed);
+ return changed;
+}
+
+bool prunePathsRedundantWithSuccessorOfCyclics(NGHolder &g, som_type som) {
+ /* TODO: the reverse form of this is also possible */
+ bool changed = false;
+ PrunePathsInfo info(g);
+
+ for (NFAVertex v : vertices_range(g)) {
+ if (hasSelfLoop(v, g) && g[v].char_reach.all()) {
+ changed |= pruneUsingSuccessors(g, info, v, som);
+ }
+ }
+
+ if (changed) {
+ pruneUseless(g);
+ clearReports(g);
+ }
+
+ return changed;
+}
+
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.h b/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.h
index 9d89a87ede2..5ed089dc053 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_misc_opt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -60,8 +60,8 @@ struct BoundedRepeatSummary {
bool improveGraph(NGHolder &g, som_type som);
/** Sometimes the reach of a vertex is greater than it needs to be to reduce
- * stop chars for the benefit of the rest of our code base (accel, etc). In
- * these circumstances, we can treat the reach as the smaller one as
+ * stop chars for the benefit of the rest of our code base (accel, etc). In
+ * these circumstances, we can treat the reach as the smaller one as
* the graphs are equivalent. */
CharReach reduced_cr(NFAVertex v, const NGHolder &g,
const std::map<NFAVertex, BoundedRepeatSummary> &br_cyclic);
@@ -72,13 +72,13 @@ std::vector<CharReach> reduced_cr(const NGHolder &g,
/** Remove cyclic stars connected to start */
bool mergeCyclicDotStars(NGHolder &g);
-/**
- * Given a cyclic state 'c' with a broad reach and a later state 'v' that is
- * only reachable if c is still on, then any edges to a successor of a direct
- * successor of c with reach a superset of v are redundant.
- */
-bool prunePathsRedundantWithSuccessorOfCyclics(NGHolder &h, som_type som);
-
+/**
+ * Given a cyclic state 'c' with a broad reach and a later state 'v' that is
+ * only reachable if c is still on, then any edges to a successor of a direct
+ * successor of c with reach a superset of v are redundant.
+ */
+bool prunePathsRedundantWithSuccessorOfCyclics(NGHolder &h, som_type som);
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_netflow.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_netflow.cpp
index a3631f6d855..780a319f5de 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_netflow.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_netflow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@
#include "ue2common.h"
#include "util/container.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include <algorithm>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
@@ -93,7 +93,7 @@ void addReverseEdges(NGHolder &g, vector<NFAEdge> &reverseEdge,
if (it == allEdges.end()) {
// No reverse edge, add one.
NFAVertex u = source(fwd, g), v = target(fwd, g);
- NFAEdge rev = add_edge(v, u, g);
+ NFAEdge rev = add_edge(v, u, g);
it = allEdges.insert(make_pair(make_pair(vidx, uidx), rev)).first;
// Add to capacity map.
u32 revIndex = g[rev].index;
@@ -112,14 +112,14 @@ static
void removeEdgesFromIndex(NGHolder &g, vector<u64a> &capacityMap, u32 idx) {
remove_edge_if([&](const NFAEdge &e) { return g[e].index >= idx; }, g);
capacityMap.resize(idx);
- renumber_edges(g);
+ renumber_edges(g);
}
/** A wrapper around boykov_kolmogorov_max_flow, returns the max flow and
* colour map (from which we can find the min cut). */
static
u64a getMaxFlow(NGHolder &h, const vector<u64a> &capacityMap_in,
- decltype(make_small_color_map(NGHolder())) &colorMap) {
+ decltype(make_small_color_map(NGHolder())) &colorMap) {
vector<u64a> capacityMap = capacityMap_in;
NFAVertex src = h.start;
NFAVertex sink = h.acceptEod;
@@ -143,22 +143,22 @@ u64a getMaxFlow(NGHolder &h, const vector<u64a> &capacityMap_in,
vector<NFAEdge> predecessors(numVertices);
vector<s32> distances(numVertices);
- auto v_index_map = get(vertex_index, h);
- auto e_index_map = get(edge_index, h);
+ auto v_index_map = get(vertex_index, h);
+ auto e_index_map = get(edge_index, h);
- u64a flow = boykov_kolmogorov_max_flow(h,
+ u64a flow = boykov_kolmogorov_max_flow(h,
make_iterator_property_map(capacityMap.begin(), e_index_map),
make_iterator_property_map(edgeResiduals.begin(), e_index_map),
make_iterator_property_map(reverseEdges.begin(), e_index_map),
make_iterator_property_map(predecessors.begin(), v_index_map),
- colorMap,
+ colorMap,
make_iterator_property_map(distances.begin(), v_index_map),
v_index_map,
src, sink);
// Remove reverse edges from graph.
removeEdgesFromIndex(h, capacityMap, numRealEdges);
- assert(num_edges(h) == numRealEdges);
+ assert(num_edges(h) == numRealEdges);
DEBUG_PRINTF("flow = %llu\n", flow);
return flow;
@@ -169,8 +169,8 @@ vector<NFAEdge> findMinCut(NGHolder &h, const vector<u64a> &scores) {
assert(hasCorrectlyNumberedEdges(h));
assert(hasCorrectlyNumberedVertices(h));
- auto colors = make_small_color_map(h);
- u64a flow = getMaxFlow(h, scores, colors);
+ auto colors = make_small_color_map(h);
+ u64a flow = getMaxFlow(h, scores, colors);
vector<NFAEdge> picked_white;
vector<NFAEdge> picked_black;
@@ -185,19 +185,19 @@ vector<NFAEdge> findMinCut(NGHolder &h, const vector<u64a> &scores) {
continue; // skips, among other things, reverse edges
}
- auto fromColor = get(colors, from);
- auto toColor = get(colors, to);
+ auto fromColor = get(colors, from);
+ auto toColor = get(colors, to);
- if (fromColor != small_color::white && toColor == small_color::white) {
+ if (fromColor != small_color::white && toColor == small_color::white) {
assert(ec <= INVALID_EDGE_CAP);
- DEBUG_PRINTF("found white cut edge %zu->%zu cap %llu\n",
+ DEBUG_PRINTF("found white cut edge %zu->%zu cap %llu\n",
h[from].index, h[to].index, ec);
observed_white_flow += ec;
picked_white.push_back(e);
}
- if (fromColor == small_color::black && toColor != small_color::black) {
+ if (fromColor == small_color::black && toColor != small_color::black) {
assert(ec <= INVALID_EDGE_CAP);
- DEBUG_PRINTF("found black cut edge %zu->%zu cap %llu\n",
+ DEBUG_PRINTF("found black cut edge %zu->%zu cap %llu\n",
h[from].index, h[to].index, ec);
observed_black_flow += ec;
picked_black.push_back(e);
@@ -206,7 +206,7 @@ vector<NFAEdge> findMinCut(NGHolder &h, const vector<u64a> &scores) {
DEBUG_PRINTF("min flow = %llu b flow = %llu w flow %llu\n", flow,
observed_black_flow, observed_white_flow);
- if (min(observed_white_flow, observed_black_flow) != flow) {
+ if (min(observed_white_flow, observed_black_flow) != flow) {
DEBUG_PRINTF("bad cut\n");
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_prefilter.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_prefilter.cpp
index 849fa09ad46..04611872a43 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_prefilter.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_prefilter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Prefilter Reductions.
*
* This file contains routines for reducing the size of an NFA graph that we
@@ -58,8 +58,8 @@
#include "util/graph_range.h"
#include <queue>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <boost/range/adaptor/map.hpp>
@@ -82,10 +82,10 @@ static const size_t BOUNDED_REPEAT_COUNT = 4;
/** Scoring penalty for boundary regions. */
static const size_t PENALTY_BOUNDARY = 32;
-/** Regions with max bounds greater than this value will have their max bound
- * replaced with inf. */
-static const size_t MAX_REPLACE_BOUND = 10000;
-
+/** Regions with max bounds greater than this value will have their max bound
+ * replaced with inf. */
+static const size_t MAX_REPLACE_BOUND = 10000;
+
namespace {
/** Information describing a region. */
@@ -94,13 +94,13 @@ struct RegionInfo {
u32 id; //!< region id
deque<NFAVertex> vertices; //!< vertices in the region
CharReach reach; //!< union of region reach
- depth minWidth{0}; //!< min width of region subgraph
- depth maxWidth{depth::infinity()}; //!< max width of region subgraph
+ depth minWidth{0}; //!< min width of region subgraph
+ depth maxWidth{depth::infinity()}; //!< max width of region subgraph
bool atBoundary = false; //!< region is next to an accept
// Bigger score is better.
size_t score() const {
- // TODO: charreach should be a signal?
+ // TODO: charreach should be a signal?
size_t numVertices = vertices.size();
if (atBoundary) {
return numVertices - min(PENALTY_BOUNDARY, numVertices);
@@ -128,16 +128,16 @@ struct RegionInfoQueueComp {
static
void findWidths(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
RegionInfo &ri) {
NGHolder rg;
- unordered_map<NFAVertex, NFAVertex> mapping;
+ unordered_map<NFAVertex, NFAVertex> mapping;
fillHolder(&rg, g, ri.vertices, &mapping);
// Wire our entries to start and our exits to accept.
for (auto v : ri.vertices) {
NFAVertex v_new = mapping[v];
- assert(v_new != NGHolder::null_vertex());
+ assert(v_new != NGHolder::null_vertex());
if (isRegionEntry(g, v, region_map) &&
!edge(rg.start, v_new, rg).second) {
@@ -156,7 +156,7 @@ void findWidths(const NGHolder &g,
// acc can be either h.accept or h.acceptEod.
static
void markBoundaryRegions(const NGHolder &h,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
map<u32, RegionInfo> &regions, NFAVertex acc) {
for (auto v : inv_adjacent_vertices_range(acc, h)) {
if (is_special(v, h)) {
@@ -164,7 +164,7 @@ void markBoundaryRegions(const NGHolder &h,
}
u32 id = region_map.at(v);
- auto ri = regions.find(id);
+ auto ri = regions.find(id);
if (ri == regions.end()) {
continue; // Not tracking this region as it's too small.
}
@@ -175,21 +175,21 @@ void markBoundaryRegions(const NGHolder &h,
static
map<u32, RegionInfo> findRegionInfo(const NGHolder &h,
- const unordered_map<NFAVertex, u32> &region_map) {
+ const unordered_map<NFAVertex, u32> &region_map) {
map<u32, RegionInfo> regions;
for (auto v : vertices_range(h)) {
if (is_special(v, h)) {
continue;
}
u32 id = region_map.at(v);
- RegionInfo &ri = regions.emplace(id, RegionInfo(id)).first->second;
+ RegionInfo &ri = regions.emplace(id, RegionInfo(id)).first->second;
ri.vertices.push_back(v);
ri.reach |= h[v].char_reach;
}
// There's no point tracking more information about regions that we won't
// consider replacing, so we remove them from the region map.
- for (auto it = regions.begin(); it != regions.end();) {
+ for (auto it = regions.begin(); it != regions.end();) {
if (it->second.vertices.size() < MIN_REPLACE_VERTICES) {
regions.erase(it++);
} else {
@@ -214,15 +214,15 @@ map<u32, RegionInfo> findRegionInfo(const NGHolder &h,
}
static
-void copyInEdges(NGHolder &g, NFAVertex from, NFAVertex to) {
+void copyInEdges(NGHolder &g, NFAVertex from, NFAVertex to) {
for (const auto &e : in_edges_range(from, g)) {
NFAVertex u = source(e, g);
- add_edge_if_not_present(u, to, g[e], g);
+ add_edge_if_not_present(u, to, g[e], g);
}
}
static
-void copyOutEdges(NGHolder &g, NFAVertex from, NFAVertex to) {
+void copyOutEdges(NGHolder &g, NFAVertex from, NFAVertex to) {
for (const auto &e : out_edges_range(from, g)) {
NFAVertex t = target(e, g);
add_edge_if_not_present(to, t, g[e], g);
@@ -235,48 +235,48 @@ void copyOutEdges(NGHolder &g, NFAVertex from, NFAVertex to) {
}
static
-void removeInteriorEdges(NGHolder &g, const RegionInfo &ri) {
- // Set of vertices in region, for quick lookups.
- const unordered_set<NFAVertex> rverts(ri.vertices.begin(),
- ri.vertices.end());
-
- auto is_interior_in_edge = [&](const NFAEdge &e) {
- return contains(rverts, source(e, g));
- };
-
- for (auto v : ri.vertices) {
- remove_in_edge_if(v, is_interior_in_edge, g);
- }
-}
-
-static
+void removeInteriorEdges(NGHolder &g, const RegionInfo &ri) {
+ // Set of vertices in region, for quick lookups.
+ const unordered_set<NFAVertex> rverts(ri.vertices.begin(),
+ ri.vertices.end());
+
+ auto is_interior_in_edge = [&](const NFAEdge &e) {
+ return contains(rverts, source(e, g));
+ };
+
+ for (auto v : ri.vertices) {
+ remove_in_edge_if(v, is_interior_in_edge, g);
+ }
+}
+
+static
void replaceRegion(NGHolder &g, const RegionInfo &ri,
size_t *verticesAdded, size_t *verticesRemoved) {
// TODO: more complex replacements.
assert(ri.vertices.size() >= MIN_REPLACE_VERTICES);
assert(ri.minWidth.is_finite());
- depth minWidth = ri.minWidth;
- depth maxWidth = ri.maxWidth;
-
- if (maxWidth > depth(MAX_REPLACE_BOUND)) {
- DEBUG_PRINTF("using inf instead of large bound %s\n",
- maxWidth.str().c_str());
- maxWidth = depth::infinity();
- }
-
+ depth minWidth = ri.minWidth;
+ depth maxWidth = ri.maxWidth;
+
+ if (maxWidth > depth(MAX_REPLACE_BOUND)) {
+ DEBUG_PRINTF("using inf instead of large bound %s\n",
+ maxWidth.str().c_str());
+ maxWidth = depth::infinity();
+ }
+
size_t replacementSize;
- if (minWidth == maxWidth || maxWidth.is_infinite()) {
- replacementSize = minWidth; // {N} or {N,}
+ if (minWidth == maxWidth || maxWidth.is_infinite()) {
+ replacementSize = minWidth; // {N} or {N,}
} else {
- replacementSize = maxWidth; // {N,M} case
+ replacementSize = maxWidth; // {N,M} case
}
DEBUG_PRINTF("orig size %zu, replace size %zu\n", ri.vertices.size(),
replacementSize);
- vector<NFAVertex> verts;
- verts.reserve(replacementSize);
+ vector<NFAVertex> verts;
+ verts.reserve(replacementSize);
for (size_t i = 0; i < replacementSize; i++) {
NFAVertex v = add_vertex(g);
g[v].char_reach = ri.reach;
@@ -286,21 +286,21 @@ void replaceRegion(NGHolder &g, const RegionInfo &ri,
verts.push_back(v);
}
- if (maxWidth.is_infinite()) {
+ if (maxWidth.is_infinite()) {
add_edge(verts.back(), verts.back(), g);
}
- removeInteriorEdges(g, ri);
+ removeInteriorEdges(g, ri);
for (size_t i = 0; i < replacementSize; i++) {
NFAVertex v_new = verts[i];
for (auto v_old : ri.vertices) {
if (i == 0) {
- copyInEdges(g, v_old, v_new);
+ copyInEdges(g, v_old, v_new);
}
if (i + 1 >= ri.minWidth) {
- copyOutEdges(g, v_old, v_new);
+ copyOutEdges(g, v_old, v_new);
}
}
}
@@ -360,7 +360,7 @@ void reduceRegions(NGHolder &h) {
// We may have vertices that have edges to both accept and acceptEod: in
// this case, we can optimize for performance by removing the acceptEod
// edges.
- remove_in_edge_if(h.acceptEod, SourceHasEdgeToAccept(h), h);
+ remove_in_edge_if(h.acceptEod, SourceHasEdgeToAccept(h), h);
}
void prefilterReductions(NGHolder &h, const CompileContext &cc) {
@@ -374,20 +374,20 @@ void prefilterReductions(NGHolder &h, const CompileContext &cc) {
return;
}
- DEBUG_PRINTF("before: graph with %zu vertices, %zu edges\n",
- num_vertices(h), num_edges(h));
+ DEBUG_PRINTF("before: graph with %zu vertices, %zu edges\n",
+ num_vertices(h), num_edges(h));
- renumber_vertices(h);
- renumber_edges(h);
+ renumber_vertices(h);
+ renumber_edges(h);
reduceRegions(h);
- renumber_vertices(h);
- renumber_edges(h);
-
- DEBUG_PRINTF("after: graph with %zu vertices, %zu edges\n",
- num_vertices(h), num_edges(h));
-
+ renumber_vertices(h);
+ renumber_edges(h);
+
+ DEBUG_PRINTF("after: graph with %zu vertices, %zu edges\n",
+ num_vertices(h), num_edges(h));
+
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_prune.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_prune.cpp
index 88b499950be..adda70312f0 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_prune.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_prune.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,7 +38,7 @@
#include "util/container.h"
#include "util/graph.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include "util/report_manager.h"
#include <deque>
@@ -58,8 +58,8 @@ namespace ue2 {
void pruneUnreachable(NGHolder &g) {
deque<NFAVertex> dead;
- if (in_degree(g.acceptEod, g) == 1 && !in_degree(g.accept, g)
- && edge(g.accept, g.acceptEod, g).second) {
+ if (in_degree(g.acceptEod, g) == 1 && !in_degree(g.accept, g)
+ && edge(g.accept, g.acceptEod, g).second) {
// Trivial case: there are no in-edges to our accepts (other than
// accept->acceptEod), so all non-specials are unreachable.
for (auto v : vertices_range(g)) {
@@ -70,10 +70,10 @@ void pruneUnreachable(NGHolder &g) {
} else {
// Walk a reverse graph from acceptEod with Boost's depth_first_visit
// call.
- typedef reverse_graph<NGHolder, NGHolder &> RevNFAGraph;
- RevNFAGraph revg(g);
+ typedef reverse_graph<NGHolder, NGHolder &> RevNFAGraph;
+ RevNFAGraph revg(g);
- map<RevNFAGraph::vertex_descriptor, default_color_type> colours;
+ map<RevNFAGraph::vertex_descriptor, default_color_type> colours;
depth_first_visit(revg, g.acceptEod,
make_dfs_visitor(boost::null_visitor()),
@@ -104,23 +104,23 @@ void pruneUnreachable(NGHolder &g) {
template<class nfag_t>
static
-bool pruneForwardUseless(NGHolder &h, const nfag_t &g,
- typename nfag_t::vertex_descriptor s,
- decltype(make_small_color_map(NGHolder())) &colors) {
+bool pruneForwardUseless(NGHolder &h, const nfag_t &g,
+ typename nfag_t::vertex_descriptor s,
+ decltype(make_small_color_map(NGHolder())) &colors) {
// Begin with all vertices set to white, as DFV only marks visited
// vertices.
- colors.fill(small_color::white);
+ colors.fill(small_color::white);
- depth_first_visit(g, s, make_dfs_visitor(boost::null_visitor()), colors);
+ depth_first_visit(g, s, make_dfs_visitor(boost::null_visitor()), colors);
vector<NFAVertex> dead;
// All non-special vertices that are still white can be removed.
for (auto v : vertices_range(g)) {
- if (!is_special(v, g) && get(colors, v) == small_color::white) {
- DEBUG_PRINTF("vertex %zu is unreachable from %zu\n",
+ if (!is_special(v, g) && get(colors, v) == small_color::white) {
+ DEBUG_PRINTF("vertex %zu is unreachable from %zu\n",
g[v].index, g[s].index);
- dead.push_back(NFAVertex(v));
+ dead.push_back(NFAVertex(v));
}
}
@@ -139,19 +139,19 @@ bool pruneForwardUseless(NGHolder &h, const nfag_t &g,
void pruneUseless(NGHolder &g, bool renumber) {
DEBUG_PRINTF("pruning useless vertices\n");
assert(hasCorrectlyNumberedVertices(g));
- auto colors = make_small_color_map(g);
+ auto colors = make_small_color_map(g);
- bool work_done = pruneForwardUseless(g, g, g.start, colors);
- work_done |= pruneForwardUseless(g, reverse_graph<NGHolder, NGHolder &>(g),
- g.acceptEod, colors);
+ bool work_done = pruneForwardUseless(g, g, g.start, colors);
+ work_done |= pruneForwardUseless(g, reverse_graph<NGHolder, NGHolder &>(g),
+ g.acceptEod, colors);
if (!work_done) {
return;
}
if (renumber) {
- renumber_edges(g);
- renumber_vertices(g);
+ renumber_edges(g);
+ renumber_vertices(g);
}
}
@@ -168,7 +168,7 @@ void pruneEmptyVertices(NGHolder &g) {
const CharReach &cr = g[v].char_reach;
if (cr.none()) {
- DEBUG_PRINTF("empty: %zu\n", g[v].index);
+ DEBUG_PRINTF("empty: %zu\n", g[v].index);
dead.push_back(v);
}
}
@@ -223,14 +223,14 @@ void pruneHighlanderAccepts(NGHolder &g, const ReportManager &rm) {
static
bool isDominatedByReporter(const NGHolder &g,
- const unordered_map<NFAVertex, NFAVertex> &dom,
+ const unordered_map<NFAVertex, NFAVertex> &dom,
NFAVertex v, ReportID report_id) {
for (auto it = dom.find(v); it != end(dom); it = dom.find(v)) {
NFAVertex u = it->second;
// Note: reporters with edges only to acceptEod are not considered to
// dominate.
if (edge(u, g.accept, g).second && contains(g[u].reports, report_id)) {
- DEBUG_PRINTF("%zu is dominated by %zu, and both report %u\n",
+ DEBUG_PRINTF("%zu is dominated by %zu, and both report %u\n",
g[v].index, g[u].index, report_id);
return true;
}
@@ -292,7 +292,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) {
}
- sort(begin(reporters), end(reporters));
+ sort(begin(reporters), end(reporters));
reporters.erase(unique(begin(reporters), end(reporters)), end(reporters));
DEBUG_PRINTF("%zu vertices have simple exhaustible reports\n",
@@ -311,14 +311,14 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) {
continue;
}
if (isDominatedByReporter(g, dom, v, report_id)) {
- DEBUG_PRINTF("removed dominated report %u from vertex %zu\n",
+ DEBUG_PRINTF("removed dominated report %u from vertex %zu\n",
report_id, g[v].index);
g[v].reports.erase(report_id);
}
}
if (g[v].reports.empty()) {
- DEBUG_PRINTF("removed edges to accepts from %zu, no reports left\n",
+ DEBUG_PRINTF("removed edges to accepts from %zu, no reports left\n",
g[v].index);
remove_edge(v, g.accept, g);
remove_edge(v, g.acceptEod, g);
@@ -333,7 +333,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) {
if (hasOnlySelfLoopAndExhaustibleAccepts(g, rm, v)) {
remove_edge(v, v, g);
modified = true;
- DEBUG_PRINTF("removed self-loop on %zu\n", g[v].index);
+ DEBUG_PRINTF("removed self-loop on %zu\n", g[v].index);
}
}
@@ -345,7 +345,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) {
// We may have only removed self-loops, in which case pruneUseless wouldn't
// renumber, so we do edge renumbering explicitly here.
- renumber_edges(g);
+ renumber_edges(g);
}
/** Removes the given Report ID from vertices connected to accept, and then
@@ -384,8 +384,8 @@ void pruneReport(NGHolder &g, ReportID report) {
remove_edges(dead, g);
pruneUnreachable(g);
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
}
/** Removes all Report IDs bar the given one from vertices connected to accept,
@@ -427,8 +427,8 @@ void pruneAllOtherReports(NGHolder &g, ReportID report) {
remove_edges(dead, g);
pruneUnreachable(g);
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_puff.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_puff.cpp
index 76996b6da84..984518b0fcc 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_puff.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_puff.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -59,7 +59,7 @@ static
size_t countChain(const NGHolder &g, NFAVertex v) {
size_t count = 0;
while (v) {
- DEBUG_PRINTF("counting vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("counting vertex %zu\n", g[v].index);
if (is_special(v, g)) {
break;
}
@@ -79,7 +79,7 @@ void wireNewAccepts(NGHolder &g, NFAVertex head,
continue;
}
- DEBUG_PRINTF("adding edge: %zu -> accept\n", g[u].index);
+ DEBUG_PRINTF("adding edge: %zu -> accept\n", g[u].index);
assert(!edge(u, g.accept, g).second);
assert(!edge(u, g.acceptEod, g).second);
add_edge(u, g.accept, g);
@@ -94,7 +94,7 @@ void wireNewAccepts(NGHolder &g, NFAVertex head,
static
bool isFixedDepth(const NGHolder &g, NFAVertex v) {
// If the vertex is reachable from startDs, it can't be fixed depth.
- auto depthFromStartDs = calcDepthsFrom(g, g.startDs);
+ auto depthFromStartDs = calcDepthsFrom(g, g.startDs);
u32 idx = g[v].index;
const DepthMinMax &ds = depthFromStartDs.at(idx);
@@ -103,7 +103,7 @@ bool isFixedDepth(const NGHolder &g, NFAVertex v) {
return false;
}
- auto depthFromStart = calcDepthsFrom(g, g.start);
+ auto depthFromStart = calcDepthsFrom(g, g.start);
/* we can still consider the head of a puff chain as at fixed depth if
* it has a self-loop: so we look at all the preds of v (other than v
@@ -134,13 +134,13 @@ bool singleStart(const NGHolder &g) {
for (auto v : adjacent_vertices_range(g.start, g)) {
if (!is_special(v, g)) {
- DEBUG_PRINTF("saw %zu\n", g[v].index);
+ DEBUG_PRINTF("saw %zu\n", g[v].index);
seen.insert(v);
}
}
for (auto v : adjacent_vertices_range(g.startDs, g)) {
if (!is_special(v, g)) {
- DEBUG_PRINTF("saw %zu\n", g[v].index);
+ DEBUG_PRINTF("saw %zu\n", g[v].index);
seen.insert(v);
}
}
@@ -156,7 +156,7 @@ bool triggerResetsPuff(const NGHolder &g, NFAVertex head) {
for (auto u : inv_adjacent_vertices_range(head, g)) {
if (!g[u].char_reach.isSubsetOf(puff_escapes)) {
- DEBUG_PRINTF("no reset on trigger %zu %zu\n", g[u].index,
+ DEBUG_PRINTF("no reset on trigger %zu %zu\n", g[u].index,
g[head].index);
return false;
}
@@ -170,7 +170,7 @@ bool triggerResetsPuff(const NGHolder &g, NFAVertex head) {
* */
static
bool triggerFloodsPuff(const NGHolder &g, NFAVertex head) {
- DEBUG_PRINTF("head = %zu\n", g[head].index);
+ DEBUG_PRINTF("head = %zu\n", g[head].index);
const CharReach &puff_cr = g[head].char_reach;
@@ -184,14 +184,14 @@ bool triggerFloodsPuff(const NGHolder &g, NFAVertex head) {
if (proper_in_degree(head, g) == 1
&& puff_cr == g[getSoleSourceVertex(g, head)].char_reach) {
head = getSoleSourceVertex(g, head);
- DEBUG_PRINTF("temp new head = %zu\n", g[head].index);
+ DEBUG_PRINTF("temp new head = %zu\n", g[head].index);
}
for (auto s : inv_adjacent_vertices_range(head, g)) {
- DEBUG_PRINTF("s = %zu\n", g[s].index);
+ DEBUG_PRINTF("s = %zu\n", g[s].index);
if (!puff_cr.isSubsetOf(g[s].char_reach)) {
- DEBUG_PRINTF("no flood on trigger %zu %zu\n", g[s].index,
- g[head].index);
+ DEBUG_PRINTF("no flood on trigger %zu %zu\n", g[s].index,
+ g[head].index);
return false;
}
@@ -266,18 +266,18 @@ void constructPuff(NGHolder &g, const NFAVertex a, const NFAVertex puffv,
RoseBuild &rose, ReportManager &rm,
flat_set<ReportID> &chain_reports, bool prefilter) {
DEBUG_PRINTF("constructing Puff for report %u\n", report);
- DEBUG_PRINTF("a = %zu\n", g[a].index);
+ DEBUG_PRINTF("a = %zu\n", g[a].index);
+
+ const Report &puff_report = rm.getReport(report);
+ const bool simple_exhaust = isSimpleExhaustible(puff_report);
- const Report &puff_report = rm.getReport(report);
- const bool simple_exhaust = isSimpleExhaustible(puff_report);
-
const bool pureAnchored = a == g.start && singleStart(g);
if (!pureAnchored) {
if (a == g.startDs || a == g.start) {
DEBUG_PRINTF("add outfix ar(false)\n");
- raw_puff rp(width, unbounded, report, cr, auto_restart,
- simple_exhaust);
+ raw_puff rp(width, unbounded, report, cr, auto_restart,
+ simple_exhaust);
rose.addOutfix(rp);
return;
}
@@ -291,7 +291,7 @@ void constructPuff(NGHolder &g, const NFAVertex a, const NFAVertex puffv,
u32 squashDistance = allowedSquashDistance(cr, width, g, puffv,
prefilter);
- Report ir = makeMpvTrigger(event, squashDistance);
+ Report ir = makeMpvTrigger(event, squashDistance);
/* only need to trigger once if floatingUnboundedDot */
bool floatingUnboundedDot = unbounded && cr.all() && !fixed_depth;
if (floatingUnboundedDot) {
@@ -302,7 +302,7 @@ void constructPuff(NGHolder &g, const NFAVertex a, const NFAVertex puffv,
} else {
DEBUG_PRINTF("add outfix ar(%d)\n", (int)auto_restart);
assert(!auto_restart || unbounded);
- raw_puff rp(width, unbounded, report, cr, auto_restart, simple_exhaust);
+ raw_puff rp(width, unbounded, report, cr, auto_restart, simple_exhaust);
rose.addOutfix(rp);
}
}
@@ -347,7 +347,7 @@ bool doComponent(RoseBuild &rose, ReportManager &rm, NGHolder &g, NFAVertex a,
}
nodes.push_back(a);
- DEBUG_PRINTF("vertex %zu has in_degree %zu\n", g[a].index,
+ DEBUG_PRINTF("vertex %zu has in_degree %zu\n", g[a].index,
in_degree(a, g));
a = getSoleSourceVertex(g, a);
@@ -385,10 +385,10 @@ bool doComponent(RoseBuild &rose, ReportManager &rm, NGHolder &g, NFAVertex a,
bool auto_restart = false;
- DEBUG_PRINTF("a = %zu\n", g[a].index);
+ DEBUG_PRINTF("a = %zu\n", g[a].index);
if (nodes.size() < MIN_PUFF_LENGTH || a == g.startDs) {
- DEBUG_PRINTF("bad %zu %zu\n", nodes.size(), g[a].index);
+ DEBUG_PRINTF("bad %zu %zu\n", nodes.size(), g[a].index);
if (nodes.size() < MIN_PUFF_LENGTH) {
return false;
} else {
@@ -470,7 +470,7 @@ bool doComponent(RoseBuild &rose, ReportManager &rm, NGHolder &g, NFAVertex a,
}
NFAVertex puffv = nodes.back();
- assert(puffv != NGHolder::null_vertex());
+ assert(puffv != NGHolder::null_vertex());
u32 width = countChain(g, nodes.back());
flat_set<ReportID> chain_reports;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_redundancy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_redundancy.cpp
index 9f475b53457..06b9daeecac 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_redundancy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_redundancy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -78,7 +78,7 @@
#include "ng_util.h"
#include "ue2common.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include <algorithm>
@@ -158,7 +158,7 @@ void populateContainers(const NGHolder &g, VertexInfoMap &infoMap) {
static
void inplaceIntersection(vector<NFAVertex> &vset1,
const flat_set<NFAVertex> &vset2) {
- const NFAVertex GONE = NGHolder::null_vertex();
+ const NFAVertex GONE = NGHolder::null_vertex();
vector<NFAVertex>::iterator it = vset1.begin(), ite = vset1.end();
flat_set<NFAVertex>::const_iterator jt = vset2.begin(), jte = vset2.end();
@@ -307,8 +307,8 @@ void markForRemoval(const NFAVertex v, VertexInfoMap &infoMap,
static
bool hasInEdgeTops(const NGHolder &g, NFAVertex v) {
- NFAEdge e = edge(g.start, v, g);
- return e && !g[e].tops.empty();
+ NFAEdge e = edge(g.start, v, g);
+ return e && !g[e].tops.empty();
}
/** Transform (1), removal of redundant vertices. */
@@ -342,7 +342,7 @@ bool doUselessMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap,
}
if (info.pred.empty() || info.succ.empty()) {
- DEBUG_PRINTF("vertex %zu has empty pred/succ list\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has empty pred/succ list\n", g[v].index);
assert(0); // non-special states should always have succ/pred lists
continue;
}
@@ -441,7 +441,7 @@ bool doUselessMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap,
CharReach &otherReach = g[t].char_reach;
if (currReach.isSubsetOf(otherReach)) {
- DEBUG_PRINTF("removing redundant vertex %zu (keeping %zu)\n",
+ DEBUG_PRINTF("removing redundant vertex %zu (keeping %zu)\n",
g[v].index, g[t].index);
markForRemoval(v, infoMap, removable);
changed = true;
@@ -568,8 +568,8 @@ bool doDiamondMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap,
CharReach &otherReach = g[t].char_reach;
otherReach |= currReach;
// v can be removed
- DEBUG_PRINTF("removing redundant vertex %zu and merging "
- "reachability with vertex %zu\n",
+ DEBUG_PRINTF("removing redundant vertex %zu and merging "
+ "reachability with vertex %zu\n",
g[v].index, g[t].index);
markForRemoval(v, infoMap, removable);
changed = true;
@@ -635,14 +635,14 @@ bool reversePathReachSubset(const NFAEdge &e, const NFAVertex &dom,
}
NFAVertex start = source(e, g);
- using RevGraph = boost::reverse_graph<NGHolder, const NGHolder &>;
+ using RevGraph = boost::reverse_graph<NGHolder, const NGHolder &>;
map<RevGraph::vertex_descriptor, boost::default_color_type> vertexColor;
// Walk the graph backwards from v, examining each node. We fail (return
// false) if we encounter a node with reach NOT a subset of domReach, and
// we stop searching at dom.
try {
- depth_first_visit(RevGraph(g), start,
+ depth_first_visit(RevGraph(g), start,
ReachSubsetVisitor(domReach),
make_assoc_property_map(vertexColor),
VertexIs<RevGraph, RevGraph::vertex_descriptor>(dom));
@@ -664,15 +664,15 @@ bool forwardPathReachSubset(const NFAEdge &e, const NFAVertex &dom,
}
NFAVertex start = target(e, g);
- map<NFAVertex, boost::default_color_type> vertexColor;
+ map<NFAVertex, boost::default_color_type> vertexColor;
// Walk the graph forward from v, examining each node. We fail (return
// false) if we encounter a node with reach NOT a subset of domReach, and
// we stop searching at dom.
try {
- depth_first_visit(g, start, ReachSubsetVisitor(domReach),
+ depth_first_visit(g, start, ReachSubsetVisitor(domReach),
make_assoc_property_map(vertexColor),
- VertexIs<NGHolder, NFAVertex>(dom));
+ VertexIs<NGHolder, NFAVertex>(dom));
} catch(ReachMismatch&) {
return false;
}
@@ -735,9 +735,9 @@ u32 findCyclic(const NGHolder &g, vector<bool> &cyclic) {
for (auto v : vertices_range(g)) {
assert(g[v].index < cyclic.size());
- if (hasSelfLoop(v, g)) {
+ if (hasSelfLoop(v, g)) {
count++;
- cyclic[g[v].index] = true;
+ cyclic[g[v].index] = true;
}
}
@@ -747,7 +747,7 @@ u32 findCyclic(const NGHolder &g, vector<bool> &cyclic) {
static
void findCyclicDom(NGHolder &g, vector<bool> &cyclic,
set<NFAEdge> &dead, som_type som) {
- auto dominators = findDominators(g);
+ auto dominators = findDominators(g);
for (auto v : vertices_range(g)) {
if (is_special(v, g)) {
@@ -763,8 +763,8 @@ void findCyclicDom(NGHolder &g, vector<bool> &cyclic,
continue;
}
- DEBUG_PRINTF("vertex %zu is dominated by directly-connected cyclic "
- "vertex %zu\n", g[v].index, g[dom].index);
+ DEBUG_PRINTF("vertex %zu is dominated by directly-connected cyclic "
+ "vertex %zu\n", g[v].index, g[dom].index);
// iff all paths through in-edge e of v involve vertices whose
// reachability is a subset of reach(dom), we can delete edge e.
@@ -774,8 +774,8 @@ void findCyclicDom(NGHolder &g, vector<bool> &cyclic,
}
if (reversePathReachSubset(e, dom, g)) {
- DEBUG_PRINTF("edge (%zu, %zu) can be removed: leading "
- "paths share dom reach\n",
+ DEBUG_PRINTF("edge (%zu, %zu) can be removed: leading "
+ "paths share dom reach\n",
g[source(e, g)].index, g[target(e, g)].index);
dead.insert(e);
if (source(e, g) == v) {
@@ -791,7 +791,7 @@ void findCyclicDom(NGHolder &g, vector<bool> &cyclic,
static
void findCyclicPostDom(NGHolder &g, vector<bool> &cyclic,
set<NFAEdge> &dead) {
- auto postdominators = findPostDominators(g);
+ auto postdominators = findPostDominators(g);
for (auto v : vertices_range(g)) {
if (is_special(v, g)) {
@@ -800,9 +800,9 @@ void findCyclicPostDom(NGHolder &g, vector<bool> &cyclic,
// Path out through a post-dominator (e.g. a?.+foobar')
NFAVertex postdom = postdominators[v];
- if (postdom && cyclic[g[postdom].index] && edge(v, postdom, g).second) {
- DEBUG_PRINTF("vertex %zu is postdominated by directly-connected "
- "cyclic vertex %zu\n", g[v].index, g[postdom].index);
+ if (postdom && cyclic[g[postdom].index] && edge(v, postdom, g).second) {
+ DEBUG_PRINTF("vertex %zu is postdominated by directly-connected "
+ "cyclic vertex %zu\n", g[v].index, g[postdom].index);
// iff all paths through in-edge e of v involve vertices whose
// reachability is a subset of reach(dom), we can delete edge e.
@@ -812,8 +812,8 @@ void findCyclicPostDom(NGHolder &g, vector<bool> &cyclic,
}
if (forwardPathReachSubset(e, postdom, g)) {
- DEBUG_PRINTF("edge (%zu, %zu) can be removed: trailing "
- "paths share postdom reach\n",
+ DEBUG_PRINTF("edge (%zu, %zu) can be removed: trailing "
+ "paths share postdom reach\n",
g[source(e, g)].index, g[target(e, g)].index);
if (target(e, g) == v) {
cyclic[g[v].index] = false;
@@ -828,7 +828,7 @@ void findCyclicPostDom(NGHolder &g, vector<bool> &cyclic,
bool removeRedundancy(NGHolder &g, som_type som) {
DEBUG_PRINTF("rr som = %d\n", (int)som);
- renumber_vertices(g);
+ renumber_vertices(g);
// Cheap check: if all the non-special vertices have in-degree one and
// out-degree one, there's no redundancy in this here graph and we can
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_region.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_region.cpp
index e025bccda32..2675be643f3 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_region.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_region.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -56,9 +56,9 @@
#include "ng_util.h"
#include "ue2common.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include <set>
#include <utility>
@@ -71,61 +71,61 @@ using namespace std;
namespace ue2 {
-using BackEdgeSet = unordered_set<NFAEdge>;
-using AcyclicGraph =
- boost::filtered_graph<NGHolder, bad_edge_filter<BackEdgeSet>>;
+using BackEdgeSet = unordered_set<NFAEdge>;
+using AcyclicGraph =
+ boost::filtered_graph<NGHolder, bad_edge_filter<BackEdgeSet>>;
namespace {
struct exit_info {
explicit exit_info(NFAVertex v) : exit(v) {}
NFAVertex exit;
- flat_set<NFAVertex> open;
+ flat_set<NFAVertex> open;
};
}
static
void checkAndAddExitCandidate(const AcyclicGraph &g,
- const unordered_set<NFAVertex> &r, NFAVertex v,
- vector<exit_info> &exits) {
- exit_info v_exit(v);
- auto &open = v_exit.open;
+ const unordered_set<NFAVertex> &r, NFAVertex v,
+ vector<exit_info> &exits) {
+ exit_info v_exit(v);
+ auto &open = v_exit.open;
/* find the set of vertices reachable from v which are not in r */
for (auto w : adjacent_vertices_range(v, g)) {
if (!contains(r, w)) {
- open.insert(w);
+ open.insert(w);
}
}
- if (!open.empty()) {
- DEBUG_PRINTF("exit %zu\n", g[v].index);
- exits.push_back(move(v_exit));
+ if (!open.empty()) {
+ DEBUG_PRINTF("exit %zu\n", g[v].index);
+ exits.push_back(move(v_exit));
}
}
static
-void findExits(const AcyclicGraph &g, const unordered_set<NFAVertex> &r,
- vector<exit_info> &exits) {
- exits.clear();
+void findExits(const AcyclicGraph &g, const unordered_set<NFAVertex> &r,
+ vector<exit_info> &exits) {
+ exits.clear();
for (auto v : r) {
checkAndAddExitCandidate(g, r, v, exits);
}
}
static
-void refineExits(const AcyclicGraph &g, const unordered_set<NFAVertex> &r,
- NFAVertex new_v, vector<exit_info> &exits) {
- /* new_v is no long an open edge */
- for (auto &exit : exits) {
- exit.open.erase(new_v);
+void refineExits(const AcyclicGraph &g, const unordered_set<NFAVertex> &r,
+ NFAVertex new_v, vector<exit_info> &exits) {
+ /* new_v is no long an open edge */
+ for (auto &exit : exits) {
+ exit.open.erase(new_v);
}
- /* no open edges: no longer an exit */
- exits.erase(remove_if(exits.begin(), exits.end(),
- [&](const exit_info &exit) { return exit.open.empty(); }),
- exits.end());
-
+ /* no open edges: no longer an exit */
+ exits.erase(remove_if(exits.begin(), exits.end(),
+ [&](const exit_info &exit) { return exit.open.empty(); }),
+ exits.end());
+
checkAndAddExitCandidate(g, r, new_v, exits);
}
@@ -133,12 +133,12 @@ void refineExits(const AcyclicGraph &g, const unordered_set<NFAVertex> &r,
*/
static
bool exitValid(UNUSED const AcyclicGraph &g, const vector<exit_info> &exits,
- const flat_set<NFAVertex> &open_jumps) {
+ const flat_set<NFAVertex> &open_jumps) {
if (exits.empty() || (exits.size() < 2 && open_jumps.empty())) {
return true;
}
if (exits.size() == 1 && open_jumps.size() == 1) {
- DEBUG_PRINTF("oj %zu, e %zu\n", g[*open_jumps.begin()].index,
+ DEBUG_PRINTF("oj %zu, e %zu\n", g[*open_jumps.begin()].index,
g[exits[0].exit].index);
if (*open_jumps.begin() == exits[0].exit) {
return true;
@@ -162,8 +162,8 @@ bool exitValid(UNUSED const AcyclicGraph &g, const vector<exit_info> &exits,
}
static
-void setRegion(const unordered_set<NFAVertex> &r, u32 rid,
- unordered_map<NFAVertex, u32> &regions) {
+void setRegion(const unordered_set<NFAVertex> &r, u32 rid,
+ unordered_map<NFAVertex, u32> &regions) {
for (auto v : r) {
regions[v] = rid;
}
@@ -173,36 +173,36 @@ static
void buildInitialCandidate(const AcyclicGraph &g,
vector<NFAVertex>::const_reverse_iterator &it,
const vector<NFAVertex>::const_reverse_iterator &ite,
- unordered_set<NFAVertex> &candidate,
+ unordered_set<NFAVertex> &candidate,
/* in exits of prev region;
* out exits from candidate */
- vector<exit_info> &exits,
- flat_set<NFAVertex> &open_jumps) {
+ vector<exit_info> &exits,
+ flat_set<NFAVertex> &open_jumps) {
if (it == ite) {
- candidate.clear();
- exits.clear();
+ candidate.clear();
+ exits.clear();
return;
}
- if (exits.empty()) {
+ if (exits.empty()) {
DEBUG_PRINTF("odd\n");
- candidate.clear();
- DEBUG_PRINTF("adding %zu to initial\n", g[*it].index);
- candidate.insert(*it);
- open_jumps.erase(*it);
- checkAndAddExitCandidate(g, candidate, *it, exits);
+ candidate.clear();
+ DEBUG_PRINTF("adding %zu to initial\n", g[*it].index);
+ candidate.insert(*it);
+ open_jumps.erase(*it);
+ checkAndAddExitCandidate(g, candidate, *it, exits);
++it;
return;
}
- // Note: findExits() will clear exits, so it's safe to mutate/move its
- // elements here.
- auto &enters = exits.front().open;
- candidate.clear();
+ // Note: findExits() will clear exits, so it's safe to mutate/move its
+ // elements here.
+ auto &enters = exits.front().open;
+ candidate.clear();
for (; it != ite; ++it) {
- DEBUG_PRINTF("adding %zu to initial\n", g[*it].index);
- candidate.insert(*it);
+ DEBUG_PRINTF("adding %zu to initial\n", g[*it].index);
+ candidate.insert(*it);
if (contains(enters, *it)) {
break;
}
@@ -210,35 +210,35 @@ void buildInitialCandidate(const AcyclicGraph &g,
if (it != ite) {
enters.erase(*it);
- open_jumps = move(enters);
- DEBUG_PRINTF("oj size = %zu\n", open_jumps.size());
+ open_jumps = move(enters);
+ DEBUG_PRINTF("oj size = %zu\n", open_jumps.size());
++it;
} else {
- open_jumps.clear();
+ open_jumps.clear();
}
- findExits(g, candidate, exits);
+ findExits(g, candidate, exits);
}
static
void findDagLeaders(const NGHolder &h, const AcyclicGraph &g,
const vector<NFAVertex> &topo,
- unordered_map<NFAVertex, u32> &regions) {
+ unordered_map<NFAVertex, u32> &regions) {
assert(!topo.empty());
u32 curr_id = 0;
- auto t_it = topo.rbegin();
- unordered_set<NFAVertex> candidate;
- flat_set<NFAVertex> open_jumps;
- DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index);
+ auto t_it = topo.rbegin();
+ unordered_set<NFAVertex> candidate;
+ flat_set<NFAVertex> open_jumps;
+ DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index);
assert(t_it != topo.rend());
candidate.insert(*t_it++);
- DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index);
+ DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index);
assert(t_it != topo.rend());
candidate.insert(*t_it++);
- vector<exit_info> exits;
- findExits(g, candidate, exits);
-
+ vector<exit_info> exits;
+ findExits(g, candidate, exits);
+
while (t_it != topo.rend()) {
assert(!candidate.empty());
@@ -253,14 +253,14 @@ void findDagLeaders(const NGHolder &h, const AcyclicGraph &g,
DEBUG_PRINTF("setting region %u\n", curr_id);
}
setRegion(candidate, curr_id++, regions);
- buildInitialCandidate(g, t_it, topo.rend(), candidate, exits,
- open_jumps);
+ buildInitialCandidate(g, t_it, topo.rend(), candidate, exits,
+ open_jumps);
} else {
NFAVertex curr = *t_it;
- DEBUG_PRINTF("adding %zu to current\n", g[curr].index);
+ DEBUG_PRINTF("adding %zu to current\n", g[curr].index);
candidate.insert(curr);
open_jumps.erase(curr);
- refineExits(g, candidate, *t_it, exits);
+ refineExits(g, candidate, *t_it, exits);
DEBUG_PRINTF(" open jumps %zu exits %zu\n", open_jumps.size(),
exits.size());
++t_it;
@@ -273,7 +273,7 @@ void findDagLeaders(const NGHolder &h, const AcyclicGraph &g,
static
void mergeUnderBackEdges(const NGHolder &g, const vector<NFAVertex> &topo,
const BackEdgeSet &backEdges,
- unordered_map<NFAVertex, u32> &regions) {
+ unordered_map<NFAVertex, u32> &regions) {
for (const auto &e : backEdges) {
NFAVertex u = source(e, g);
NFAVertex v = target(e, g);
@@ -284,7 +284,7 @@ void mergeUnderBackEdges(const NGHolder &g, const vector<NFAVertex> &topo,
continue;
}
- DEBUG_PRINTF("merging v = %zu(%u), u = %zu(%u)\n", g[v].index, rv,
+ DEBUG_PRINTF("merging v = %zu(%u), u = %zu(%u)\n", g[v].index, rv,
g[u].index, ru);
assert(rv < ru);
@@ -343,15 +343,15 @@ void reorderSpecials(const NGHolder &w, const AcyclicGraph &acyclic_g,
static
void liftSinks(const AcyclicGraph &acyclic_g, vector<NFAVertex> &topoOrder) {
- unordered_set<NFAVertex> sinks;
+ unordered_set<NFAVertex> sinks;
for (auto v : vertices_range(acyclic_g)) {
if (is_special(v, acyclic_g)) {
continue;
}
if (isLeafNode(v, acyclic_g)) {
- DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index);
- sinks.insert(NFAVertex(v));
+ DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index);
+ sinks.insert(NFAVertex(v));
}
}
@@ -365,18 +365,18 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector<NFAVertex> &topoOrder) {
DEBUG_PRINTF("look\n");
changed = false;
for (auto v : vertices_range(acyclic_g)) {
- if (is_special(v, acyclic_g) || contains(sinks, NFAVertex(v))) {
+ if (is_special(v, acyclic_g) || contains(sinks, NFAVertex(v))) {
continue;
}
for (auto w : adjacent_vertices_range(v, acyclic_g)) {
- if (!contains(sinks, NFAVertex(w))) {
+ if (!contains(sinks, NFAVertex(w))) {
goto next;
}
}
- DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index);
- sinks.insert(NFAVertex(v));
+ DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index);
+ sinks.insert(NFAVertex(v));
changed = true;
next:;
}
@@ -387,10 +387,10 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector<NFAVertex> &topoOrder) {
continue;
}
NFAVertex s = *ri;
- DEBUG_PRINTF("handling sink %zu\n", acyclic_g[s].index);
- unordered_set<NFAVertex> parents;
+ DEBUG_PRINTF("handling sink %zu\n", acyclic_g[s].index);
+ unordered_set<NFAVertex> parents;
for (const auto &e : in_edges_range(s, acyclic_g)) {
- parents.insert(NFAVertex(source(e, acyclic_g)));
+ parents.insert(NFAVertex(source(e, acyclic_g)));
}
/* vertex has no children not reachable on a back edge, bubble the
@@ -408,20 +408,20 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector<NFAVertex> &topoOrder) {
}
}
-using ColorMap = decltype(make_small_color_map(NGHolder()));
-
+using ColorMap = decltype(make_small_color_map(NGHolder()));
+
/** Build a reverse topo ordering (with only the specials that are in use). We
* also want to ensure vertices which only lead to back edges are placed near
* their parents. */
static
vector<NFAVertex> buildTopoOrder(const NGHolder &w,
const AcyclicGraph &acyclic_g,
- ColorMap &colours) {
+ ColorMap &colours) {
vector<NFAVertex> topoOrder;
- topoOrder.reserve(num_vertices(w));
+ topoOrder.reserve(num_vertices(w));
- topological_sort(acyclic_g, back_inserter(topoOrder),
- color_map(colours));
+ topological_sort(acyclic_g, back_inserter(topoOrder),
+ color_map(colours));
reorderSpecials(w, acyclic_g, topoOrder);
@@ -433,35 +433,35 @@ vector<NFAVertex> buildTopoOrder(const NGHolder &w,
DEBUG_PRINTF("TOPO ORDER\n");
for (auto ri = topoOrder.rbegin(); ri != topoOrder.rend(); ++ri) {
- DEBUG_PRINTF("[%zu]\n", acyclic_g[*ri].index);
+ DEBUG_PRINTF("[%zu]\n", acyclic_g[*ri].index);
}
DEBUG_PRINTF("----------\n");
return topoOrder;
}
-unordered_map<NFAVertex, u32> assignRegions(const NGHolder &g) {
+unordered_map<NFAVertex, u32> assignRegions(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
const u32 numVertices = num_vertices(g);
DEBUG_PRINTF("assigning regions for %u vertices in holder\n", numVertices);
- auto colours = make_small_color_map(g);
+ auto colours = make_small_color_map(g);
// Build an acyclic graph for this NGHolder.
BackEdgeSet deadEdges;
- depth_first_search(g,
- visitor(BackEdges<BackEdgeSet>(deadEdges))
- .root_vertex(g.start)
- .color_map(colours));
+ depth_first_search(g,
+ visitor(BackEdges<BackEdgeSet>(deadEdges))
+ .root_vertex(g.start)
+ .color_map(colours));
- auto af = make_bad_edge_filter(&deadEdges);
- AcyclicGraph acyclic_g(g, af);
+ auto af = make_bad_edge_filter(&deadEdges);
+ AcyclicGraph acyclic_g(g, af);
// Build a (reverse) topological ordering.
vector<NFAVertex> topoOrder = buildTopoOrder(g, acyclic_g, colours);
// Everybody starts in region 0.
- unordered_map<NFAVertex, u32> regions;
+ unordered_map<NFAVertex, u32> regions;
regions.reserve(numVertices);
for (auto v : vertices_range(g)) {
regions.emplace(v, 0);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_region.h b/contrib/libs/hyperscan/src/nfagraph/ng_region.h
index 27572492e19..a4708a582ed 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_region.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_region.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,18 +37,18 @@
#include "util/container.h"
#include "util/graph_range.h"
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
namespace ue2 {
/** \brief Assign a region ID to every vertex in the graph. */
-std::unordered_map<NFAVertex, u32> assignRegions(const NGHolder &g);
+std::unordered_map<NFAVertex, u32> assignRegions(const NGHolder &g);
/** \brief True if vertices \p a and \p b are in the same region. */
template <class Graph>
bool inSameRegion(const Graph &g, NFAVertex a, NFAVertex b,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
assert(contains(region_map, a) && contains(region_map, b));
return region_map.at(a) == region_map.at(b) &&
@@ -58,7 +58,7 @@ bool inSameRegion(const Graph &g, NFAVertex a, NFAVertex b,
/** \brief True if vertex \p b is in a later region than vertex \p a. */
template <class Graph>
bool inLaterRegion(const Graph &g, NFAVertex a, NFAVertex b,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
assert(contains(region_map, a) && contains(region_map, b));
u32 aa = g[a].index;
@@ -85,7 +85,7 @@ bool inLaterRegion(const Graph &g, NFAVertex a, NFAVertex b,
/** \brief True if vertex \p b is in an earlier region than vertex \p a. */
template <class Graph>
bool inEarlierRegion(const Graph &g, NFAVertex a, NFAVertex b,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
assert(contains(region_map, a) && contains(region_map, b));
u32 aa = g[a].index;
@@ -112,7 +112,7 @@ bool inEarlierRegion(const Graph &g, NFAVertex a, NFAVertex b,
/** \brief True if vertex \p v is an entry vertex for its region. */
template <class Graph>
bool isRegionEntry(const Graph &g, NFAVertex v,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
// Note that some graph types do not have inv_adjacent_vertices, so we must
// use in_edges here.
for (const auto &e : in_edges_range(v, g)) {
@@ -127,7 +127,7 @@ bool isRegionEntry(const Graph &g, NFAVertex v,
/** \brief True if vertex \p v is an exit vertex for its region. */
template <class Graph>
bool isRegionExit(const Graph &g, NFAVertex v,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
for (auto w : adjacent_vertices_range(v, g)) {
if (!inSameRegion(g, v, w, region_map)) {
return true;
@@ -140,7 +140,7 @@ bool isRegionExit(const Graph &g, NFAVertex v,
/** \brief True if vertex \p v is in a region all on its own. */
template <class Graph>
bool isSingletonRegion(const Graph &g, NFAVertex v,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
for (const auto &e : in_edges_range(v, g)) {
auto u = source(e, g);
if (u != v && inSameRegion(g, v, u, region_map)) {
@@ -178,10 +178,10 @@ bool isSingletonRegion(const Graph &g, NFAVertex v,
*/
template <class Graph>
bool isOptionalRegion(const Graph &g, NFAVertex v,
- const std::unordered_map<NFAVertex, u32> &region_map) {
+ const std::unordered_map<NFAVertex, u32> &region_map) {
assert(isRegionEntry(g, v, region_map));
- DEBUG_PRINTF("check if r%u is optional (inspecting v%zu)\n",
+ DEBUG_PRINTF("check if r%u is optional (inspecting v%zu)\n",
region_map.at(v), g[v].index);
// Region zero is never optional.
@@ -198,12 +198,12 @@ bool isOptionalRegion(const Graph &g, NFAVertex v,
if (inSameRegion(g, v, u, region_map)) {
continue;
}
- DEBUG_PRINTF(" searching from u=%zu\n", g[u].index);
+ DEBUG_PRINTF(" searching from u=%zu\n", g[u].index);
assert(inEarlierRegion(g, v, u, region_map));
for (auto w : adjacent_vertices_range(u, g)) {
- DEBUG_PRINTF(" searching to w=%zu\n", g[w].index);
+ DEBUG_PRINTF(" searching to w=%zu\n", g[w].index);
if (inLaterRegion(g, v, w, region_map)) {
return true;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_region_redundancy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_region_redundancy.cpp
index 3ea73e78ab0..1126d4d6c98 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_region_redundancy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_region_redundancy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -60,7 +60,7 @@ struct RegionInfo {
static
bool regionHasUnexpectedAccept(const NGHolder &g, const u32 region,
const flat_set<ReportID> &expected_reports,
- const unordered_map<NFAVertex, u32> &region_map) {
+ const unordered_map<NFAVertex, u32> &region_map) {
/* TODO: only check vertices connected to accept/acceptEOD */
for (auto v : vertices_range(g)) {
if (region != region_map.at(v)) {
@@ -84,13 +84,13 @@ bool regionHasUnexpectedAccept(const NGHolder &g, const u32 region,
static
void processCyclicStateForward(NGHolder &h, NFAVertex cyc,
const map<u32, RegionInfo> &info,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
set<u32> &deadRegions) {
u32 region = region_map.at(cyc);
CharReach cr = h[cyc].char_reach;
auto reports = h[cyc].reports;
- DEBUG_PRINTF("going forward from %zu/%u\n", h[cyc].index,
+ DEBUG_PRINTF("going forward from %zu/%u\n", h[cyc].index,
region);
map<u32, RegionInfo>::const_iterator it;
@@ -98,7 +98,7 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc,
NFAVertex v = it->second.entry;
const CharReach &region_cr = it->second.cr;
assert(isRegionEntry(h, v, region_map) && !is_special(v, h));
- DEBUG_PRINTF("checking %zu\n", h[v].index);
+ DEBUG_PRINTF("checking %zu\n", h[v].index);
if (!region_cr.isSubsetOf(cr)) {
DEBUG_PRINTF("doesn't cover the reach of region %u\n", region);
@@ -107,8 +107,8 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc,
if (isOptionalRegion(h, v, region_map)
&& !regionHasUnexpectedAccept(h, region, reports, region_map)) {
- DEBUG_PRINTF("cyclic state %zu leads to optional region leader"
- " %zu\n", h[cyc].index, h[v].index);
+ DEBUG_PRINTF("cyclic state %zu leads to optional region leader"
+ " %zu\n", h[cyc].index, h[v].index);
deadRegions.insert(region);
} else if (isSingletonRegion(h, v, region_map)) {
/* we can use this region as straw and suck in optional regions on
@@ -130,20 +130,20 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc,
static
void processCyclicStateReverse(NGHolder &h, NFAVertex cyc,
const map<u32, RegionInfo> &info,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
set<u32> &deadRegions) {
u32 region = region_map.at(cyc);
CharReach cr = h[cyc].char_reach;
auto reports = h[cyc].reports;
- DEBUG_PRINTF("going back from %zu/%u\n", h[cyc].index, region);
+ DEBUG_PRINTF("going back from %zu/%u\n", h[cyc].index, region);
map<u32, RegionInfo>::const_iterator it;
while ((it = info.find(--region)) != info.end()) {
NFAVertex v = it->second.entry;
const CharReach &region_cr = it->second.cr;
assert(isRegionEntry(h, v, region_map) && !is_special(v, h));
- DEBUG_PRINTF("checking %zu\n", h[v].index);
+ DEBUG_PRINTF("checking %zu\n", h[v].index);
if (!region_cr.isSubsetOf(cr)) {
DEBUG_PRINTF("doesn't cover the reach of region %u\n", region);
@@ -152,7 +152,7 @@ void processCyclicStateReverse(NGHolder &h, NFAVertex cyc,
if (isOptionalRegion(h, v, region_map)
&& !regionHasUnexpectedAccept(h, region, reports, region_map)) {
- DEBUG_PRINTF("cyclic state %zu trails optional region leader %zu\n",
+ DEBUG_PRINTF("cyclic state %zu trails optional region leader %zu\n",
h[cyc].index, h[v].index);
deadRegions.insert(region);
} else if (isSingletonRegion(h, v, region_map)) {
@@ -179,7 +179,7 @@ void processCyclicStateReverse(NGHolder &h, NFAVertex cyc,
static
map<u32, RegionInfo> buildRegionInfoMap(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &region_map) {
+ const unordered_map<NFAVertex, u32> &region_map) {
map<u32, RegionInfo> info;
for (auto v : vertices_range(g)) {
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_repeat.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_repeat.cpp
index 95d52e855be..1f63ad3c6f0 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_repeat.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_repeat.cpp
@@ -46,16 +46,16 @@
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include "util/graph_undirected.h"
#include "util/report_manager.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <algorithm>
#include <map>
#include <queue>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/depth_first_search.hpp>
@@ -65,9 +65,9 @@
#include <boost/icl/interval_set.hpp>
using namespace std;
-using boost::depth_first_search;
-using boost::depth_first_visit;
-using boost::make_assoc_property_map;
+using boost::depth_first_search;
+using boost::depth_first_visit;
+using boost::make_assoc_property_map;
namespace ue2 {
@@ -111,8 +111,8 @@ using RepeatGraph = boost::filtered_graph<NGHolder, ReachFilter<NGHolder>,
struct ReachSubgraph {
vector<NFAVertex> vertices;
- depth repeatMin{0};
- depth repeatMax{0};
+ depth repeatMin{0};
+ depth repeatMax{0};
u32 minPeriod = 1;
bool is_reset = false;
enum RepeatType historyType = REPEAT_RING;
@@ -123,59 +123,59 @@ struct ReachSubgraph {
static
void findInitDepths(const NGHolder &g,
- unordered_map<NFAVertex, NFAVertexDepth> &depths) {
- auto d = calcDepths(g);
+ unordered_map<NFAVertex, NFAVertexDepth> &depths) {
+ auto d = calcDepths(g);
for (auto v : vertices_range(g)) {
- size_t idx = g[v].index;
+ size_t idx = g[v].index;
assert(idx < d.size());
- depths.emplace(v, d[idx]);
+ depths.emplace(v, d[idx]);
}
}
static
-vector<NFAVertex> buildTopoOrder(const RepeatGraph &g) {
- /* Note: RepeatGraph is a filtered version of NGHolder and still has
- * NFAVertex as its vertex descriptor */
-
- typedef unordered_set<NFAEdge> EdgeSet;
+vector<NFAVertex> buildTopoOrder(const RepeatGraph &g) {
+ /* Note: RepeatGraph is a filtered version of NGHolder and still has
+ * NFAVertex as its vertex descriptor */
+
+ typedef unordered_set<NFAEdge> EdgeSet;
EdgeSet deadEdges;
// We don't have indices spanning [0,N] on our filtered graph, so we
// provide a colour map.
- unordered_map<NFAVertex, boost::default_color_type> colours;
+ unordered_map<NFAVertex, boost::default_color_type> colours;
depth_first_search(g, visitor(BackEdges<EdgeSet>(deadEdges)).
color_map(make_assoc_property_map(colours)));
- auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&deadEdges));
+ auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&deadEdges));
- vector<NFAVertex> topoOrder;
+ vector<NFAVertex> topoOrder;
topological_sort(acyclic_g, back_inserter(topoOrder),
color_map(make_assoc_property_map(colours)));
reverse(topoOrder.begin(), topoOrder.end());
-
- return topoOrder;
+
+ return topoOrder;
}
static
void proper_pred(const NGHolder &g, NFAVertex v,
- unordered_set<NFAVertex> &p) {
+ unordered_set<NFAVertex> &p) {
pred(g, v, &p);
p.erase(v); // self-loops
}
static
void proper_succ(const NGHolder &g, NFAVertex v,
- unordered_set<NFAVertex> &s) {
+ unordered_set<NFAVertex> &s) {
succ(g, v, &s);
s.erase(v); // self-loops
}
static
bool roguePredecessor(const NGHolder &g, NFAVertex v,
- const unordered_set<NFAVertex> &involved,
- const unordered_set<NFAVertex> &pred) {
+ const unordered_set<NFAVertex> &involved,
+ const unordered_set<NFAVertex> &pred) {
u32 seen = 0;
for (auto u : inv_adjacent_vertices_range(v, g)) {
@@ -183,7 +183,7 @@ bool roguePredecessor(const NGHolder &g, NFAVertex v,
continue;
}
if (!contains(pred, u)) {
- DEBUG_PRINTF("%zu is a rogue pred\n", g[u].index);
+ DEBUG_PRINTF("%zu is a rogue pred\n", g[u].index);
return true;
}
@@ -200,8 +200,8 @@ bool roguePredecessor(const NGHolder &g, NFAVertex v,
static
bool rogueSuccessor(const NGHolder &g, NFAVertex v,
- const unordered_set<NFAVertex> &involved,
- const unordered_set<NFAVertex> &succ) {
+ const unordered_set<NFAVertex> &involved,
+ const unordered_set<NFAVertex> &succ) {
u32 seen = 0;
for (auto w : adjacent_vertices_range(v, g)) {
if (contains(involved, w)) {
@@ -209,7 +209,7 @@ bool rogueSuccessor(const NGHolder &g, NFAVertex v,
}
if (!contains(succ, w)) {
- DEBUG_PRINTF("%zu is a rogue succ\n", g[w].index);
+ DEBUG_PRINTF("%zu is a rogue succ\n", g[w].index);
return true;
}
@@ -226,8 +226,8 @@ bool rogueSuccessor(const NGHolder &g, NFAVertex v,
static
bool hasDifferentTops(const NGHolder &g, const vector<NFAVertex> &verts) {
- /* TODO: check that we need this now that we allow multiple tops */
- const flat_set<u32> *tops = nullptr;
+ /* TODO: check that we need this now that we allow multiple tops */
+ const flat_set<u32> *tops = nullptr;
for (auto v : verts) {
for (const auto &e : in_edges_range(v, g)) {
@@ -235,12 +235,12 @@ bool hasDifferentTops(const NGHolder &g, const vector<NFAVertex> &verts) {
if (u != g.start && u != g.startDs) {
continue; // Only edges from starts have valid top properties.
}
- DEBUG_PRINTF("edge (%zu,%zu) with %zu tops\n", g[u].index,
- g[v].index, g[e].tops.size());
- if (!tops) {
- tops = &g[e].tops;
- } else if (g[e].tops != *tops) {
- return true; // More than one set of tops.
+ DEBUG_PRINTF("edge (%zu,%zu) with %zu tops\n", g[u].index,
+ g[v].index, g[e].tops.size());
+ if (!tops) {
+ tops = &g[e].tops;
+ } else if (g[e].tops != *tops) {
+ return true; // More than one set of tops.
}
}
}
@@ -250,19 +250,19 @@ bool hasDifferentTops(const NGHolder &g, const vector<NFAVertex> &verts) {
static
bool vertexIsBad(const NGHolder &g, NFAVertex v,
- const unordered_set<NFAVertex> &involved,
- const unordered_set<NFAVertex> &tail,
- const unordered_set<NFAVertex> &pred,
- const unordered_set<NFAVertex> &succ,
+ const unordered_set<NFAVertex> &involved,
+ const unordered_set<NFAVertex> &tail,
+ const unordered_set<NFAVertex> &pred,
+ const unordered_set<NFAVertex> &succ,
const flat_set<ReportID> &reports) {
- DEBUG_PRINTF("check vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("check vertex %zu\n", g[v].index);
// We must drop any vertex that is the target of a back-edge within
// our subgraph. The tail set contains all vertices that are after v in a
// topo ordering.
for (auto u : inv_adjacent_vertices_range(v, g)) {
if (contains(tail, u)) {
- DEBUG_PRINTF("back-edge (%zu,%zu) in subgraph found\n",
+ DEBUG_PRINTF("back-edge (%zu,%zu) in subgraph found\n",
g[u].index, g[v].index);
return true;
}
@@ -272,18 +272,18 @@ bool vertexIsBad(const NGHolder &g, NFAVertex v,
// edges from *all* the vertices in pred and no other external entries.
// Similarly for exits.
if (roguePredecessor(g, v, involved, pred)) {
- DEBUG_PRINTF("preds for %zu not well-formed\n", g[v].index);
+ DEBUG_PRINTF("preds for %zu not well-formed\n", g[v].index);
return true;
}
if (rogueSuccessor(g, v, involved, succ)) {
- DEBUG_PRINTF("succs for %zu not well-formed\n", g[v].index);
+ DEBUG_PRINTF("succs for %zu not well-formed\n", g[v].index);
return true;
}
// All reporting vertices should have the same reports.
if (is_match_vertex(v, g) && reports != g[v].reports) {
- DEBUG_PRINTF("report mismatch to %zu\n", g[v].index);
+ DEBUG_PRINTF("report mismatch to %zu\n", g[v].index);
return true;
}
@@ -298,7 +298,7 @@ void splitSubgraph(const NGHolder &g, const deque<NFAVertex> &verts,
// We construct a copy of the graph using just the vertices we want, rather
// than using a filtered_graph -- this way is faster.
NGHolder verts_g;
- unordered_map<NFAVertex, NFAVertex> verts_map; // in g -> in verts_g
+ unordered_map<NFAVertex, NFAVertex> verts_map; // in g -> in verts_g
fillHolder(&verts_g, g, verts, &verts_map);
const auto ug = make_undirected_graph(verts_g);
@@ -388,10 +388,10 @@ void checkReachSubgraphs(const NGHolder &g, vector<ReachSubgraph> &rs,
continue;
}
- unordered_set<NFAVertex> involved(rsi.vertices.begin(),
- rsi.vertices.end());
- unordered_set<NFAVertex> tail(involved); // to look for back-edges.
- unordered_set<NFAVertex> pred, succ;
+ unordered_set<NFAVertex> involved(rsi.vertices.begin(),
+ rsi.vertices.end());
+ unordered_set<NFAVertex> tail(involved); // to look for back-edges.
+ unordered_set<NFAVertex> pred, succ;
proper_pred(g, rsi.vertices.front(), pred);
proper_succ(g, rsi.vertices.back(), succ);
@@ -525,7 +525,7 @@ bool processSubgraph(const NGHolder &g, ReachSubgraph &rsi,
NFAVertex first = rsi.vertices.front();
NFAVertex last = rsi.vertices.back();
- typedef unordered_map<NFAVertex, DistanceSet> DistanceMap;
+ typedef unordered_map<NFAVertex, DistanceSet> DistanceMap;
DistanceMap dist;
// Initial distance sets.
@@ -533,7 +533,7 @@ bool processSubgraph(const NGHolder &g, ReachSubgraph &rsi,
if (u == first) {
continue; // no self-loops
}
- DEBUG_PRINTF("pred vertex %zu\n", g[u].index);
+ DEBUG_PRINTF("pred vertex %zu\n", g[u].index);
dist[u].insert(0);
}
@@ -597,8 +597,8 @@ bool processSubgraph(const NGHolder &g, ReachSubgraph &rsi,
range.first, range.second);
return false;
}
- rsi.repeatMin = depth(range.first);
- rsi.repeatMax = depth(range.second);
+ rsi.repeatMin = depth(range.first);
+ rsi.repeatMax = depth(range.second);
// If we've got a self-loop anywhere, we've got inf max.
if (anySelfLoop(g, rsi.vertices.begin(), rsi.vertices.end())) {
@@ -619,7 +619,7 @@ bool processSubgraph(const NGHolder &g, ReachSubgraph &rsi,
static
bool allPredsInSubgraph(NFAVertex v, const NGHolder &g,
- const unordered_set<NFAVertex> &involved) {
+ const unordered_set<NFAVertex> &involved) {
for (auto u : inv_adjacent_vertices_range(v, g)) {
if (!contains(involved, u)) {
return false;
@@ -630,12 +630,12 @@ bool allPredsInSubgraph(NFAVertex v, const NGHolder &g,
static
void buildTugTrigger(NGHolder &g, NFAVertex cyclic, NFAVertex v,
- const unordered_set<NFAVertex> &involved,
- unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ const unordered_set<NFAVertex> &involved,
+ unordered_map<NFAVertex, NFAVertexDepth> &depths,
vector<NFAVertex> &tugs) {
if (allPredsInSubgraph(v, g, involved)) {
// We can transform this vertex into a tug trigger in-place.
- DEBUG_PRINTF("all preds in subgraph, vertex %zu becomes tug\n",
+ DEBUG_PRINTF("all preds in subgraph, vertex %zu becomes tug\n",
g[v].index);
add_edge(cyclic, v, g);
tugs.push_back(v);
@@ -647,7 +647,7 @@ void buildTugTrigger(NGHolder &g, NFAVertex cyclic, NFAVertex v,
NFAVertex t = clone_vertex(g, v);
depths[t] = depths[v];
- DEBUG_PRINTF("there are other paths, cloned tug %zu from vertex %zu\n",
+ DEBUG_PRINTF("there are other paths, cloned tug %zu from vertex %zu\n",
g[t].index, g[v].index);
tugs.push_back(t);
@@ -664,7 +664,7 @@ NFAVertex createCyclic(NGHolder &g, ReachSubgraph &rsi) {
NFAVertex cyclic = clone_vertex(g, last);
add_edge(cyclic, cyclic, g);
- DEBUG_PRINTF("created cyclic vertex %zu\n", g[cyclic].index);
+ DEBUG_PRINTF("created cyclic vertex %zu\n", g[cyclic].index);
return cyclic;
}
@@ -675,7 +675,7 @@ NFAVertex createPos(NGHolder &g, ReachSubgraph &rsi) {
g[pos].char_reach = g[first].char_reach;
- DEBUG_PRINTF("created pos vertex %zu\n", g[pos].index);
+ DEBUG_PRINTF("created pos vertex %zu\n", g[pos].index);
return pos;
}
@@ -710,7 +710,7 @@ u32 unpeelAmount(const NGHolder &g, const ReachSubgraph &rsi) {
static
void unpeelNearEnd(NGHolder &g, ReachSubgraph &rsi,
- unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ unordered_map<NFAVertex, NFAVertexDepth> &depths,
vector<NFAVertex> *succs) {
u32 unpeel = unpeelAmount(g, rsi);
DEBUG_PRINTF("unpeeling %u vertices\n", unpeel);
@@ -721,7 +721,7 @@ void unpeelNearEnd(NGHolder &g, ReachSubgraph &rsi,
NFAVertex d = clone_vertex(g, last);
depths[d] = depths[last];
- DEBUG_PRINTF("created vertex %zu\n", g[d].index);
+ DEBUG_PRINTF("created vertex %zu\n", g[d].index);
for (auto v : *succs) {
add_edge(d, v, g);
@@ -769,24 +769,24 @@ void getSuccessors(const NGHolder &g, const ReachSubgraph &rsi,
* NFA graph and replace it with a cyclic state. */
static
void replaceSubgraphWithSpecial(NGHolder &g, ReachSubgraph &rsi,
- vector<BoundedRepeatData> *repeats,
- unordered_map<NFAVertex, NFAVertexDepth> &depths,
- unordered_set<NFAVertex> &created) {
+ vector<BoundedRepeatData> *repeats,
+ unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ unordered_set<NFAVertex> &created) {
assert(!rsi.bad);
- /* As we may need to unpeel 2 vertices, we need the width to be more than 2.
- * This should only happen if the graph did not have redundancy pass
- * performed on as vertex count checks would be prevent us reaching here.
- */
- if (rsi.repeatMax <= depth(2)) {
- return;
- }
+ /* As we may need to unpeel 2 vertices, we need the width to be more than 2.
+ * This should only happen if the graph did not have redundancy pass
+ * performed on as vertex count checks would be prevent us reaching here.
+ */
+ if (rsi.repeatMax <= depth(2)) {
+ return;
+ }
assert(rsi.repeatMin > depth(0));
assert(rsi.repeatMax >= rsi.repeatMin);
- assert(rsi.repeatMax > depth(2));
+ assert(rsi.repeatMax > depth(2));
DEBUG_PRINTF("entry\n");
- const unordered_set<NFAVertex> involved(rsi.vertices.begin(),
+ const unordered_set<NFAVertex> involved(rsi.vertices.begin(),
rsi.vertices.end());
vector<NFAVertex> succs;
getSuccessors(g, rsi, &succs);
@@ -847,16 +847,16 @@ void replaceSubgraphWithSpecial(NGHolder &g, ReachSubgraph &rsi,
static
void replaceSubgraphWithLazySpecial(NGHolder &g, ReachSubgraph &rsi,
vector<BoundedRepeatData> *repeats,
- unordered_map<NFAVertex, NFAVertexDepth> &depths,
- unordered_set<NFAVertex> &created) {
+ unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ unordered_set<NFAVertex> &created) {
assert(!rsi.bad);
assert(rsi.repeatMin);
assert(rsi.repeatMax >= rsi.repeatMin);
DEBUG_PRINTF("entry\n");
- const unordered_set<NFAVertex> involved(rsi.vertices.begin(),
- rsi.vertices.end());
+ const unordered_set<NFAVertex> involved(rsi.vertices.begin(),
+ rsi.vertices.end());
vector<NFAVertex> succs;
getSuccessors(g, rsi, &succs);
@@ -950,7 +950,7 @@ void reprocessSubgraph(const NGHolder &h, const Grey &grey,
* involved in other repeats as a result of earlier repeat transformations. */
static
bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi,
- const unordered_set<NFAVertex> &created) {
+ const unordered_set<NFAVertex> &created) {
assert(!rsi.bad);
if (created.empty()) {
@@ -969,7 +969,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi,
zap = it;
break;
} else {
- DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index);
+ DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index);
}
}
DEBUG_PRINTF("peeling %zu vertices from front\n",
@@ -986,7 +986,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi,
zap = it.base(); // Note: erases everything after it.
break;
} else {
- DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index);
+ DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index);
}
}
DEBUG_PRINTF("peeling %zu vertices from back\n",
@@ -997,7 +997,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi,
// no-no.
for (auto v : rsi.vertices) {
if (contains(created, v)) {
- DEBUG_PRINTF("vertex %zu is in another repeat\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu is in another repeat\n", g[v].index);
return false;
}
}
@@ -1012,15 +1012,15 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi,
* idea to extend to cyclic states, too. */
static
void peelStartDotStar(const NGHolder &g,
- const unordered_map<NFAVertex, NFAVertexDepth> &depths,
- const Grey &grey, ReachSubgraph &rsi) {
+ const unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ const Grey &grey, ReachSubgraph &rsi) {
if (rsi.vertices.size() < 1) {
return;
}
NFAVertex first = rsi.vertices.front();
if (depths.at(first).fromStartDotStar.min == depth(1)) {
- DEBUG_PRINTF("peeling start front vertex %zu\n", g[first].index);
+ DEBUG_PRINTF("peeling start front vertex %zu\n", g[first].index);
rsi.vertices.erase(rsi.vertices.begin());
reprocessSubgraph(g, grey, rsi);
}
@@ -1029,7 +1029,7 @@ void peelStartDotStar(const NGHolder &g,
static
void buildReachSubgraphs(const NGHolder &g, vector<ReachSubgraph> &rs,
const u32 minNumVertices) {
- const ReachFilter<NGHolder> fil(&g);
+ const ReachFilter<NGHolder> fil(&g);
const RepeatGraph rg(g, fil, fil);
if (!isCompBigEnough(rg, minNumVertices)) {
@@ -1046,7 +1046,7 @@ void buildReachSubgraphs(const NGHolder &g, vector<ReachSubgraph> &rs,
DEBUG_PRINTF("found %u connected repeat components\n", num);
// Now, we build a set of topo-ordered ReachSubgraphs.
- vector<NFAVertex> topoOrder = buildTopoOrder(rg);
+ vector<NFAVertex> topoOrder = buildTopoOrder(rg);
rs.resize(num);
@@ -1089,14 +1089,14 @@ bool hasSkipEdges(const NGHolder &g, const ReachSubgraph &rsi) {
/* depth info is valid as calculated at entry */
static
bool entered_at_fixed_offset(NFAVertex v, const NGHolder &g,
- const unordered_map<NFAVertex, NFAVertexDepth> &depths,
- const unordered_set<NFAVertex> &reached_by_fixed_tops) {
+ const unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ const unordered_set<NFAVertex> &reached_by_fixed_tops) {
DEBUG_PRINTF("|reached_by_fixed_tops| %zu\n",
reached_by_fixed_tops.size());
if (is_triggered(g) && !contains(reached_by_fixed_tops, v)) {
/* can't do this for infix/suffixes unless we know trigger literals
* can only occur at one offset */
- DEBUG_PRINTF("bad top(s) for %zu\n", g[v].index);
+ DEBUG_PRINTF("bad top(s) for %zu\n", g[v].index);
return false;
}
@@ -1116,8 +1116,8 @@ bool entered_at_fixed_offset(NFAVertex v, const NGHolder &g,
for (auto u : inv_adjacent_vertices_range(v, g)) {
const depth &u_max_depth = depths.at(u).fromStart.max;
- DEBUG_PRINTF("pred %zu max depth %s from start\n", g[u].index,
- u_max_depth.str().c_str());
+ DEBUG_PRINTF("pred %zu max depth %s from start\n", g[u].index,
+ u_max_depth.str().c_str());
if (u_max_depth != first - depth(1)) {
return false;
}
@@ -1135,12 +1135,12 @@ NFAVertex buildTriggerStates(NGHolder &g, const vector<CharReach> &trigger,
g[v].char_reach = cr;
add_edge(u, v, g);
if (u == g.start) {
- g[edge(u, v, g)].tops.insert(top);
+ g[edge(u, v, g)].tops.insert(top);
}
u = v;
}
- DEBUG_PRINTF("trigger len=%zu has sink %zu\n", trigger.size(), g[u].index);
+ DEBUG_PRINTF("trigger len=%zu has sink %zu\n", trigger.size(), g[u].index);
return u;
}
@@ -1165,21 +1165,21 @@ void addTriggers(NGHolder &g,
continue;
}
- const auto &tops = g[e].tops;
+ const auto &tops = g[e].tops;
// The caller may not have given us complete trigger information. If we
// don't have any triggers for a particular top, we should just leave
// it alone.
- for (u32 top : tops) {
- if (!contains(triggers, top)) {
- DEBUG_PRINTF("no triggers for top %u\n", top);
- goto next_edge;
- }
-
- starts_by_top[top].push_back(v);
+ for (u32 top : tops) {
+ if (!contains(triggers, top)) {
+ DEBUG_PRINTF("no triggers for top %u\n", top);
+ goto next_edge;
+ }
+
+ starts_by_top[top].push_back(v);
}
dead.push_back(e);
- next_edge:;
+ next_edge:;
}
remove_edges(dead, g);
@@ -1216,12 +1216,12 @@ CharReach predReach(const NGHolder &g, NFAVertex v) {
*/
static
void filterMap(const NGHolder &subg,
- unordered_map<NFAVertex, NFAVertex> &vmap) {
- NGHolder::vertex_iterator vi, ve;
+ unordered_map<NFAVertex, NFAVertex> &vmap) {
+ NGHolder::vertex_iterator vi, ve;
tie(vi, ve) = vertices(subg);
- const unordered_set<NFAVertex> remaining_verts(vi, ve);
+ const unordered_set<NFAVertex> remaining_verts(vi, ve);
- unordered_map<NFAVertex, NFAVertex> fmap; // filtered map
+ unordered_map<NFAVertex, NFAVertex> fmap; // filtered map
for (const auto &m : vmap) {
if (contains(remaining_verts, m.second)) {
@@ -1236,7 +1236,7 @@ void filterMap(const NGHolder &subg,
* the bounded repeat. */
static
void buildRepeatGraph(NGHolder &rg,
- unordered_map<NFAVertex, NFAVertex> &rg_map,
+ unordered_map<NFAVertex, NFAVertex> &rg_map,
const NGHolder &g, const ReachSubgraph &rsi,
const map<u32, vector<vector<CharReach>>> &triggers) {
cloneHolder(rg, g, &rg_map);
@@ -1247,7 +1247,7 @@ void buildRepeatGraph(NGHolder &rg,
add_edge(rg.accept, rg.acceptEod, rg);
// Find the set of vertices in rg involved in the repeat.
- unordered_set<NFAVertex> rg_involved;
+ unordered_set<NFAVertex> rg_involved;
for (const auto &v : rsi.vertices) {
assert(contains(rg_map, v));
rg_involved.insert(rg_map.at(v));
@@ -1270,7 +1270,7 @@ void buildRepeatGraph(NGHolder &rg,
if (is_triggered(rg)) {
// Add vertices for all our triggers
addTriggers(rg, triggers);
- renumber_vertices(rg);
+ renumber_vertices(rg);
// We don't know anything about how often this graph is triggered, so we
// make the start vertex cyclic for the purposes of this analysis ONLY.
@@ -1289,29 +1289,29 @@ void buildRepeatGraph(NGHolder &rg,
*/
static
void buildInputGraph(NGHolder &lhs,
- unordered_map<NFAVertex, NFAVertex> &lhs_map,
+ unordered_map<NFAVertex, NFAVertex> &lhs_map,
const NGHolder &g, const NFAVertex first,
const map<u32, vector<vector<CharReach>>> &triggers) {
- DEBUG_PRINTF("building lhs with first=%zu\n", g[first].index);
+ DEBUG_PRINTF("building lhs with first=%zu\n", g[first].index);
cloneHolder(lhs, g, &lhs_map);
assert(g.kind == lhs.kind);
addTriggers(lhs, triggers);
- renumber_vertices(lhs);
+ renumber_vertices(lhs);
// Replace each back-edge (u,v) with an edge (startDs,v), which will
// generate entries at at least the rate of the loop created by that
// back-edge.
set<NFAEdge> dead;
BackEdges<set<NFAEdge> > backEdgeVisitor(dead);
- depth_first_search(lhs, visitor(backEdgeVisitor).root_vertex(lhs.start));
+ depth_first_search(lhs, visitor(backEdgeVisitor).root_vertex(lhs.start));
for (const auto &e : dead) {
const NFAVertex u = source(e, lhs), v = target(e, lhs);
if (u == v) {
continue; // Self-loops are OK.
}
- DEBUG_PRINTF("replacing back-edge (%zu,%zu) with edge (startDs,%zu)\n",
- lhs[u].index, lhs[v].index, lhs[v].index);
+ DEBUG_PRINTF("replacing back-edge (%zu,%zu) with edge (startDs,%zu)\n",
+ lhs[u].index, lhs[v].index, lhs[v].index);
add_edge_if_not_present(lhs.startDs, v, lhs);
remove_edge(e, lhs);
@@ -1343,8 +1343,8 @@ static const size_t MAX_SOLE_ENTRY_VERTICES = 10000;
* single offset at runtime. See UE-1361. */
static
bool hasSoleEntry(const NGHolder &g, const ReachSubgraph &rsi,
- const unordered_map<NFAVertex, NFAVertexDepth> &depths,
- const unordered_set<NFAVertex> &reached_by_fixed_tops,
+ const unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ const unordered_set<NFAVertex> &reached_by_fixed_tops,
const map<u32, vector<vector<CharReach>>> &triggers) {
DEBUG_PRINTF("checking repeat {%s,%s}\n", rsi.repeatMin.str().c_str(),
rsi.repeatMax.str().c_str());
@@ -1374,12 +1374,12 @@ bool hasSoleEntry(const NGHolder &g, const ReachSubgraph &rsi,
}
NGHolder rg;
- unordered_map<NFAVertex, NFAVertex> rg_map;
+ unordered_map<NFAVertex, NFAVertex> rg_map;
buildRepeatGraph(rg, rg_map, g, rsi, triggers);
assert(rg.kind == g.kind);
NGHolder lhs;
- unordered_map<NFAVertex, NFAVertex> lhs_map;
+ unordered_map<NFAVertex, NFAVertex> lhs_map;
buildInputGraph(lhs, lhs_map, g, first, triggers);
assert(lhs.kind == g.kind);
@@ -1393,18 +1393,18 @@ bool hasSoleEntry(const NGHolder &g, const ReachSubgraph &rsi,
// are in one region, vertices in the bounded repeat are in another.
const u32 lhs_region = 1;
const u32 repeat_region = 2;
- unordered_map<NFAVertex, u32> region_map;
+ unordered_map<NFAVertex, u32> region_map;
for (const auto &v : rsi.vertices) {
assert(!is_special(v, g)); // no specials in repeats
assert(contains(rg_map, v));
- DEBUG_PRINTF("rg vertex %zu in repeat\n", rg[rg_map.at(v)].index);
+ DEBUG_PRINTF("rg vertex %zu in repeat\n", rg[rg_map.at(v)].index);
region_map.emplace(rg_map.at(v), repeat_region);
}
for (const auto &v : vertices_range(rg)) {
if (!contains(region_map, v)) {
- DEBUG_PRINTF("rg vertex %zu in lhs (trigger)\n", rg[v].index);
+ DEBUG_PRINTF("rg vertex %zu in lhs (trigger)\n", rg[v].index);
region_map.emplace(v, lhs_region);
}
}
@@ -1446,7 +1446,7 @@ struct StrawWalker {
if (next == v) { // Ignore self loop.
++ai;
if (ai == ae) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
next = *ai;
}
@@ -1461,7 +1461,7 @@ struct StrawWalker {
succs.erase(v);
for (tie(ai, ae) = adjacent_vertices(v, g); ai != ae; ++ai) {
next = *ai;
- DEBUG_PRINTF("checking %zu\n", g[next].index);
+ DEBUG_PRINTF("checking %zu\n", g[next].index);
if (next == v) {
continue;
}
@@ -1482,31 +1482,31 @@ struct StrawWalker {
return next;
}
DEBUG_PRINTF("bailing\n");
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
return next;
}
NFAVertex walk(NFAVertex v, vector<NFAVertex> &straw) const {
- DEBUG_PRINTF("walk from %zu\n", g[v].index);
- unordered_set<NFAVertex> visited;
+ DEBUG_PRINTF("walk from %zu\n", g[v].index);
+ unordered_set<NFAVertex> visited;
straw.clear();
while (!is_special(v, g)) {
- DEBUG_PRINTF("checking %zu\n", g[v].index);
+ DEBUG_PRINTF("checking %zu\n", g[v].index);
NFAVertex next = step(v);
- if (next == NGHolder::null_vertex()) {
+ if (next == NGHolder::null_vertex()) {
break;
}
if (!visited.insert(next).second) {
- DEBUG_PRINTF("already visited %zu, bailing\n", g[next].index);
+ DEBUG_PRINTF("already visited %zu, bailing\n", g[next].index);
break; /* don't want to get stuck in any complicated loops */
}
const CharReach &reach_v = g[v].char_reach;
const CharReach &reach_next = g[next].char_reach;
if (!reach_v.isSubsetOf(reach_next)) {
- DEBUG_PRINTF("%zu's reach is not a superset of %zu's\n",
+ DEBUG_PRINTF("%zu's reach is not a superset of %zu's\n",
g[next].index, g[v].index);
break;
}
@@ -1514,7 +1514,7 @@ struct StrawWalker {
// If this is cyclic with the right reach, we're done. Note that
// startDs fulfils this requirement.
if (hasSelfLoop(next, g) && !isBoundedRepeatCyclic(next)) {
- DEBUG_PRINTF("found cyclic %zu\n", g[next].index);
+ DEBUG_PRINTF("found cyclic %zu\n", g[next].index);
return next;
}
@@ -1523,7 +1523,7 @@ struct StrawWalker {
}
straw.clear();
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
private:
@@ -1538,8 +1538,8 @@ static
NFAVertex walkStrawToCyclicRev(const NGHolder &g, NFAVertex v,
const vector<BoundedRepeatData> &all_repeats,
vector<NFAVertex> &straw) {
- typedef boost::reverse_graph<NGHolder, const NGHolder &> RevGraph;
- const RevGraph revg(g);
+ typedef boost::reverse_graph<NGHolder, const NGHolder &> RevGraph;
+ const RevGraph revg(g);
auto cyclic = StrawWalker<RevGraph>(g, revg, all_repeats).walk(v, straw);
reverse(begin(straw), end(straw)); // path comes from cyclic
@@ -1550,7 +1550,7 @@ static
NFAVertex walkStrawToCyclicFwd(const NGHolder &g, NFAVertex v,
const vector<BoundedRepeatData> &all_repeats,
vector<NFAVertex> &straw) {
- return StrawWalker<NGHolder>(g, g, all_repeats).walk(v, straw);
+ return StrawWalker<NGHolder>(g, g, all_repeats).walk(v, straw);
}
/** True if entries to this subgraph must pass through a cyclic state with
@@ -1566,7 +1566,7 @@ bool hasCyclicSupersetEntryPath(const NGHolder &g, const ReachSubgraph &rsi,
// until we encounter our cyclic, all of which must have superset reach.
vector<NFAVertex> straw;
return walkStrawToCyclicRev(g, rsi.vertices.front(), all_repeats, straw) !=
- NGHolder::null_vertex();
+ NGHolder::null_vertex();
}
static
@@ -1574,7 +1574,7 @@ bool hasCyclicSupersetExitPath(const NGHolder &g, const ReachSubgraph &rsi,
const vector<BoundedRepeatData> &all_repeats) {
vector<NFAVertex> straw;
return walkStrawToCyclicFwd(g, rsi.vertices.back(), all_repeats, straw) !=
- NGHolder::null_vertex();
+ NGHolder::null_vertex();
}
static
@@ -1610,7 +1610,7 @@ vector<CharReach> getUnionedTrigger(const NGHolder &g, const NFAVertex v) {
vector<CharReach> trigger;
- flat_set<NFAVertex> curr, next;
+ flat_set<NFAVertex> curr, next;
insert(&curr, inv_adjacent_vertices(v, g));
if (contains(curr, g.start)) {
@@ -1711,7 +1711,7 @@ vector<vector<CharReach>> getRepeatTriggers(const NGHolder &g,
assert(!done.empty());
// Convert our path list into a set of unique triggers.
- ue2_unordered_set<vector<CharReach>> unique_triggers;
+ ue2_unordered_set<vector<CharReach>> unique_triggers;
for (const auto &path : done) {
vector<CharReach> reach_path;
for (auto jt = path.rbegin(), jte = path.rend(); jt != jte; ++jt) {
@@ -1759,8 +1759,8 @@ static
void
selectHistoryScheme(const NGHolder &g, const ReportManager *rm,
ReachSubgraph &rsi,
- const unordered_map<NFAVertex, NFAVertexDepth> &depths,
- const unordered_set<NFAVertex> &reached_by_fixed_tops,
+ const unordered_map<NFAVertex, NFAVertexDepth> &depths,
+ const unordered_set<NFAVertex> &reached_by_fixed_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
const vector<BoundedRepeatData> &all_repeats,
const bool simple_model_selection) {
@@ -1828,7 +1828,7 @@ selectHistoryScheme(const NGHolder &g, const ReportManager *rm,
static
void buildFeeder(NGHolder &g, const BoundedRepeatData &rd,
- unordered_set<NFAVertex> &created,
+ unordered_set<NFAVertex> &created,
const vector<NFAVertex> &straw) {
if (!g[rd.cyclic].char_reach.all()) {
// Create another cyclic feeder state with flipped reach. It has an
@@ -1857,7 +1857,7 @@ void buildFeeder(NGHolder &g, const BoundedRepeatData &rd,
add_edge(u, feeder, g);
}
- DEBUG_PRINTF("added feeder %zu\n", g[feeder].index);
+ DEBUG_PRINTF("added feeder %zu\n", g[feeder].index);
} else {
// No neg trigger means feeder is empty, and unnecessary.
assert(g[rd.pos_trigger].char_reach.all());
@@ -1875,7 +1875,7 @@ void buildFeeder(NGHolder &g, const BoundedRepeatData &rd,
*/
static
bool improveLeadingRepeat(NGHolder &g, BoundedRepeatData &rd,
- unordered_set<NFAVertex> &created,
+ unordered_set<NFAVertex> &created,
const vector<BoundedRepeatData> &all_repeats) {
assert(edge(g.startDs, g.startDs, g).second);
@@ -1905,13 +1905,13 @@ bool improveLeadingRepeat(NGHolder &g, BoundedRepeatData &rd,
// This transformation is only safe if the straw path from startDs that
// we've discovered can *only* lead to this repeat, since we're going to
// remove the self-loop on startDs.
- if (proper_out_degree(g.startDs, g) > 1) {
+ if (proper_out_degree(g.startDs, g) > 1) {
DEBUG_PRINTF("startDs has other successors\n");
return false;
}
for (const auto &v : straw) {
if (proper_out_degree(v, g) != 1) {
- DEBUG_PRINTF("branch between startDs and repeat, from vertex %zu\n",
+ DEBUG_PRINTF("branch between startDs and repeat, from vertex %zu\n",
g[v].index);
return false;
}
@@ -1979,7 +1979,7 @@ vector<NFAVertex> makeOwnStraw(NGHolder &g, BoundedRepeatData &rd,
*/
static
bool improveLeadingRepeatOutfix(NGHolder &g, BoundedRepeatData &rd,
- unordered_set<NFAVertex> &created,
+ unordered_set<NFAVertex> &created,
const vector<BoundedRepeatData> &all_repeats) {
assert(g.kind == NFA_OUTFIX);
@@ -2077,12 +2077,12 @@ bool endsInAcceptEod(const NGHolder &g, const ReachSubgraph &rsi) {
namespace {
class pfti_visitor : public boost::default_dfs_visitor {
public:
- pfti_visitor(unordered_map<NFAVertex, depth> &top_depths_in,
+ pfti_visitor(unordered_map<NFAVertex, depth> &top_depths_in,
const depth &our_depth_in)
: top_depths(top_depths_in), our_depth(our_depth_in) {}
- void discover_vertex(NFAVertex v, UNUSED const NGHolder &g) {
- DEBUG_PRINTF("discovered %zu (depth %s)\n", g[v].index,
+ void discover_vertex(NFAVertex v, UNUSED const NGHolder &g) {
+ DEBUG_PRINTF("discovered %zu (depth %s)\n", g[v].index,
our_depth.str().c_str());
auto it = top_depths.find(v);
@@ -2093,7 +2093,7 @@ public:
top_depths[v] = our_depth;
}
}
- unordered_map<NFAVertex, depth> &top_depths;
+ unordered_map<NFAVertex, depth> &top_depths;
const depth &our_depth;
};
} // namespace
@@ -2101,51 +2101,51 @@ public:
static
void populateFixedTopInfo(const map<u32, u32> &fixed_depth_tops,
const NGHolder &g,
- unordered_set<NFAVertex> *reached_by_fixed_tops) {
+ unordered_set<NFAVertex> *reached_by_fixed_tops) {
if (fixed_depth_tops.empty()) {
return; /* we will never find anything */
}
assert(!proper_out_degree(g.startDs, g));
- unordered_map<NFAVertex, depth> top_depths;
- auto colours = make_small_color_map(g);
+ unordered_map<NFAVertex, depth> top_depths;
+ auto colours = make_small_color_map(g);
for (const auto &e : out_edges_range(g.start, g)) {
NFAVertex v = target(e, g);
if (v == g.startDs) {
continue;
}
-
+
depth td = depth::infinity();
- for (u32 top : g[e].tops) {
- if (!contains(fixed_depth_tops, top)) {
- td = depth::infinity();
- break;
- }
- depth td_t(fixed_depth_tops.at(top));
- if (td == td_t) {
- continue;
- } else if (td == depth::infinity()) {
- td = td_t;
- } else {
- td = depth::infinity();
- break;
- }
- }
-
- DEBUG_PRINTF("scanning from %zu depth=%s\n", g[v].index,
- td.str().c_str());
+ for (u32 top : g[e].tops) {
+ if (!contains(fixed_depth_tops, top)) {
+ td = depth::infinity();
+ break;
+ }
+ depth td_t(fixed_depth_tops.at(top));
+ if (td == td_t) {
+ continue;
+ } else if (td == depth::infinity()) {
+ td = td_t;
+ } else {
+ td = depth::infinity();
+ break;
+ }
+ }
+
+ DEBUG_PRINTF("scanning from %zu depth=%s\n", g[v].index,
+ td.str().c_str());
/* for each vertex reachable from v update its map to reflect that it is
* reachable from a top of depth td. */
- depth_first_visit(g, v, pfti_visitor(top_depths, td), colours);
+ depth_first_visit(g, v, pfti_visitor(top_depths, td), colours);
}
for (const auto &v_depth : top_depths) {
const NFAVertex v = v_depth.first;
const depth &d = v_depth.second;
if (d.is_finite()) {
- DEBUG_PRINTF("%zu reached by fixed tops at depth %s\n",
+ DEBUG_PRINTF("%zu reached by fixed tops at depth %s\n",
g[v].index, d.str().c_str());
reached_by_fixed_tops->insert(v);
}
@@ -2158,20 +2158,20 @@ void populateFixedTopInfo(const map<u32, u32> &fixed_depth_tops,
static
bool hasOverlappingRepeats(UNUSED const NGHolder &g,
const vector<BoundedRepeatData> &repeats) {
- unordered_set<NFAVertex> involved;
+ unordered_set<NFAVertex> involved;
for (const auto &br : repeats) {
if (contains(involved, br.cyclic)) {
- DEBUG_PRINTF("already seen cyclic %zu\n", g[br.cyclic].index);
+ DEBUG_PRINTF("already seen cyclic %zu\n", g[br.cyclic].index);
return true;
}
if (contains(involved, br.pos_trigger)) {
- DEBUG_PRINTF("already seen pos %zu\n", g[br.pos_trigger].index);
+ DEBUG_PRINTF("already seen pos %zu\n", g[br.pos_trigger].index);
return true;
}
for (auto v : br.tug_triggers) {
if (contains(involved, v)) {
- DEBUG_PRINTF("already seen tug %zu\n", g[v].index);
+ DEBUG_PRINTF("already seen tug %zu\n", g[v].index);
return true;
}
}
@@ -2193,7 +2193,7 @@ bool hasOverlappingRepeats(UNUSED const NGHolder &g,
*/
static
bool repeatIsNasty(const NGHolder &g, const ReachSubgraph &rsi,
- const unordered_map<NFAVertex, NFAVertexDepth> &depths) {
+ const unordered_map<NFAVertex, NFAVertexDepth> &depths) {
if (num_vertices(g) > NFA_MAX_STATES) {
// We may have no choice but to implement this repeat to get the graph
// down to a tractable number of vertices.
@@ -2246,13 +2246,13 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm,
#ifndef NDEBUG
// So we can assert that the number of tops hasn't changed at the end of
// this analysis.
- const flat_set<u32> allTops = getTops(g);
+ const flat_set<u32> allTops = getTops(g);
#endif
// Later on, we're (a little bit) dependent on depth information for
// unpeeling and so forth. Note that these depths MUST be maintained when
// new vertices are added.
- unordered_map<NFAVertex, NFAVertexDepth> depths;
+ unordered_map<NFAVertex, NFAVertexDepth> depths;
findInitDepths(g, depths);
// Construct our list of subgraphs with the same reach using BGL magic.
@@ -2309,15 +2309,15 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm,
// could make this unnecessary?
const unique_ptr<const NGHolder> orig_g(cloneHolder(g));
- unordered_set<NFAVertex> reached_by_fixed_tops;
+ unordered_set<NFAVertex> reached_by_fixed_tops;
if (is_triggered(g)) {
populateFixedTopInfo(fixed_depth_tops, g, &reached_by_fixed_tops);
}
// Go to town on the remaining acceptable subgraphs.
- unordered_set<NFAVertex> created;
+ unordered_set<NFAVertex> created;
for (auto &rsi : rs) {
- DEBUG_PRINTF("subgraph (beginning vertex %zu) is a {%s,%s} repeat\n",
+ DEBUG_PRINTF("subgraph (beginning vertex %zu) is a {%s,%s} repeat\n",
g[rsi.vertices.front()].index,
rsi.repeatMin.str().c_str(), rsi.repeatMax.str().c_str());
@@ -2350,7 +2350,7 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm,
// Some of our analyses require correctly numbered vertices, so we
// renumber after changes.
- renumber_vertices(g);
+ renumber_vertices(g);
}
bool modified_start_ds = false;
@@ -2391,8 +2391,8 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm,
// We have modified the graph, so we need to ensure that our edges
// and vertices are correctly numbered.
- renumber_vertices(g);
- renumber_edges(g);
+ renumber_vertices(g);
+ renumber_edges(g);
// Remove stray report IDs.
clearReports(g);
}
@@ -2431,20 +2431,20 @@ bool isPureRepeat(const NGHolder &g, PureRepeat &repeat) {
// Must be start anchored.
assert(edge(g.startDs, g.startDs, g).second);
- if (out_degree(g.startDs, g) > 1) {
+ if (out_degree(g.startDs, g) > 1) {
DEBUG_PRINTF("Unanchored\n");
return false;
}
// Must not be EOD-anchored.
assert(edge(g.accept, g.acceptEod, g).second);
- if (in_degree(g.acceptEod, g) > 1) {
+ if (in_degree(g.acceptEod, g) > 1) {
DEBUG_PRINTF("EOD anchored\n");
return false;
}
// Must have precisely one top.
- if (is_triggered(g) && !onlyOneTop(g)) {
+ if (is_triggered(g) && !onlyOneTop(g)) {
DEBUG_PRINTF("Too many tops\n");
return false;
}
@@ -2493,7 +2493,7 @@ bool isPureRepeat(const NGHolder &g, PureRepeat &repeat) {
// have the same report set as the vertices in the repeat.
if (repeat.bounds.min == depth(1) &&
g[g.start].reports == g[v].reports) {
- repeat.bounds.min = depth(0);
+ repeat.bounds.min = depth(0);
DEBUG_PRINTF("graph is %s repeat\n", repeat.bounds.str().c_str());
} else {
DEBUG_PRINTF("not a supported repeat\n");
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_repeat.h b/contrib/libs/hyperscan/src/nfagraph/ng_repeat.h
index 7e04edf571c..cfd804b7eff 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_repeat.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_repeat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@
#include "ue2common.h"
#include "nfa/repeat_internal.h"
#include "util/depth.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <map>
#include <vector>
@@ -122,7 +122,7 @@ void findRepeats(const NGHolder &h, u32 minRepeatVertices,
struct PureRepeat {
CharReach reach;
DepthMinMax bounds;
- flat_set<ReportID> reports;
+ flat_set<ReportID> reports;
bool operator==(const PureRepeat &a) const {
return reach == a.reach && bounds == a.bounds && reports == a.reports;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_reports.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_reports.cpp
index bb88aa0d88d..4e9b498df06 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_reports.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_reports.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -65,26 +65,26 @@ bool can_exhaust(const NGHolder &g, const ReportManager &rm) {
return true;
}
-void set_report(NGHolder &g, ReportID internal_report) {
- // First, wipe the report IDs on all vertices.
- for (auto v : vertices_range(g)) {
- g[v].reports.clear();
- }
-
- // Any predecessors of accept get our id.
- for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
- g[v].reports.insert(internal_report);
- }
-
- // Same for preds of acceptEod, except accept itself.
- for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
- if (v == g.accept) {
- continue;
- }
- g[v].reports.insert(internal_report);
- }
-}
-
+void set_report(NGHolder &g, ReportID internal_report) {
+ // First, wipe the report IDs on all vertices.
+ for (auto v : vertices_range(g)) {
+ g[v].reports.clear();
+ }
+
+ // Any predecessors of accept get our id.
+ for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
+ g[v].reports.insert(internal_report);
+ }
+
+ // Same for preds of acceptEod, except accept itself.
+ for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
+ if (v == g.accept) {
+ continue;
+ }
+ g[v].reports.insert(internal_report);
+ }
+}
+
/** Derive a maximum offset for the graph from the max_offset values of its
* reports. Returns MAX_OFFSET for inf. */
u64a findMaxOffset(const NGHolder &g, const ReportManager &rm) {
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_reports.h b/contrib/libs/hyperscan/src/nfagraph/ng_reports.h
index 49570c11913..31c9530880b 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_reports.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_reports.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -48,10 +48,10 @@ std::set<ReportID> all_reports(const NGHolder &g);
/** True if *all* reports in the graph are exhaustible. */
bool can_exhaust(const NGHolder &g, const ReportManager &rm);
-/** Replaces all existing reports on the holder with the provided internal
- * report id. */
-void set_report(NGHolder &g, ReportID internal_report);
-
+/** Replaces all existing reports on the holder with the provided internal
+ * report id. */
+void set_report(NGHolder &g, ReportID internal_report);
+
/** Derive a maximum offset for the graph from the max_offset values of its
* reports. Returns MAX_OFFSET for inf. */
u64a findMaxOffset(const NGHolder &g, const ReportManager &rm);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.cpp
index 151814200bd..704697e57fc 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -49,71 +49,71 @@ namespace ue2 {
/** Connect the start vertex to each of the vertices in \p tops. This is useful
* temporarily for when we need to run a graph algorithm that expects a single
* source vertex. */
-static
-void wireStartToTops(NGHolder &g, const flat_set<NFAVertex> &tops,
- vector<NFAEdge> &tempEdges) {
- for (NFAVertex v : tops) {
+static
+void wireStartToTops(NGHolder &g, const flat_set<NFAVertex> &tops,
+ vector<NFAEdge> &tempEdges) {
+ for (NFAVertex v : tops) {
assert(!isLeafNode(v, g));
- const NFAEdge &e = add_edge(g.start, v, g);
- tempEdges.push_back(e);
+ const NFAEdge &e = add_edge(g.start, v, g);
+ tempEdges.push_back(e);
+ }
+}
+
+/**
+ * Returns true if start's successors (aside from startDs) are subset of
+ * startDs's proper successors or if start has no successors other than startDs.
+ */
+static
+bool startIsRedundant(const NGHolder &g) {
+ /* We ignore startDs as the self-loop may have been stripped as an
+ * optimisation for repeats (improveLeadingRepeats()). */
+ set<NFAVertex> start;
+ insert(&start, adjacent_vertices_range(g.start, g));
+ start.erase(g.startDs);
+
+ // Trivial case: start has no successors other than startDs.
+ if (start.empty()) {
+ DEBUG_PRINTF("start has no out-edges other than to startDs\n");
+ return true;
+ }
+
+ set<NFAVertex> startDs;
+ insert(&startDs, adjacent_vertices_range(g.startDs, g));
+ startDs.erase(g.startDs);
+
+ if (!is_subset_of(start, startDs)) {
+ DEBUG_PRINTF("out-edges of start and startDs aren't equivalent\n");
+ return false;
}
+
+ return true;
}
-/**
- * Returns true if start's successors (aside from startDs) are subset of
- * startDs's proper successors or if start has no successors other than startDs.
- */
static
-bool startIsRedundant(const NGHolder &g) {
- /* We ignore startDs as the self-loop may have been stripped as an
- * optimisation for repeats (improveLeadingRepeats()). */
- set<NFAVertex> start;
- insert(&start, adjacent_vertices_range(g.start, g));
- start.erase(g.startDs);
-
- // Trivial case: start has no successors other than startDs.
- if (start.empty()) {
- DEBUG_PRINTF("start has no out-edges other than to startDs\n");
- return true;
- }
-
- set<NFAVertex> startDs;
- insert(&startDs, adjacent_vertices_range(g.startDs, g));
- startDs.erase(g.startDs);
-
- if (!is_subset_of(start, startDs)) {
- DEBUG_PRINTF("out-edges of start and startDs aren't equivalent\n");
- return false;
- }
-
- return true;
-}
-
-static
-void getStateOrdering(NGHolder &g, const flat_set<NFAVertex> &tops,
+void getStateOrdering(NGHolder &g, const flat_set<NFAVertex> &tops,
vector<NFAVertex> &ordering) {
// First, wire up our "tops" to start so that we have a single source,
// which will give a nicer topo order.
- vector<NFAEdge> tempEdges;
- wireStartToTops(g, tops, tempEdges);
+ vector<NFAEdge> tempEdges;
+ wireStartToTops(g, tops, tempEdges);
- renumber_vertices(g);
+ renumber_vertices(g);
vector<NFAVertex> temp = getTopoOrdering(g);
- remove_edges(tempEdges, g);
+ remove_edges(tempEdges, g);
// Move {start, startDs} to the end, so they'll be first when we reverse
- // the ordering (if they are required).
+ // the ordering (if they are required).
temp.erase(remove(temp.begin(), temp.end(), g.startDs));
temp.erase(remove(temp.begin(), temp.end(), g.start));
- if (proper_out_degree(g.startDs, g)) {
- temp.push_back(g.startDs);
- }
- if (!startIsRedundant(g)) {
- temp.push_back(g.start);
- }
+ if (proper_out_degree(g.startDs, g)) {
+ temp.push_back(g.startDs);
+ }
+ if (!startIsRedundant(g)) {
+ temp.push_back(g.start);
+ }
// Walk ordering, remove vertices that shouldn't be participating in state
// numbering, such as accepts.
@@ -131,16 +131,16 @@ void getStateOrdering(NGHolder &g, const flat_set<NFAVertex> &tops,
// Returns the number of states.
static
-unordered_map<NFAVertex, u32>
+unordered_map<NFAVertex, u32>
getStateIndices(const NGHolder &h, const vector<NFAVertex> &ordering) {
- unordered_map<NFAVertex, u32> states;
+ unordered_map<NFAVertex, u32> states;
for (const auto &v : vertices_range(h)) {
states[v] = NO_STATE;
}
u32 stateNum = 0;
for (auto v : ordering) {
- DEBUG_PRINTF("assigning state num %u to vertex %zu\n", stateNum,
+ DEBUG_PRINTF("assigning state num %u to vertex %zu\n", stateNum,
h[v].index);
states[v] = stateNum++;
}
@@ -183,15 +183,15 @@ void optimiseTightLoops(const NGHolder &g, vector<NFAVertex> &ordering) {
continue;
}
- DEBUG_PRINTF("moving vertex %zu next to %zu\n", g[v].index, g[u].index);
+ DEBUG_PRINTF("moving vertex %zu next to %zu\n", g[v].index, g[u].index);
ordering.erase(v_it);
ordering.insert(++u_it, v);
}
}
-unordered_map<NFAVertex, u32>
-numberStates(NGHolder &h, const flat_set<NFAVertex> &tops) {
+unordered_map<NFAVertex, u32>
+numberStates(NGHolder &h, const flat_set<NFAVertex> &tops) {
DEBUG_PRINTF("numbering states for holder %p\n", &h);
vector<NFAVertex> ordering;
@@ -199,10 +199,10 @@ numberStates(NGHolder &h, const flat_set<NFAVertex> &tops) {
optimiseTightLoops(h, ordering);
- return getStateIndices(h, ordering);
+ return getStateIndices(h, ordering);
}
-u32 countStates(const unordered_map<NFAVertex, u32> &state_ids) {
+u32 countStates(const unordered_map<NFAVertex, u32> &state_ids) {
if (state_ids.empty()) {
return 0;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.h b/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.h
index 0ed4acb6e26..75d19c6294e 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_restructuring.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,16 +28,16 @@
/** \file
* \brief State numbering and late graph restructuring code.
- */
+ */
#ifndef NG_RESTRUCTURING_H
#define NG_RESTRUCTURING_H
#include "ng_holder.h"
#include "ue2common.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
-#include <unordered_map>
+#include <unordered_map>
namespace ue2 {
@@ -50,14 +50,14 @@ static constexpr u32 NO_STATE = ~0;
/**
* \brief Gives each participating vertex in the graph a unique state index.
*/
-std::unordered_map<NFAVertex, u32>
-numberStates(NGHolder &h, const flat_set<NFAVertex> &tops);
+std::unordered_map<NFAVertex, u32>
+numberStates(NGHolder &h, const flat_set<NFAVertex> &tops);
/**
* \brief Counts the number of states (vertices with state indices) in the
* graph.
*/
-u32 countStates(const std::unordered_map<NFAVertex, u32> &state_ids);
+u32 countStates(const std::unordered_map<NFAVertex, u32> &state_ids);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_revacc.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_revacc.cpp
index af85f01b9f8..0f932668c9f 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_revacc.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_revacc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,8 +40,8 @@
#include "util/charreach.h"
#include "util/graph_range.h"
-#include <set>
-
+#include <set>
+
using namespace std;
namespace ue2 {
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_small_literal_set.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_small_literal_set.cpp
index 1bca34eff66..9c2d9ba38d1 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_small_literal_set.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_small_literal_set.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,7 @@
#include "ng_small_literal_set.h"
#include "grey.h"
-#include "ng_holder.h"
+#include "ng_holder.h"
#include "ng_util.h"
#include "rose/rose_build.h"
#include "util/compare.h"
@@ -100,7 +100,7 @@ bool operator<(const sls_literal &a, const sls_literal &b) {
static
bool checkLongMixedSensitivityLiterals(
- const map<sls_literal, flat_set<ReportID>> &literals) {
+ const map<sls_literal, flat_set<ReportID>> &literals) {
const size_t len = MAX_MASK2_WIDTH;
for (const sls_literal &lit : literals | map_keys) {
@@ -114,7 +114,7 @@ bool checkLongMixedSensitivityLiterals(
static
bool findLiterals(const NGHolder &g,
- map<sls_literal, flat_set<ReportID>> *literals) {
+ map<sls_literal, flat_set<ReportID>> *literals) {
vector<NFAVertex> order = getTopoOrdering(g);
vector<set<sls_literal>> built(num_vertices(g));
@@ -125,7 +125,7 @@ bool findLiterals(const NGHolder &g,
set<sls_literal> &out = built[g[v].index];
read_count[g[v].index] = out_degree(v, g);
- DEBUG_PRINTF("setting read_count to %zu for %zu\n",
+ DEBUG_PRINTF("setting read_count to %zu for %zu\n",
read_count[g[v].index], g[v].index);
assert(out.empty());
@@ -154,7 +154,7 @@ bool findLiterals(const NGHolder &g,
}
set<sls_literal> &in = built[g[u].index];
- DEBUG_PRINTF("getting from %zu (%zu reads to go)\n",
+ DEBUG_PRINTF("getting from %zu (%zu reads to go)\n",
g[u].index, read_count[g[u].index]);
assert(!in.empty());
assert(read_count[g[u].index]);
@@ -188,7 +188,7 @@ bool findLiterals(const NGHolder &g,
read_count[g[u].index]--;
if (!read_count[g[u].index]) {
- DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index);
+ DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index);
in.clear();
}
}
@@ -198,7 +198,7 @@ bool findLiterals(const NGHolder &g,
}
static
-size_t min_period(const map<sls_literal, flat_set<ReportID>> &literals) {
+size_t min_period(const map<sls_literal, flat_set<ReportID>> &literals) {
size_t rv = SIZE_MAX;
for (const sls_literal &lit : literals | map_keys) {
@@ -222,14 +222,14 @@ bool handleSmallLiteralSets(RoseBuild &rose, const NGHolder &g,
return false;
}
- if (!hasNarrowReachVertex(g, MAX_LITERAL_SET_SIZE * 2 + 1)) {
- DEBUG_PRINTF("vertex with wide reach found\n");
- return false;
- }
-
+ if (!hasNarrowReachVertex(g, MAX_LITERAL_SET_SIZE * 2 + 1)) {
+ DEBUG_PRINTF("vertex with wide reach found\n");
+ return false;
+ }
+
DEBUG_PRINTF("looking for literals\n");
- map<sls_literal, flat_set<ReportID>> literals;
+ map<sls_literal, flat_set<ReportID>> literals;
if (!findLiterals(g, &literals)) {
DEBUG_PRINTF(":(\n");
return false;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_som.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_som.cpp
index 90942def3e9..d23ac408b04 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_som.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_som.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,13 +26,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief SOM ("Start of Match") analysis.
*/
-
-#include "ng_som.h"
-
+
+#include "ng_som.h"
+
#include "ng.h"
#include "ng_dump.h"
#include "ng_equivalence.h"
@@ -48,11 +48,11 @@
#include "ng_som_util.h"
#include "ng_split.h"
#include "ng_util.h"
-#include "ng_violet.h"
+#include "ng_violet.h"
#include "ng_width.h"
#include "grey.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "nfa/goughcompile.h"
#include "nfa/nfa_internal.h" // for MO_INVALID_IDX
#include "parser/position.h"
@@ -69,8 +69,8 @@
#include <algorithm>
#include <map>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
using namespace std;
@@ -105,7 +105,7 @@ struct som_plan {
static
bool regionCanEstablishSom(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const u32 region, const vector<NFAVertex> &r_exits,
const vector<DepthMinMax> &depths) {
if (region == regions.at(g.accept) ||
@@ -116,7 +116,7 @@ bool regionCanEstablishSom(const NGHolder &g,
DEBUG_PRINTF("region %u\n", region);
for (UNUSED auto v : r_exits) {
- DEBUG_PRINTF(" exit %zu\n", g[v].index);
+ DEBUG_PRINTF(" exit %zu\n", g[v].index);
}
/* simple if each region exit is at fixed distance from SOM. Note SOM does
@@ -125,12 +125,12 @@ bool regionCanEstablishSom(const NGHolder &g,
assert(regions.at(v) == region);
const DepthMinMax &d = depths.at(g[v].index);
if (d.min != d.max) {
- DEBUG_PRINTF("failing %zu as %s != %s\n", g[v].index,
+ DEBUG_PRINTF("failing %zu as %s != %s\n", g[v].index,
d.min.str().c_str(), d.max.str().c_str());
return false;
}
}
- DEBUG_PRINTF("region %u/%zu is good\n", regions.at(r_exits[0]),
+ DEBUG_PRINTF("region %u/%zu is good\n", regions.at(r_exits[0]),
g[r_exits[0]].index);
return true;
@@ -151,7 +151,7 @@ struct region_info {
static
void buildRegionMapping(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
map<u32, region_info> &info,
bool include_region_0 = false) {
for (auto v : vertices_range(g)) {
@@ -184,7 +184,7 @@ void buildRegionMapping(const NGHolder &g,
set<NFAEdge> be;
BackEdges<set<NFAEdge> > backEdgeVisitor(be);
- boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start));
+ boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start));
for (const auto &e : be) {
NFAVertex u = source(e, g);
@@ -211,17 +211,17 @@ void buildRegionMapping(const NGHolder &g,
r_i.optional ? " (optional)" : "");
DEBUG_PRINTF(" enters:");
for (u32 i = 0; i < r_i.enters.size(); i++) {
- printf(" %zu", g[r_i.enters[i]].index);
+ printf(" %zu", g[r_i.enters[i]].index);
}
printf("\n");
DEBUG_PRINTF(" exits:");
for (u32 i = 0; i < r_i.exits.size(); i++) {
- printf(" %zu", g[r_i.exits[i]].index);
+ printf(" %zu", g[r_i.exits[i]].index);
}
printf("\n");
DEBUG_PRINTF(" all:");
for (u32 i = 0; i < r_i.full.size(); i++) {
- printf(" %zu", g[r_i.full[i]].index);
+ printf(" %zu", g[r_i.full[i]].index);
}
printf("\n");
}
@@ -230,7 +230,7 @@ void buildRegionMapping(const NGHolder &g,
static
bool validateXSL(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const u32 region, const CharReach &escapes, u32 *bad_region) {
/* need to check that the escapes escape all of the graph past region */
u32 first_bad_region = ~0U;
@@ -238,7 +238,7 @@ bool validateXSL(const NGHolder &g,
u32 v_region = regions.at(v);
if (!is_special(v, g) && v_region > region &&
(escapes & g[v].char_reach).any()) {
- DEBUG_PRINTF("problem with escapes for %zu\n", g[v].index);
+ DEBUG_PRINTF("problem with escapes for %zu\n", g[v].index);
first_bad_region = MIN(first_bad_region, v_region);
}
}
@@ -253,7 +253,7 @@ bool validateXSL(const NGHolder &g,
static
bool validateEXSL(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const u32 region, const CharReach &escapes,
const NGHolder &prefix, u32 *bad_region) {
/* EXSL: To be a valid EXSL with escapes e, we require that all states
@@ -267,7 +267,7 @@ bool validateEXSL(const NGHolder &g,
const vector<CharReach> escapes_vec(1, escapes);
const vector<CharReach> notescapes_vec(1, ~escapes);
- flat_set<NFAVertex> states;
+ flat_set<NFAVertex> states;
/* turn on all states past the prefix */
DEBUG_PRINTF("region %u is cutover\n", region);
for (auto v : vertices_range(g)) {
@@ -280,7 +280,7 @@ bool validateEXSL(const NGHolder &g,
states = execute_graph(g, escapes_vec, states);
/* flood with any number of not escapes */
- flat_set<NFAVertex> prev_states;
+ flat_set<NFAVertex> prev_states;
while (prev_states != states) {
prev_states = states;
states = execute_graph(g, notescapes_vec, states);
@@ -290,7 +290,7 @@ bool validateEXSL(const NGHolder &g,
/* find input starts to use for when we are running the prefix through as
* when the escape character arrives we may be in matching the prefix
* already */
- flat_set<NFAVertex> prefix_start_states;
+ flat_set<NFAVertex> prefix_start_states;
for (auto v : vertices_range(prefix)) {
if (v != prefix.accept && v != prefix.acceptEod
/* and as we have already made it past the prefix once */
@@ -355,7 +355,7 @@ bool isPossibleLock(const NGHolder &g,
static
unique_ptr<NGHolder>
-makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
+makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
const region_info &curr, const region_info &next,
bool renumber = true) {
const vector<NFAVertex> &curr_exits = curr.exits;
@@ -370,12 +370,12 @@ makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
deque<NFAVertex> lhs_verts;
insert(&lhs_verts, lhs_verts.end(), vertices(g));
- unordered_map<NFAVertex, NFAVertex> lhs_map; // g -> prefix
+ unordered_map<NFAVertex, NFAVertex> lhs_map; // g -> prefix
fillHolder(&prefix, g, lhs_verts, &lhs_map);
prefix.kind = NFA_OUTFIX;
// We need a reverse mapping to track regions.
- unordered_map<NFAVertex, NFAVertex> rev_map; // prefix -> g
+ unordered_map<NFAVertex, NFAVertex> rev_map; // prefix -> g
for (const auto &e : lhs_map) {
rev_map.emplace(e.second, e.first);
}
@@ -385,7 +385,7 @@ makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
add_edge(prefix.accept, prefix.acceptEod, prefix);
assert(!next_enters.empty());
- assert(next_enters.front() != NGHolder::null_vertex());
+ assert(next_enters.front() != NGHolder::null_vertex());
u32 dead_region = regions.at(next_enters.front());
DEBUG_PRINTF("curr_region %u, dead_region %u\n",
regions.at(curr_exits.front()), dead_region);
@@ -404,7 +404,7 @@ makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
vector<NFAVertex> to_clear;
assert(contains(lhs_map, curr_exits.front()));
NFAVertex p_u = lhs_map[curr_exits.front()];
- DEBUG_PRINTF("p_u: %zu\n", prefix[p_u].index);
+ DEBUG_PRINTF("p_u: %zu\n", prefix[p_u].index);
for (auto p_v : adjacent_vertices_range(p_u, prefix)) {
auto v = rev_map.at(p_v);
if (p_v == prefix.accept || regions.at(v) < dead_region) {
@@ -414,7 +414,7 @@ makePrefix(const NGHolder &g, const unordered_map<NFAVertex, u32> &regions,
}
for (auto v : to_clear) {
- DEBUG_PRINTF("clearing in_edges on %zu\n", prefix[v].index);
+ DEBUG_PRINTF("clearing in_edges on %zu\n", prefix[v].index);
clear_in_edges(v, prefix);
}
@@ -446,9 +446,9 @@ void replaceTempSomSlot(ReportManager &rm, NGHolder &g, u32 real_slot) {
}
static
-void setPrefixReports(ReportManager &rm, NGHolder &g, ReportType ir_type,
- u32 som_loc, const vector<DepthMinMax> &depths,
- bool prefix_by_rev) {
+void setPrefixReports(ReportManager &rm, NGHolder &g, ReportType ir_type,
+ u32 som_loc, const vector<DepthMinMax> &depths,
+ bool prefix_by_rev) {
Report ir = makeCallback(0U, 0);
ir.type = ir_type;
ir.onmatch = som_loc;
@@ -472,7 +472,7 @@ void setPrefixReports(ReportManager &rm, NGHolder &g, ReportType ir_type,
}
static
-void updatePrefixReports(ReportManager &rm, NGHolder &g, ReportType ir_type) {
+void updatePrefixReports(ReportManager &rm, NGHolder &g, ReportType ir_type) {
/* update the som action on the prefix report */
for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
auto &reports = g[v].reports;
@@ -543,7 +543,7 @@ void setMidfixReports(ReportManager &rm, const som_plan &item,
static
bool finalRegion(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
NFAVertex v) {
u32 region = regions.at(v);
for (auto w : adjacent_vertices_range(v, g)) {
@@ -557,8 +557,8 @@ bool finalRegion(const NGHolder &g,
static
void replaceExternalReportsWithSomRep(ReportManager &rm, NGHolder &g,
- NFAVertex v, ReportType ir_type,
- u64a param) {
+ NFAVertex v, ReportType ir_type,
+ u64a param) {
assert(!g[v].reports.empty());
flat_set<ReportID> r_new;
@@ -577,7 +577,7 @@ void replaceExternalReportsWithSomRep(ReportManager &rm, NGHolder &g,
ir.somDistance = param;
ReportID rep = rm.getInternalId(ir);
- DEBUG_PRINTF("vertex %zu, replacing report %u with %u (type %u)\n",
+ DEBUG_PRINTF("vertex %zu, replacing report %u with %u (type %u)\n",
g[v].index, report_id, rep, ir_type);
r_new.insert(rep);
}
@@ -691,7 +691,7 @@ void fillHolderForLockCheck(NGHolder *out, const NGHolder &g,
map<u32, region_info>::const_iterator picked) {
/* NOTE: This is appropriate for firstMatchIsFirst */
DEBUG_PRINTF("prepping for lock check\n");
-
+
NGHolder &midfix = *out;
map<NFAVertex, NFAVertex> v_map;
@@ -699,18 +699,18 @@ void fillHolderForLockCheck(NGHolder *out, const NGHolder &g,
v_map[g.startDs] = midfix.startDs;
/* include the lock region */
- assert(picked != info.end());
- auto graph_last = next(picked);
+ assert(picked != info.end());
+ auto graph_last = next(picked);
+
+ assert(!graph_last->second.dag);
+ assert(graph_last->second.full.size() == 1);
- assert(!graph_last->second.dag);
- assert(graph_last->second.full.size() == 1);
-
- for (auto jt = graph_last; ; --jt) {
+ for (auto jt = graph_last; ; --jt) {
DEBUG_PRINTF("adding r %u to midfix\n", jt->first);
/* add all vertices in region, create mapping */
for (auto v : jt->second.full) {
- DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
+ DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
if (contains(v_map, v)) {
continue;
}
@@ -742,38 +742,38 @@ void fillHolderForLockCheck(NGHolder *out, const NGHolder &g,
}
}
- if (jt == info.begin()) {
- break;
- }
- }
-
- /* add edges from startds to the enters of all the initial optional
- * regions and the first mandatory region. */
- for (auto jt = info.begin(); ; ++jt) {
+ if (jt == info.begin()) {
+ break;
+ }
+ }
+
+ /* add edges from startds to the enters of all the initial optional
+ * regions and the first mandatory region. */
+ for (auto jt = info.begin(); ; ++jt) {
for (auto enter : jt->second.enters) {
assert(contains(v_map, enter));
NFAVertex v = v_map[enter];
add_edge_if_not_present(midfix.startDs, v, midfix);
}
- if (!jt->second.optional) {
+ if (!jt->second.optional) {
+ break;
+ }
+
+ if (jt == graph_last) {
+ /* all regions are optional - add a direct edge to accept */
+ add_edge_if_not_present(midfix.startDs, midfix.accept, midfix);
break;
}
-
- if (jt == graph_last) {
- /* all regions are optional - add a direct edge to accept */
- add_edge_if_not_present(midfix.startDs, midfix.accept, midfix);
- break;
- }
}
assert(in_degree(midfix.accept, midfix));
- renumber_vertices(midfix);
+ renumber_vertices(midfix);
}
static
void fillRoughMidfix(NGHolder *out, const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
map<u32, region_info>::const_iterator picked) {
/* as we are not the first prefix, we are probably not acyclic. We need to
@@ -795,7 +795,7 @@ void fillRoughMidfix(NGHolder *out, const NGHolder &g,
/* add all vertices in region, create mapping */
for (auto v : jt->second.full) {
- DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
+ DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
NFAVertex vnew = add_vertex(g[v], midfix);
v_map[v] = vnew;
}
@@ -835,7 +835,7 @@ void fillRoughMidfix(NGHolder *out, const NGHolder &g,
do {
for (auto v : jt->second.exits) {
- DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
+ DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index);
NFAVertex vnew = add_vertex(g[v], midfix);
v_map[v] = vnew;
@@ -943,7 +943,7 @@ bool isMandRegionBetween(map<u32, region_info>::const_iterator a,
// (woot!); updates picked, plan and bad_region.
static
bool advancePlan(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const NGHolder &prefix, bool stuck,
map<u32, region_info>::const_iterator &picked,
const map<u32, region_info>::const_iterator furthest,
@@ -1022,7 +1022,7 @@ bool addPlan(vector<som_plan> &plan, u32 parent) {
// Fetches all preds of {accept, acceptEod} for this graph.
static
void addReporterVertices(const NGHolder &g, vector<NFAVertex> &reporters) {
- set<NFAVertex> tmp;
+ set<NFAVertex> tmp;
insert(&tmp, inv_adjacent_vertices(g.accept, g));
insert(&tmp, inv_adjacent_vertices(g.acceptEod, g));
tmp.erase(g.accept);
@@ -1030,7 +1030,7 @@ void addReporterVertices(const NGHolder &g, vector<NFAVertex> &reporters) {
#ifdef DEBUG
DEBUG_PRINTF("add reporters:");
for (UNUSED auto v : tmp) {
- printf(" %zu", g[v].index);
+ printf(" %zu", g[v].index);
}
printf("\n");
#endif
@@ -1044,7 +1044,7 @@ void addReporterVertices(const region_info &r, const NGHolder &g,
vector<NFAVertex> &reporters) {
for (auto v : r.exits) {
if (edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second) {
- DEBUG_PRINTF("add reporter %zu\n", g[v].index);
+ DEBUG_PRINTF("add reporter %zu\n", g[v].index);
reporters.push_back(v);
}
}
@@ -1053,12 +1053,12 @@ void addReporterVertices(const region_info &r, const NGHolder &g,
// Fetches the mappings of all preds of {accept, acceptEod} in this region.
static
void addMappedReporterVertices(const region_info &r, const NGHolder &g,
- const unordered_map<NFAVertex, NFAVertex> &mapping,
+ const unordered_map<NFAVertex, NFAVertex> &mapping,
vector<NFAVertex> &reporters) {
for (auto v : r.exits) {
if (edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second) {
- DEBUG_PRINTF("adding v=%zu\n", g[v].index);
- auto it = mapping.find(v);
+ DEBUG_PRINTF("adding v=%zu\n", g[v].index);
+ auto it = mapping.find(v);
assert(it != mapping.end());
reporters.push_back(it->second);
}
@@ -1069,9 +1069,9 @@ void addMappedReporterVertices(const region_info &r, const NGHolder &g,
// from earlier regions.
static
void cloneGraphWithOneEntry(NGHolder &out, const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
NFAVertex entry, const vector<NFAVertex> &enters,
- unordered_map<NFAVertex, NFAVertex> &orig_to_copy) {
+ unordered_map<NFAVertex, NFAVertex> &orig_to_copy) {
orig_to_copy.clear();
cloneHolder(out, g, &orig_to_copy);
@@ -1096,7 +1096,7 @@ void cloneGraphWithOneEntry(NGHolder &out, const NGHolder &g,
}
static
-void expandGraph(NGHolder &g, unordered_map<NFAVertex, u32> &regions,
+void expandGraph(NGHolder &g, unordered_map<NFAVertex, u32> &regions,
vector<NFAVertex> &enters) {
assert(!enters.empty());
const u32 split_region = regions.at(enters.front());
@@ -1113,7 +1113,7 @@ void expandGraph(NGHolder &g, unordered_map<NFAVertex, u32> &regions,
}
for (auto enter : enters) {
- DEBUG_PRINTF("processing enter %zu\n", g[enter].index);
+ DEBUG_PRINTF("processing enter %zu\n", g[enter].index);
map<NFAVertex, NFAVertex> orig_to_copy;
// Make a copy of all of the tail vertices, storing region info along
@@ -1163,7 +1163,7 @@ void expandGraph(NGHolder &g, unordered_map<NFAVertex, u32> &regions,
[&](const NFAEdge &e) {
NFAVertex u = source(e, g);
return regions.at(u) < split_region;
- }, g);
+ }, g);
}
new_enters.push_back(orig_to_copy[enter]);
@@ -1179,11 +1179,11 @@ void expandGraph(NGHolder &g, unordered_map<NFAVertex, u32> &regions,
static
bool doTreePlanningIntl(NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
map<u32, region_info>::const_iterator picked, u32 bad_region,
u32 parent_plan,
- const unordered_map<NFAVertex, NFAVertex> &copy_to_orig,
+ const unordered_map<NFAVertex, NFAVertex> &copy_to_orig,
vector<som_plan> &plan, const Grey &grey) {
assert(picked != info.end());
@@ -1335,14 +1335,14 @@ bool doTreePlanning(NGHolder &g,
dumpHolder(g, g_regions, 14, "som_expandedtree", grey);
for (auto v : enters) {
- DEBUG_PRINTF("enter %zu\n", g[v].index);
+ DEBUG_PRINTF("enter %zu\n", g[v].index);
// For this entry vertex, construct a version of the graph without the
// other entries in this region (g_path), and calculate its depths and
// regions.
NGHolder g_path;
- unordered_map<NFAVertex, NFAVertex> orig_to_copy;
+ unordered_map<NFAVertex, NFAVertex> orig_to_copy;
cloneGraphWithOneEntry(g_path, g, g_regions, v, enters, orig_to_copy);
auto regions = assignRegions(g_path);
dumpHolder(g_path, regions, 14, "som_treepath", grey);
@@ -1376,7 +1376,7 @@ bool doTreePlanning(NGHolder &g,
}
// Construct reverse mapping from vertices in g_path to g.
- unordered_map<NFAVertex, NFAVertex> copy_to_orig;
+ unordered_map<NFAVertex, NFAVertex> copy_to_orig;
for (const auto &m : orig_to_copy) {
copy_to_orig.insert(make_pair(m.second, m.first));
}
@@ -1399,7 +1399,7 @@ enum dsp_behaviour {
static
bool doSomPlanning(NGHolder &g, bool stuck_in,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
map<u32, region_info>::const_iterator picked,
vector<som_plan> &plan,
@@ -1570,12 +1570,12 @@ void dumpSomPlan(UNUSED const NGHolder &g, UNUSED const som_plan &p,
p.is_reset, p.parent);
printf(" reporters:");
for (auto v : p.reporters) {
- printf(" %zu", g[v].index);
+ printf(" %zu", g[v].index);
}
printf("\n");
printf(" reporters_in:");
for (auto v : p.reporters_in) {
- printf(" %zu", g[v].index);
+ printf(" %zu", g[v].index);
}
printf("\n");
#endif
@@ -1589,9 +1589,9 @@ void dumpSomPlan(UNUSED const NGHolder &g, UNUSED const som_plan &p,
* implement the full pattern.
*/
static
-void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
- NGHolder &g, vector<som_plan> &plan,
- const u32 first_som_slot) {
+void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
+ NGHolder &g, vector<som_plan> &plan,
+ const u32 first_som_slot) {
ReportManager &rm = ng.rm;
SomSlotManager &ssm = ng.ssm;
@@ -1604,14 +1604,14 @@ void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
// Root plan, which already has a SOM slot assigned (first_som_slot).
dumpSomPlan(g, plan.front(), 0);
- dumpSomSubComponent(*plan.front().prefix, "04_som", expr.index, comp_id, 0,
- ng.cc.grey);
+ dumpSomSubComponent(*plan.front().prefix, "04_som", expr.index, comp_id, 0,
+ ng.cc.grey);
assert(plan.front().prefix);
if (plan.front().escapes.any() && !plan.front().is_reset) {
/* setup escaper for first som location */
if (!createEscaper(ng, *plan.front().prefix, plan.front().escapes,
first_som_slot)) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
}
@@ -1623,7 +1623,7 @@ void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
for (++it; it != plan.end(); ++it) {
const u32 plan_num = it - plan.begin();
dumpSomPlan(g, *it, plan_num);
- dumpSomSubComponent(*it->prefix, "04_som", expr.index, comp_id,
+ dumpSomSubComponent(*it->prefix, "04_som", expr.index, comp_id,
plan_num, ng.cc.grey);
assert(it->parent < plan_num);
@@ -1634,7 +1634,7 @@ void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
assert(!it->no_implement);
if (!buildMidfix(ng, *it, som_slot_in, som_slot_out)) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
updateReportToUseRecordedSom(rm, g, it->reporters_in, som_slot_in);
updateReportToUseRecordedSom(rm, g, it->reporters, som_slot_out);
@@ -1642,10 +1642,10 @@ void implementSomPlan(NG &ng, const ExpressionInfo &expr, u32 comp_id,
/* create prefix to set the som_loc */
if (!plan.front().no_implement) {
- renumber_vertices(*plan.front().prefix);
+ renumber_vertices(*plan.front().prefix);
assert(plan.front().prefix->kind == NFA_OUTFIX);
if (!ng.addHolder(*plan.front().prefix)) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
}
}
@@ -1733,17 +1733,17 @@ void clearProperInEdges(NGHolder &g, const NFAVertex sink) {
namespace {
struct SomRevNfa {
- SomRevNfa(NFAVertex s, ReportID r, bytecode_ptr<NFA> n)
+ SomRevNfa(NFAVertex s, ReportID r, bytecode_ptr<NFA> n)
: sink(s), report(r), nfa(move(n)) {}
NFAVertex sink;
ReportID report;
- bytecode_ptr<NFA> nfa;
+ bytecode_ptr<NFA> nfa;
};
}
static
-bytecode_ptr<NFA> makeBareSomRevNfa(const NGHolder &g,
- const CompileContext &cc) {
+bytecode_ptr<NFA> makeBareSomRevNfa(const NGHolder &g,
+ const CompileContext &cc) {
// Create a reversed anchored version of this NFA which fires a zero report
// ID on accept.
NGHolder g_rev;
@@ -1752,14 +1752,14 @@ bytecode_ptr<NFA> makeBareSomRevNfa(const NGHolder &g,
setZeroReports(g_rev);
// Prep for actual construction.
- renumber_vertices(g_rev);
+ renumber_vertices(g_rev);
g_rev.kind = NFA_REV_PREFIX;
reduceGraphEquivalences(g_rev, cc);
removeRedundancy(g_rev, SOM_NONE);
DEBUG_PRINTF("building a rev NFA with %zu vertices\n", num_vertices(g_rev));
- auto nfa = constructReversedNFA(g_rev, cc);
+ auto nfa = constructReversedNFA(g_rev, cc);
if (!nfa) {
return nfa;
}
@@ -1792,9 +1792,9 @@ bool makeSomRevNfa(vector<SomRevNfa> &som_nfas, const NGHolder &g,
return true;
}
- renumber_vertices(g2); // for findMinWidth, findMaxWidth.
+ renumber_vertices(g2); // for findMinWidth, findMaxWidth.
- auto nfa = makeBareSomRevNfa(g2, cc);
+ auto nfa = makeBareSomRevNfa(g2, cc);
if (!nfa) {
DEBUG_PRINTF("couldn't build rev nfa\n");
return false;
@@ -1856,7 +1856,7 @@ bool doSomRevNfa(NG &ng, NGHolder &g, const CompileContext &cc) {
}
static
-u32 doSomRevNfaPrefix(NG &ng, const ExpressionInfo &expr, NGHolder &g,
+u32 doSomRevNfaPrefix(NG &ng, const ExpressionInfo &expr, NGHolder &g,
const CompileContext &cc) {
depth maxWidth = findMaxWidth(g);
@@ -1865,7 +1865,7 @@ u32 doSomRevNfaPrefix(NG &ng, const ExpressionInfo &expr, NGHolder &g,
auto nfa = makeBareSomRevNfa(g, cc);
if (!nfa) {
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
if (ng.cc.streaming) {
@@ -1939,7 +1939,7 @@ map<u32, region_info>::const_iterator findLaterLiteral(const NGHolder &g,
static
bool attemptToBuildChainAfterSombe(SomSlotManager &ssm, NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
map<u32, region_info>::const_iterator picked,
const Grey &grey,
@@ -2013,7 +2013,7 @@ void setReportOnHaigPrefix(RoseBuild &rose, NGHolder &h) {
static
bool tryHaig(RoseBuild &rose, NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
som_type som, u32 somPrecision,
map<u32, region_info>::const_iterator picked,
shared_ptr<raw_som_dfa> *haig, shared_ptr<NGHolder> *haig_prefix,
@@ -2059,9 +2059,9 @@ void roseAddHaigLiteral(RoseBuild &tb, const shared_ptr<NGHolder> &prefix,
}
static
-sombe_rv doHaigLitSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
- u32 comp_id, som_type som,
- const unordered_map<NFAVertex, u32> &regions,
+sombe_rv doHaigLitSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
+ u32 comp_id, som_type som,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
map<u32, region_info>::const_iterator lower_bound) {
DEBUG_PRINTF("entry\n");
@@ -2070,18 +2070,18 @@ sombe_rv doHaigLitSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
ReportManager &rm = ng.rm;
SomSlotManager &ssm = ng.ssm;
- if (!cc.grey.allowHaigLit) {
+ if (!cc.grey.allowHaigLit) {
return SOMBE_FAIL;
}
const u32 numSomLocsBefore = ssm.numSomSlots(); /* for rollback */
u32 som_loc = ssm.getPrivateSomSlot();
- if (!checkViolet(rm, g, false, cc) && !isImplementableNFA(g, &rm, cc)) {
+ if (!checkViolet(rm, g, false, cc) && !isImplementableNFA(g, &rm, cc)) {
// This is an optimisation: if we can't build a Haig from a portion of
// the graph, then we won't be able to manage it as an outfix either
// when we fall back.
- throw CompileError(expr.index, "Pattern is too large.");
+ throw CompileError(expr.index, "Pattern is too large.");
}
while (1) {
@@ -2156,7 +2156,7 @@ sombe_rv doHaigLitSom(NG &ng, NGHolder &g, const ExpressionInfo &expr,
goto next_try;
}
- implementSomPlan(ng, expr, comp_id, g, plan, som_loc);
+ implementSomPlan(ng, expr, comp_id, g, plan, som_loc);
Report ir = makeCallback(0U, 0);
assert(!plan.empty());
@@ -2227,7 +2227,7 @@ bool leadingLiterals(const NGHolder &g, set<ue2_literal> *lits,
for (const auto &m : curr) {
const NFAVertex u = m.first;
const vector<ue2_literal> &base = m.second;
- DEBUG_PRINTF("expanding from %zu\n", g[u].index);
+ DEBUG_PRINTF("expanding from %zu\n", g[u].index);
for (auto v : adjacent_vertices_range(u, g)) {
if (v == g.startDs) {
continue;
@@ -2240,7 +2240,7 @@ bool leadingLiterals(const NGHolder &g, set<ue2_literal> *lits,
DEBUG_PRINTF("match\n");
goto skip_to_next_terminal;
}
- if (g[v].char_reach.count() > 2 * MAX_LEADING_LITERALS) {
+ if (g[v].char_reach.count() > 2 * MAX_LEADING_LITERALS) {
DEBUG_PRINTF("wide\n");
goto skip_to_next_terminal;
}
@@ -2256,8 +2256,8 @@ bool leadingLiterals(const NGHolder &g, set<ue2_literal> *lits,
CharReach cr = g[v].char_reach;
vector<ue2_literal> &out = next[v];
- DEBUG_PRINTF("expanding to %zu (|| = %zu)\n", g[v].index,
- cr.count());
+ DEBUG_PRINTF("expanding to %zu (|| = %zu)\n", g[v].index,
+ cr.count());
for (size_t c = cr.find_first(); c != CharReach::npos;
c = cr.find_next(c)) {
bool nocase = ourisalpha(c) && cr.test(mytoupper(c))
@@ -2333,7 +2333,7 @@ bool splitOffLeadingLiterals(const NGHolder &g, set<ue2_literal> *lit_out,
set<NFAVertex> adj_term1;
insert(&adj_term1, adjacent_vertices(*terms.begin(), g));
for (auto v : terms) {
- DEBUG_PRINTF("term %zu\n", g[v].index);
+ DEBUG_PRINTF("term %zu\n", g[v].index);
set<NFAVertex> temp;
insert(&temp, adjacent_vertices(v, g));
if (temp != adj_term1) {
@@ -2342,7 +2342,7 @@ bool splitOffLeadingLiterals(const NGHolder &g, set<ue2_literal> *lit_out,
}
}
- unordered_map<NFAVertex, NFAVertex> rhs_map;
+ unordered_map<NFAVertex, NFAVertex> rhs_map;
vector<NFAVertex> pivots;
insert(&pivots, pivots.end(), adj_term1);
splitRHS(g, pivots, rhs, &rhs_map);
@@ -2353,14 +2353,14 @@ bool splitOffLeadingLiterals(const NGHolder &g, set<ue2_literal> *lit_out,
static
void findBestLiteral(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
ue2_literal *lit_out, NFAVertex *v,
const CompileContext &cc) {
map<u32, region_info> info;
buildRegionMapping(g, regions, info, false);
ue2_literal best;
- NFAVertex best_v = NGHolder::null_vertex();
+ NFAVertex best_v = NGHolder::null_vertex();
map<u32, region_info>::const_iterator lit = info.begin();
while (1) {
@@ -2393,10 +2393,10 @@ void findBestLiteral(const NGHolder &g,
static
bool splitOffBestLiteral(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
ue2_literal *lit_out, NGHolder *lhs, NGHolder *rhs,
const CompileContext &cc) {
- NFAVertex v = NGHolder::null_vertex();
+ NFAVertex v = NGHolder::null_vertex();
findBestLiteral(g, regions, lit_out, &v, cc);
if (lit_out->empty()) {
@@ -2405,43 +2405,43 @@ bool splitOffBestLiteral(const NGHolder &g,
DEBUG_PRINTF("literal is '%s'\n", dumpString(*lit_out).c_str());
- unordered_map<NFAVertex, NFAVertex> lhs_map;
- unordered_map<NFAVertex, NFAVertex> rhs_map;
+ unordered_map<NFAVertex, NFAVertex> lhs_map;
+ unordered_map<NFAVertex, NFAVertex> rhs_map;
splitGraph(g, v, lhs, &lhs_map, rhs, &rhs_map);
- DEBUG_PRINTF("v = %zu\n", g[v].index);
+ DEBUG_PRINTF("v = %zu\n", g[v].index);
return true;
}
-/**
- * Replace the given graph's EXTERNAL_CALLBACK reports with
- * EXTERNAL_CALLBACK_SOM_PASS reports.
- */
-void makeReportsSomPass(ReportManager &rm, NGHolder &g) {
- for (const auto &v : vertices_range(g)) {
- const auto &reports = g[v].reports;
- if (reports.empty()) {
- continue;
- }
-
- flat_set<ReportID> new_reports;
- for (const ReportID &id : reports) {
- const Report &report = rm.getReport(id);
- if (report.type != EXTERNAL_CALLBACK) {
- new_reports.insert(id);
- continue;
- }
- Report report2 = report;
- report2.type = EXTERNAL_CALLBACK_SOM_PASS;
- new_reports.insert(rm.getInternalId(report2));
- }
-
- g[v].reports = new_reports;
- }
-}
-
+/**
+ * Replace the given graph's EXTERNAL_CALLBACK reports with
+ * EXTERNAL_CALLBACK_SOM_PASS reports.
+ */
+void makeReportsSomPass(ReportManager &rm, NGHolder &g) {
+ for (const auto &v : vertices_range(g)) {
+ const auto &reports = g[v].reports;
+ if (reports.empty()) {
+ continue;
+ }
+
+ flat_set<ReportID> new_reports;
+ for (const ReportID &id : reports) {
+ const Report &report = rm.getReport(id);
+ if (report.type != EXTERNAL_CALLBACK) {
+ new_reports.insert(id);
+ continue;
+ }
+ Report report2 = report;
+ report2.type = EXTERNAL_CALLBACK_SOM_PASS;
+ new_reports.insert(rm.getInternalId(report2));
+ }
+
+ g[v].reports = new_reports;
+ }
+}
+
static
bool doLitHaigSom(NG &ng, NGHolder &g, som_type som) {
ue2_literal lit;
@@ -2464,8 +2464,8 @@ bool doLitHaigSom(NG &ng, NGHolder &g, som_type som) {
assert(lit.length() <= MAX_MASK2_WIDTH || !mixed_sensitivity(lit));
- makeReportsSomPass(ng.rm, *rhs);
-
+ makeReportsSomPass(ng.rm, *rhs);
+
dumpHolder(*rhs, 91, "lithaig_rhs", ng.cc.grey);
vector<vector<CharReach> > triggers;
@@ -2497,7 +2497,7 @@ bool doLitHaigSom(NG &ng, NGHolder &g, som_type som) {
static
bool doHaigLitHaigSom(NG &ng, NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
som_type som) {
if (!ng.cc.grey.allowLitHaig) {
return false;
@@ -2528,8 +2528,8 @@ bool doHaigLitHaigSom(NG &ng, NGHolder &g,
return false; /* TODO: handle */
}
- makeReportsSomPass(ng.rm, *rhs);
-
+ makeReportsSomPass(ng.rm, *rhs);
+
dumpHolder(*lhs, 92, "haiglithaig_lhs", ng.cc.grey);
dumpHolder(*rhs, 93, "haiglithaig_rhs", ng.cc.grey);
@@ -2541,7 +2541,7 @@ bool doHaigLitHaigSom(NG &ng, NGHolder &g,
RoseInVertex v = add_vertex(RoseInVertexProps::makeLiteral(lit), ig);
bool lhs_all_vac = true;
- NGHolder::adjacency_iterator ai, ae;
+ NGHolder::adjacency_iterator ai, ae;
for (tie(ai, ae) = adjacent_vertices(lhs->startDs, *lhs);
ai != ae && lhs_all_vac; ++ai) {
if (!is_special(*ai, *lhs)) {
@@ -2630,7 +2630,7 @@ bool doHaigLitHaigSom(NG &ng, NGHolder &g,
}
} else {
DEBUG_PRINTF("has start->accept edge\n");
- if (in_degree(g.acceptEod, g) > 1) {
+ if (in_degree(g.acceptEod, g) > 1) {
DEBUG_PRINTF("also has a path to EOD\n");
return false;
}
@@ -2665,8 +2665,8 @@ bool doMultiLitHaigSom(NG &ng, NGHolder &g, som_type som) {
return false;
}
- makeReportsSomPass(ng.rm, *rhs);
-
+ makeReportsSomPass(ng.rm, *rhs);
+
dumpHolder(*rhs, 91, "lithaig_rhs", ng.cc.grey);
vector<vector<CharReach>> triggers;
@@ -2731,7 +2731,7 @@ bool trySombe(NG &ng, NGHolder &g, som_type som) {
static
map<u32, region_info>::const_iterator pickInitialSomCut(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
const vector<DepthMinMax> &depths) {
map<u32, region_info>::const_iterator picked = info.end();
@@ -2756,7 +2756,7 @@ map<u32, region_info>::const_iterator pickInitialSomCut(const NGHolder &g,
static
map<u32, region_info>::const_iterator tryForLaterRevNfaCut(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
const vector<DepthMinMax> &depths,
const map<u32, region_info>::const_iterator &orig,
@@ -2831,7 +2831,7 @@ map<u32, region_info>::const_iterator tryForLaterRevNfaCut(const NGHolder &g,
reverseHolder(*prefix, g_rev);
anchorStarts(g_rev);
- renumber_vertices(g_rev);
+ renumber_vertices(g_rev);
g_rev.kind = NFA_REV_PREFIX;
reduceGraphEquivalences(g_rev, cc);
removeRedundancy(g_rev, SOM_NONE);
@@ -2848,7 +2848,7 @@ map<u32, region_info>::const_iterator tryForLaterRevNfaCut(const NGHolder &g,
static
unique_ptr<NGHolder> makePrefixForChain(NGHolder &g,
- const unordered_map<NFAVertex, u32> &regions,
+ const unordered_map<NFAVertex, u32> &regions,
const map<u32, region_info> &info,
const map<u32, region_info>::const_iterator &picked,
vector<DepthMinMax> *depths, bool prefix_by_rev,
@@ -2875,13 +2875,13 @@ unique_ptr<NGHolder> makePrefixForChain(NGHolder &g,
}
depths->clear(); /* renumbering invalidates depths */
- renumber_vertices(*prefix);
+ renumber_vertices(*prefix);
DEBUG_PRINTF("done\n");
return prefix;
}
-sombe_rv doSom(NG &ng, NGHolder &g, const ExpressionInfo &expr, u32 comp_id,
+sombe_rv doSom(NG &ng, NGHolder &g, const ExpressionInfo &expr, u32 comp_id,
som_type som) {
assert(som);
DEBUG_PRINTF("som hello\n");
@@ -2891,7 +2891,7 @@ sombe_rv doSom(NG &ng, NGHolder &g, const ExpressionInfo &expr, u32 comp_id,
// Special case: if g is completely anchored or begins with a dot-star, we
// know that we have an absolute SOM of zero all the time.
- if (!proper_out_degree(g.startDs, g) || beginsWithDotStar(g)) {
+ if (!proper_out_degree(g.startDs, g) || beginsWithDotStar(g)) {
makeSomAbsReports(rm, g, g.accept);
makeSomAbsReports(rm, g, g.acceptEod);
return SOMBE_HANDLED_INTERNAL;
@@ -3005,10 +3005,10 @@ sombe_rv doSom(NG &ng, NGHolder &g, const ExpressionInfo &expr, u32 comp_id,
/* create prefix to set the som_loc */
updatePrefixReports(rm, *prefix, INTERNAL_SOM_LOC_SET_IF_UNSET);
if (prefix_by_rev) {
- u32 rev_comp_id = doSomRevNfaPrefix(ng, expr, *prefix, cc);
+ u32 rev_comp_id = doSomRevNfaPrefix(ng, expr, *prefix, cc);
updatePrefixReportsRevNFA(rm, *prefix, rev_comp_id);
}
- renumber_vertices(*prefix);
+ renumber_vertices(*prefix);
if (!ng.addHolder(*prefix)) {
DEBUG_PRINTF("failed to add holder\n");
clear_graph(g);
@@ -3088,18 +3088,18 @@ sombe_rv doSom(NG &ng, NGHolder &g, const ExpressionInfo &expr, u32 comp_id,
updatePrefixReports(rm, *prefix, INTERNAL_SOM_LOC_SET);
}
if (prefix_by_rev && !plan.front().no_implement) {
- u32 rev_comp_id = doSomRevNfaPrefix(ng, expr, *prefix, cc);
+ u32 rev_comp_id = doSomRevNfaPrefix(ng, expr, *prefix, cc);
updatePrefixReportsRevNFA(rm, *prefix, rev_comp_id);
}
- implementSomPlan(ng, expr, comp_id, g, plan, som_loc);
+ implementSomPlan(ng, expr, comp_id, g, plan, som_loc);
DEBUG_PRINTF("success\n");
return SOMBE_HANDLED_INTERNAL;
}
-sombe_rv doSomWithHaig(NG &ng, NGHolder &g, const ExpressionInfo &expr,
- u32 comp_id, som_type som) {
+sombe_rv doSomWithHaig(NG &ng, NGHolder &g, const ExpressionInfo &expr,
+ u32 comp_id, som_type som) {
assert(som);
DEBUG_PRINTF("som+haig hello\n");
@@ -3136,7 +3136,7 @@ sombe_rv doSomWithHaig(NG &ng, NGHolder &g, const ExpressionInfo &expr,
buildRegionMapping(g, regions, info, true);
sombe_rv rv =
- doHaigLitSom(ng, g, expr, comp_id, som, regions, info, info.begin());
+ doHaigLitSom(ng, g, expr, comp_id, som, regions, info, info.begin());
if (rv == SOMBE_FAIL) {
clear_graph(g);
cloneHolder(g, g_pristine);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_som.h b/contrib/libs/hyperscan/src/nfagraph/ng_som.h
index 31631c7458a..ecae4c67fba 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_som.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_som.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,14 +34,14 @@
#define NG_SOM_H
#include "som/som.h"
-#include "ue2common.h"
+#include "ue2common.h"
namespace ue2 {
-class ExpressionInfo;
+class ExpressionInfo;
class NG;
class NGHolder;
-class ReportManager;
+class ReportManager;
struct Grey;
enum sombe_rv {
@@ -65,17 +65,17 @@ enum sombe_rv {
* May throw a "Pattern too large" exception if prefixes of the
* pattern are too large to compile.
*/
-sombe_rv doSom(NG &ng, NGHolder &h, const ExpressionInfo &expr, u32 comp_id,
+sombe_rv doSom(NG &ng, NGHolder &h, const ExpressionInfo &expr, u32 comp_id,
som_type som);
/** Returns SOMBE_FAIL (and the original graph) if SOM cannot be established.
* May also throw pattern too large if prefixes of the pattern are too large to
* compile. */
-sombe_rv doSomWithHaig(NG &ng, NGHolder &h, const ExpressionInfo &expr,
- u32 comp_id, som_type som);
+sombe_rv doSomWithHaig(NG &ng, NGHolder &h, const ExpressionInfo &expr,
+ u32 comp_id, som_type som);
+
+void makeReportsSomPass(ReportManager &rm, NGHolder &g);
-void makeReportsSomPass(ReportManager &rm, NGHolder &g);
-
} // namespace ue2
#endif // NG_SOM_H
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_som_add_redundancy.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_som_add_redundancy.cpp
index ba7a2c40c8f..33544ec1736 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_som_add_redundancy.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_som_add_redundancy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -155,13 +155,13 @@ bool addSomRedundancy(NGHolder &g, vector<DepthMinMax> &depths) {
if (is_special(v, g)) {
continue;
}
- if (!in_degree(v, g)) {
+ if (!in_degree(v, g)) {
continue; // unreachable, probably killed
}
const DepthMinMax &d = getDepth(v, g, depths);
- DEBUG_PRINTF("vertex %zu has depths %s\n", g[v].index,
+ DEBUG_PRINTF("vertex %zu has depths %s\n", g[v].index,
d.str().c_str());
if (d.min == d.max) {
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_som_util.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_som_util.cpp
index d6ccc24aa07..1e7a41bb0ca 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_som_util.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_som_util.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -54,7 +54,7 @@ vector<DepthMinMax> getDistancesFromSOM(const NGHolder &g_orig) {
// We operate on a temporary copy of the original graph here, so we don't
// have to mutate the original.
NGHolder g;
- unordered_map<NFAVertex, NFAVertex> vmap; // vertex in g_orig to vertex in g
+ unordered_map<NFAVertex, NFAVertex> vmap; // vertex in g_orig to vertex in g
cloneHolder(g, g_orig, &vmap);
vector<NFAVertex> vstarts;
@@ -76,10 +76,10 @@ vector<DepthMinMax> getDistancesFromSOM(const NGHolder &g_orig) {
clear_in_edges(v, g);
}
- //dumpGraph("som_depth.dot", g);
+ //dumpGraph("som_depth.dot", g);
- // Find depths, indexed by vertex index in g
- auto temp_depths = calcDepthsFrom(g, g.start);
+ // Find depths, indexed by vertex index in g
+ auto temp_depths = calcDepthsFrom(g, g.start);
// Transfer depths, indexed by vertex index in g_orig.
vector<DepthMinMax> depths(num_vertices(g_orig));
@@ -94,7 +94,7 @@ vector<DepthMinMax> getDistancesFromSOM(const NGHolder &g_orig) {
if (v_orig == g_orig.startDs || is_virtual_start(v_orig, g_orig)) {
// StartDs and virtual starts always have zero depth.
- d = DepthMinMax(depth(0), depth(0));
+ d = DepthMinMax(depth(0), depth(0));
} else {
u32 new_idx = g[v_new].index;
d = temp_depths.at(new_idx);
@@ -136,14 +136,14 @@ bool firstMatchIsFirst(const NGHolder &p) {
return false;
}
- flat_set<NFAVertex> states;
+ flat_set<NFAVertex> states;
/* turn on all states (except starts - avoid suffix matches) */
/* If we were doing (1) we would also except states leading to accepts -
avoid prefix matches */
for (auto v : vertices_range(p)) {
assert(!is_virtual_start(v, p));
if (!is_special(v, p)) {
- DEBUG_PRINTF("turning on %zu\n", p[v].index);
+ DEBUG_PRINTF("turning on %zu\n", p[v].index);
states.insert(v);
}
}
@@ -154,9 +154,9 @@ bool firstMatchIsFirst(const NGHolder &p) {
for (auto v : states) {
/* need to check if this vertex may represent an infix match - ie
* it does not have an edge to accept. */
- DEBUG_PRINTF("check %zu\n", p[v].index);
+ DEBUG_PRINTF("check %zu\n", p[v].index);
if (!edge(v, p.accept, p).second) {
- DEBUG_PRINTF("fail %zu\n", p[v].index);
+ DEBUG_PRINTF("fail %zu\n", p[v].index);
return false;
}
}
@@ -166,7 +166,7 @@ bool firstMatchIsFirst(const NGHolder &p) {
}
bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
smgb_cache &cache) {
/* Need to ensure all matches of the graph g up to u contain no infixes
* which are also matches of the graph to u.
@@ -186,11 +186,11 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
return cache.smgb[u];
}
- DEBUG_PRINTF("checking if som can go backwards on %zu\n", g[u].index);
+ DEBUG_PRINTF("checking if som can go backwards on %zu\n", g[u].index);
set<NFAEdge> be;
BackEdges<set<NFAEdge>> backEdgeVisitor(be);
- boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start));
+ boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start));
bool rv;
if (0) {
@@ -207,7 +207,7 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
NFAVertex s = source(e, g);
NFAVertex t = target(e, g);
/* only need to worry about big cycles including/before u */
- DEBUG_PRINTF("back edge %zu %zu\n", g[s].index, g[t].index);
+ DEBUG_PRINTF("back edge %zu %zu\n", g[s].index, g[t].index);
if (s != t && region_map.at(s) <= u_region) {
DEBUG_PRINTF("eek big cycle\n");
rv = true; /* big cycle -> eek */
@@ -215,11 +215,11 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
}
}
- unordered_map<NFAVertex, NFAVertex> orig_to_copy;
+ unordered_map<NFAVertex, NFAVertex> orig_to_copy;
NGHolder c_g;
cloneHolder(c_g, g, &orig_to_copy);
- /* treat virtual starts as unconditional - wire to startDs instead */
+ /* treat virtual starts as unconditional - wire to startDs instead */
for (NFAVertex v : vertices_range(g)) {
if (!is_virtual_start(v, g)) {
continue;
@@ -232,7 +232,7 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
clear_vertex(c_v, c_g);
}
- /* treat u as the only accept state */
+ /* treat u as the only accept state */
NFAVertex c_u = orig_to_copy[u];
clear_in_edges(c_g.acceptEod, c_g);
add_edge(c_g.accept, c_g.acceptEod, c_g);
@@ -253,9 +253,9 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
}
for (auto v : adjacent_vertices_range(t, g)) {
if (contains(u_succ, v)) {
- /* due to virtual starts being aliased with normal starts in the
- * copy of the graph, we may have already added the edges. */
- add_edge_if_not_present(orig_to_copy[t], c_g.accept, c_g);
+ /* due to virtual starts being aliased with normal starts in the
+ * copy of the graph, we may have already added the edges. */
+ add_edge_if_not_present(orig_to_copy[t], c_g.accept, c_g);
break;
}
}
@@ -264,13 +264,13 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
pruneUseless(c_g);
be.clear();
- boost::depth_first_search(c_g, visitor(backEdgeVisitor)
- .root_vertex(c_g.start));
+ boost::depth_first_search(c_g, visitor(backEdgeVisitor)
+ .root_vertex(c_g.start));
for (const auto &e : be) {
NFAVertex s = source(e, c_g);
NFAVertex t = target(e, c_g);
- DEBUG_PRINTF("back edge %zu %zu\n", c_g[s].index, c_g[t].index);
+ DEBUG_PRINTF("back edge %zu %zu\n", c_g[s].index, c_g[t].index);
if (s != t) {
assert(0);
DEBUG_PRINTF("eek big cycle\n");
@@ -287,7 +287,7 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
}
bool sentClearsTail(const NGHolder &g,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
const NGHolder &sent, u32 last_head_region,
u32 *bad_region) {
/* if a subsequent match from the prefix clears the rest of the pattern
@@ -312,7 +312,7 @@ bool sentClearsTail(const NGHolder &g,
*/
u32 first_bad_region = ~0U;
- flat_set<NFAVertex> states;
+ flat_set<NFAVertex> states;
/* turn on all states */
DEBUG_PRINTF("region %u is cutover\n", last_head_region);
for (auto v : vertices_range(g)) {
@@ -322,7 +322,7 @@ bool sentClearsTail(const NGHolder &g,
}
for (UNUSED auto v : states) {
- DEBUG_PRINTF("start state: %zu\n", g[v].index);
+ DEBUG_PRINTF("start state: %zu\n", g[v].index);
}
/* run the prefix the main graph */
@@ -334,7 +334,7 @@ bool sentClearsTail(const NGHolder &g,
continue; /* not in tail */
}
- DEBUG_PRINTF("v %zu is still on\n", g[v].index);
+ DEBUG_PRINTF("v %zu is still on\n", g[v].index);
assert(v != g.accept && v != g.acceptEod); /* no cr */
assert(contains(region_map, v));
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_som_util.h b/contrib/libs/hyperscan/src/nfagraph/ng_som_util.h
index c06260fb9f0..e2d38642c4f 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_som_util.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_som_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@
#include "util/depth.h"
#include <map>
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
namespace ue2 {
@@ -61,7 +61,7 @@ struct smgb_cache : public mbsb_cache {
};
bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
- const std::unordered_map<NFAVertex, u32> &region_map,
+ const std::unordered_map<NFAVertex, u32> &region_map,
smgb_cache &cache);
/**
@@ -75,7 +75,7 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g,
* region ID associated with a tail state that is still on.
*/
bool sentClearsTail(const NGHolder &g,
- const std::unordered_map<NFAVertex, u32> &region_map,
+ const std::unordered_map<NFAVertex, u32> &region_map,
const NGHolder &sent, u32 last_head_region,
u32 *bad_region);
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_split.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_split.cpp
index ac1531881c1..91a099fc38a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_split.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_split.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -62,13 +62,13 @@ void clearAccepts(NGHolder &g) {
}
static
-void filterSplitMap(const NGHolder &g,
- unordered_map<NFAVertex, NFAVertex> *out_map) {
- unordered_set<NFAVertex> verts;
+void filterSplitMap(const NGHolder &g,
+ unordered_map<NFAVertex, NFAVertex> *out_map) {
+ unordered_set<NFAVertex> verts;
insert(&verts, vertices(g));
- auto it = out_map->begin();
+ auto it = out_map->begin();
while (it != out_map->end()) {
- auto jt = it;
+ auto jt = it;
++it;
if (!contains(verts, jt->second)) {
out_map->erase(jt);
@@ -78,8 +78,8 @@ void filterSplitMap(const NGHolder &g,
static
void splitLHS(const NGHolder &base, const vector<NFAVertex> &pivots,
- const vector<NFAVertex> &rhs_pivots, NGHolder *lhs,
- unordered_map<NFAVertex, NFAVertex> *lhs_map) {
+ const vector<NFAVertex> &rhs_pivots, NGHolder *lhs,
+ unordered_map<NFAVertex, NFAVertex> *lhs_map) {
assert(lhs && lhs_map);
cloneHolder(*lhs, base, lhs_map);
@@ -87,7 +87,7 @@ void splitLHS(const NGHolder &base, const vector<NFAVertex> &pivots,
clearAccepts(*lhs);
for (auto pivot : pivots) {
- DEBUG_PRINTF("pivot is %zu lv %zu lm %zu\n", base[pivot].index,
+ DEBUG_PRINTF("pivot is %zu lv %zu lm %zu\n", base[pivot].index,
num_vertices(*lhs), lhs_map->size());
assert(contains(*lhs_map, pivot));
@@ -100,12 +100,12 @@ void splitLHS(const NGHolder &base, const vector<NFAVertex> &pivots,
add_edge((*lhs_map)[pivot], lhs->accept, *lhs);
}
- /* should do the renumbering unconditionally as we know edges are already
- * misnumbered */
- pruneUseless(*lhs, false);
- renumber_edges(*lhs);
- renumber_vertices(*lhs);
-
+ /* should do the renumbering unconditionally as we know edges are already
+ * misnumbered */
+ pruneUseless(*lhs, false);
+ renumber_edges(*lhs);
+ renumber_vertices(*lhs);
+
filterSplitMap(*lhs, lhs_map);
switch (base.kind) {
@@ -117,21 +117,21 @@ void splitLHS(const NGHolder &base, const vector<NFAVertex> &pivots,
case NFA_SUFFIX:
lhs->kind = NFA_INFIX;
break;
- case NFA_EAGER_PREFIX:
- /* Current code should not be assigning eager until well after all the
- * splitting is done. */
- assert(0);
- lhs->kind = NFA_EAGER_PREFIX;
- break;
+ case NFA_EAGER_PREFIX:
+ /* Current code should not be assigning eager until well after all the
+ * splitting is done. */
+ assert(0);
+ lhs->kind = NFA_EAGER_PREFIX;
+ break;
case NFA_REV_PREFIX:
- case NFA_OUTFIX_RAW:
+ case NFA_OUTFIX_RAW:
assert(0);
break;
}
}
void splitLHS(const NGHolder &base, NFAVertex pivot,
- NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map) {
+ NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map) {
vector<NFAVertex> pivots(1, pivot);
vector<NFAVertex> rhs_pivots;
insert(&rhs_pivots, rhs_pivots.end(), adjacent_vertices(pivot, base));
@@ -139,7 +139,7 @@ void splitLHS(const NGHolder &base, NFAVertex pivot,
}
void splitRHS(const NGHolder &base, const vector<NFAVertex> &pivots,
- NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
+ NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
assert(rhs && rhs_map);
cloneHolder(*rhs, base, rhs_map);
@@ -151,15 +151,15 @@ void splitRHS(const NGHolder &base, const vector<NFAVertex> &pivots,
for (auto pivot : pivots) {
assert(contains(*rhs_map, pivot));
- NFAEdge e = add_edge(rhs->start, (*rhs_map)[pivot], *rhs);
- (*rhs)[e].tops.insert(DEFAULT_TOP);
+ NFAEdge e = add_edge(rhs->start, (*rhs_map)[pivot], *rhs);
+ (*rhs)[e].tops.insert(DEFAULT_TOP);
}
-
- /* should do the renumbering unconditionally as we know edges are already
- * misnumbered */
- pruneUseless(*rhs, false);
- renumber_edges(*rhs);
- renumber_vertices(*rhs);
+
+ /* should do the renumbering unconditionally as we know edges are already
+ * misnumbered */
+ pruneUseless(*rhs, false);
+ renumber_edges(*rhs);
+ renumber_vertices(*rhs);
filterSplitMap(*rhs, rhs_map);
switch (base.kind) {
@@ -171,14 +171,14 @@ void splitRHS(const NGHolder &base, const vector<NFAVertex> &pivots,
case NFA_OUTFIX:
rhs->kind = NFA_SUFFIX;
break;
- case NFA_EAGER_PREFIX:
- /* Current code should not be assigning eager until well after all the
- * splitting is done. */
- assert(0);
- rhs->kind = NFA_INFIX;
- break;
+ case NFA_EAGER_PREFIX:
+ /* Current code should not be assigning eager until well after all the
+ * splitting is done. */
+ assert(0);
+ rhs->kind = NFA_INFIX;
+ break;
case NFA_REV_PREFIX:
- case NFA_OUTFIX_RAW:
+ case NFA_OUTFIX_RAW:
assert(0);
break;
}
@@ -191,8 +191,8 @@ void findCommonSuccessors(const NGHolder &g, const vector<NFAVertex> &pivots,
vector<NFAVertex> &succ) {
assert(!pivots.empty());
- set<NFAVertex> adj;
- set<NFAVertex> adj_temp;
+ set<NFAVertex> adj;
+ set<NFAVertex> adj_temp;
insert(&adj, adjacent_vertices(pivots.at(0), g));
@@ -211,12 +211,12 @@ void findCommonSuccessors(const NGHolder &g, const vector<NFAVertex> &pivots,
}
void splitGraph(const NGHolder &base, const vector<NFAVertex> &pivots,
- NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map,
- NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
+ NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map,
+ NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
DEBUG_PRINTF("splitting graph at %zu vertices\n", pivots.size());
assert(!has_parallel_edge(base));
- assert(isCorrectlyTopped(base));
+ assert(isCorrectlyTopped(base));
/* RHS pivots are built from the common set of successors of pivots. */
vector<NFAVertex> rhs_pivots;
@@ -230,13 +230,13 @@ void splitGraph(const NGHolder &base, const vector<NFAVertex> &pivots,
assert(!has_parallel_edge(*lhs));
assert(!has_parallel_edge(*rhs));
- assert(isCorrectlyTopped(*lhs));
- assert(isCorrectlyTopped(*rhs));
+ assert(isCorrectlyTopped(*lhs));
+ assert(isCorrectlyTopped(*rhs));
}
void splitGraph(const NGHolder &base, NFAVertex pivot,
- NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map,
- NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
+ NGHolder *lhs, unordered_map<NFAVertex, NFAVertex> *lhs_map,
+ NGHolder *rhs, unordered_map<NFAVertex, NFAVertex> *rhs_map) {
vector<NFAVertex> pivots(1, pivot);
splitGraph(base, pivots, lhs, lhs_map, rhs, rhs_map);
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_split.h b/contrib/libs/hyperscan/src/nfagraph/ng_split.h
index 3762bca1709..9ddc0332570 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_split.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_split.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,9 +33,9 @@
#ifndef NG_SPLIT_H
#define NG_SPLIT_H
-#include "ng_holder.h"
-
-#include <unordered_map>
+#include "ng_holder.h"
+
+#include <unordered_map>
#include <vector>
namespace ue2 {
@@ -47,29 +47,29 @@ class NGHolder;
* is in the lhs if it is reachable from start without going through the
* pivot. The pivot ends up in the LHS and any adjacent vertices in the RHS.
*
- * Note: The RHS is setup to be triggered by TOP 0
- *
+ * Note: The RHS is setup to be triggered by TOP 0
+ *
* When multiple split vertices are provided:
* - RHS contains all vertices reachable from every pivot
* - LHS contains all vertices which are reachable from start ignoring any
* vertices which have an edge to every pivot
*/
void splitGraph(const NGHolder &base, NFAVertex pivot, NGHolder *lhs,
- std::unordered_map<NFAVertex, NFAVertex> *lhs_map,
+ std::unordered_map<NFAVertex, NFAVertex> *lhs_map,
NGHolder *rhs,
- std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
+ std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
void splitGraph(const NGHolder &base, const std::vector<NFAVertex> &pivots,
NGHolder *lhs,
- std::unordered_map<NFAVertex, NFAVertex> *lhs_map,
+ std::unordered_map<NFAVertex, NFAVertex> *lhs_map,
NGHolder *rhs,
- std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
+ std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
void splitLHS(const NGHolder &base, NFAVertex pivot, NGHolder *lhs,
- std::unordered_map<NFAVertex, NFAVertex> *lhs_map);
+ std::unordered_map<NFAVertex, NFAVertex> *lhs_map);
void splitRHS(const NGHolder &base, const std::vector<NFAVertex> &pivots,
- NGHolder *rhs, std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
+ NGHolder *rhs, std::unordered_map<NFAVertex, NFAVertex> *rhs_map);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_squash.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_squash.cpp
index c288415c01f..03495d14410 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_squash.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_squash.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -111,8 +111,8 @@
#include <deque>
#include <map>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/reverse_graph.hpp>
@@ -121,26 +121,26 @@ using namespace std;
namespace ue2 {
-using PostDomTree = unordered_map<NFAVertex, unordered_set<NFAVertex>>;
+using PostDomTree = unordered_map<NFAVertex, unordered_set<NFAVertex>>;
static
-PostDomTree buildPDomTree(const NGHolder &g) {
- PostDomTree tree;
- tree.reserve(num_vertices(g));
+PostDomTree buildPDomTree(const NGHolder &g) {
+ PostDomTree tree;
+ tree.reserve(num_vertices(g));
+
+ auto postdominators = findPostDominators(g);
- auto postdominators = findPostDominators(g);
-
for (auto v : vertices_range(g)) {
if (is_special(v, g)) {
continue;
}
NFAVertex pdom = postdominators[v];
if (pdom) {
- DEBUG_PRINTF("vertex %zu -> %zu\n", g[pdom].index, g[v].index);
+ DEBUG_PRINTF("vertex %zu -> %zu\n", g[pdom].index, g[v].index);
tree[pdom].insert(v);
}
}
- return tree;
+ return tree;
}
/**
@@ -153,13 +153,13 @@ void buildSquashMask(NFAStateSet &mask, const NGHolder &g, NFAVertex v,
const CharReach &cr, const NFAStateSet &init,
const vector<NFAVertex> &vByIndex, const PostDomTree &tree,
som_type som, const vector<DepthMinMax> &som_depths,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
smgb_cache &cache) {
- DEBUG_PRINTF("build base squash mask for vertex %zu)\n", g[v].index);
+ DEBUG_PRINTF("build base squash mask for vertex %zu)\n", g[v].index);
vector<NFAVertex> q;
- auto it = tree.find(v);
+ auto it = tree.find(v);
if (it != tree.end()) {
q.insert(q.end(), it->second.begin(), it->second.end());
}
@@ -275,9 +275,9 @@ void buildPred(NFAStateSet &pred, const NGHolder &g, NFAVertex v) {
static
void findDerivedSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
const PostDomTree &pdom_tree, const NFAStateSet &init,
- unordered_map<NFAVertex, NFAStateSet> *squash,
- som_type som, const vector<DepthMinMax> &som_depths,
- const unordered_map<NFAVertex, u32> &region_map,
+ unordered_map<NFAVertex, NFAStateSet> *squash,
+ som_type som, const vector<DepthMinMax> &som_depths,
+ const unordered_map<NFAVertex, u32> &region_map,
smgb_cache &cache) {
deque<NFAVertex> remaining;
for (const auto &m : *squash) {
@@ -302,7 +302,7 @@ void findDerivedSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
}
NFAStateSet u_squash(init.size());
- size_t u_index = g[u].index;
+ size_t u_index = g[u].index;
buildSquashMask(u_squash, g, u, g[u].char_reach, init, vByIndex,
pdom_tree, som, som_depths, region_map, cache);
@@ -310,7 +310,7 @@ void findDerivedSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
u_squash.set(u_index); /* never clear ourselves */
if ((~u_squash).any()) { // i.e. some bits unset in mask
- DEBUG_PRINTF("%zu is an upstream squasher of %zu\n", u_index,
+ DEBUG_PRINTF("%zu is an upstream squasher of %zu\n", u_index,
g[v].index);
(*squash)[u] = u_squash;
remaining.push_back(u);
@@ -319,61 +319,61 @@ void findDerivedSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
}
}
-/* If there are redundant states in the graph, it may be possible for two
- * sibling .* states to try to squash each other -- which should be prevented.
- *
- * Note: this situation should only happen if ng_equivalence has not been run.
- */
-static
-void clearMutualSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
- unordered_map<NFAVertex, NFAStateSet> &squash) {
- for (auto it = squash.begin(); it != squash.end();) {
- NFAVertex a = it->first;
- u32 a_index = g[a].index;
-
- NFAStateSet a_squash = ~it->second; /* default is mask of survivors */
- for (auto b_index = a_squash.find_first(); b_index != a_squash.npos;
- b_index = a_squash.find_next(b_index)) {
- assert(b_index != a_index);
- NFAVertex b = vByIndex[b_index];
-
- auto b_it = squash.find(b);
- if (b_it == squash.end()) {
- continue;
- }
- auto &b_squash = b_it->second;
- if (!b_squash.test(a_index)) {
- /* b and a squash each other, prevent this */
- DEBUG_PRINTF("removing mutual squash %u %zu\n",
- a_index, b_index);
- b_squash.set(a_index);
- it->second.set(b_index);
- }
- }
-
- if (it->second.all()) {
- DEBUG_PRINTF("%u is no longer an effective squash state\n",
- a_index);
- it = squash.erase(it);
- } else {
- ++it;
- }
- }
-}
-
-unordered_map<NFAVertex, NFAStateSet> findSquashers(const NGHolder &g,
- som_type som) {
- unordered_map<NFAVertex, NFAStateSet> squash;
-
+/* If there are redundant states in the graph, it may be possible for two
+ * sibling .* states to try to squash each other -- which should be prevented.
+ *
+ * Note: this situation should only happen if ng_equivalence has not been run.
+ */
+static
+void clearMutualSquashers(const NGHolder &g, const vector<NFAVertex> &vByIndex,
+ unordered_map<NFAVertex, NFAStateSet> &squash) {
+ for (auto it = squash.begin(); it != squash.end();) {
+ NFAVertex a = it->first;
+ u32 a_index = g[a].index;
+
+ NFAStateSet a_squash = ~it->second; /* default is mask of survivors */
+ for (auto b_index = a_squash.find_first(); b_index != a_squash.npos;
+ b_index = a_squash.find_next(b_index)) {
+ assert(b_index != a_index);
+ NFAVertex b = vByIndex[b_index];
+
+ auto b_it = squash.find(b);
+ if (b_it == squash.end()) {
+ continue;
+ }
+ auto &b_squash = b_it->second;
+ if (!b_squash.test(a_index)) {
+ /* b and a squash each other, prevent this */
+ DEBUG_PRINTF("removing mutual squash %u %zu\n",
+ a_index, b_index);
+ b_squash.set(a_index);
+ it->second.set(b_index);
+ }
+ }
+
+ if (it->second.all()) {
+ DEBUG_PRINTF("%u is no longer an effective squash state\n",
+ a_index);
+ it = squash.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+unordered_map<NFAVertex, NFAStateSet> findSquashers(const NGHolder &g,
+ som_type som) {
+ unordered_map<NFAVertex, NFAStateSet> squash;
+
// Number of bits to use for all our masks. If we're a triggered graph,
// tops have already been assigned, so we don't have to account for them.
const u32 numStates = num_vertices(g);
// Build post-dominator tree.
- auto pdom_tree = buildPDomTree(g);
+ auto pdom_tree = buildPDomTree(g);
// Build list of vertices by state ID and a set of init states.
- vector<NFAVertex> vByIndex(numStates, NGHolder::null_vertex());
+ vector<NFAVertex> vByIndex(numStates, NGHolder::null_vertex());
NFAStateSet initStates(numStates);
smgb_cache cache(g);
@@ -398,7 +398,7 @@ unordered_map<NFAVertex, NFAStateSet> findSquashers(const NGHolder &g,
for (u32 i = 0; i < numStates; i++) {
NFAVertex v = vByIndex[i];
- assert(v != NGHolder::null_vertex());
+ assert(v != NGHolder::null_vertex());
const CharReach &cr = g[v].char_reach;
/* only non-init cyclics can be squashers */
@@ -502,8 +502,8 @@ unordered_map<NFAVertex, NFAStateSet> findSquashers(const NGHolder &g,
findDerivedSquashers(g, vByIndex, pdom_tree, initStates, &squash, som,
som_depths, region_map, cache);
- clearMutualSquashers(g, vByIndex, squash);
-
+ clearMutualSquashers(g, vByIndex, squash);
+
return squash;
}
@@ -515,11 +515,11 @@ unordered_map<NFAVertex, NFAStateSet> findSquashers(const NGHolder &g,
* -# squash only a few acyclic states
*/
void filterSquashers(const NGHolder &g,
- unordered_map<NFAVertex, NFAStateSet> &squash) {
- assert(hasCorrectlyNumberedVertices(g));
-
+ unordered_map<NFAVertex, NFAStateSet> &squash) {
+ assert(hasCorrectlyNumberedVertices(g));
+
DEBUG_PRINTF("filtering\n");
- vector<NFAVertex> rev(num_vertices(g)); /* vertex_index -> vertex */
+ vector<NFAVertex> rev(num_vertices(g)); /* vertex_index -> vertex */
for (auto v : vertices_range(g)) {
rev[g[v].index] = v;
}
@@ -528,7 +528,7 @@ void filterSquashers(const NGHolder &g,
if (!contains(squash, v)) {
continue;
}
- DEBUG_PRINTF("looking at squash set for vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("looking at squash set for vertex %zu\n", g[v].index);
if (!hasSelfLoop(v, g)) {
DEBUG_PRINTF("acyclic\n");
@@ -538,8 +538,8 @@ void filterSquashers(const NGHolder &g,
NFAStateSet squashed = squash[v];
squashed.flip(); /* default sense for mask of survivors */
- for (auto sq = squashed.find_first(); sq != squashed.npos;
- sq = squashed.find_next(sq)) {
+ for (auto sq = squashed.find_first(); sq != squashed.npos;
+ sq = squashed.find_next(sq)) {
NFAVertex u = rev[sq];
if (hasSelfLoop(u, g)) {
DEBUG_PRINTF("squashing a cyclic (%zu) is always good\n", sq);
@@ -606,7 +606,7 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) {
NFAVertex u = source(e, g);
const auto &r = g[u].reports;
if (!r.empty() && is_subset_of(r, reports)) {
- DEBUG_PRINTF("vertex %zu\n", g[u].index);
+ DEBUG_PRINTF("vertex %zu\n", g[u].index);
dead.insert(e);
}
}
@@ -615,7 +615,7 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) {
NFAVertex u = source(e, g);
const auto &r = g[u].reports;
if (!r.empty() && is_subset_of(r, reports)) {
- DEBUG_PRINTF("vertex %zu\n", g[u].index);
+ DEBUG_PRINTF("vertex %zu\n", g[u].index);
dead.insert(e);
}
}
@@ -626,9 +626,9 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) {
static
vector<NFAVertex> findUnreachable(const NGHolder &g) {
- const boost::reverse_graph<NGHolder, const NGHolder &> revg(g);
+ const boost::reverse_graph<NGHolder, const NGHolder &> revg(g);
- unordered_map<NFAVertex, boost::default_color_type> colours;
+ unordered_map<NFAVertex, boost::default_color_type> colours;
colours.reserve(num_vertices(g));
depth_first_visit(revg, g.acceptEod,
@@ -639,7 +639,7 @@ vector<NFAVertex> findUnreachable(const NGHolder &g) {
vector<NFAVertex> unreach;
for (auto v : vertices_range(revg)) {
if (!contains(colours, v)) {
- unreach.push_back(NFAVertex(v));
+ unreach.push_back(NFAVertex(v));
}
}
return unreach;
@@ -647,9 +647,9 @@ vector<NFAVertex> findUnreachable(const NGHolder &g) {
/** Populates squash masks for states that can be switched off by highlander
* (single match) reporters. */
-unordered_map<NFAVertex, NFAStateSet>
+unordered_map<NFAVertex, NFAStateSet>
findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) {
- unordered_map<NFAVertex, NFAStateSet> squash;
+ unordered_map<NFAVertex, NFAStateSet> squash;
set<NFAVertex> verts;
getHighlanderReporters(g, g.accept, rm, verts);
@@ -662,7 +662,7 @@ findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) {
const u32 numStates = num_vertices(g);
for (auto v : verts) {
- DEBUG_PRINTF("vertex %zu with %zu reports\n", g[v].index,
+ DEBUG_PRINTF("vertex %zu with %zu reports\n", g[v].index,
g[v].reports.size());
// Find the set of vertices that lead to v or any other reporter with a
@@ -670,7 +670,7 @@ findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) {
// cutting the appropriate out-edges to accept and seeing which
// vertices become unreachable.
- unordered_map<NFAVertex, NFAVertex> orig_to_copy;
+ unordered_map<NFAVertex, NFAVertex> orig_to_copy;
NGHolder h;
cloneHolder(h, g, &orig_to_copy);
removeEdgesToAccept(h, orig_to_copy[v]);
@@ -689,7 +689,7 @@ findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) {
NFAStateSet &mask = squash[v];
for (auto uv : unreach) {
- DEBUG_PRINTF("squashes index %zu\n", h[uv].index);
+ DEBUG_PRINTF("squashes index %zu\n", h[uv].index);
mask.reset(h[uv].index);
}
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_squash.h b/contrib/libs/hyperscan/src/nfagraph/ng_squash.h
index f2d66744a5a..489f541e84d 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_squash.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_squash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,7 +36,7 @@
#include "som/som.h"
#include "ue2common.h"
-#include <unordered_map>
+#include <unordered_map>
#include <boost/dynamic_bitset.hpp>
namespace ue2 {
@@ -44,10 +44,10 @@ namespace ue2 {
class NGHolder;
class ReportManager;
-/**
- * Dynamically-sized bitset, as an NFA can have an arbitrary number of states.
- */
-using NFAStateSet = boost::dynamic_bitset<>;
+/**
+ * Dynamically-sized bitset, as an NFA can have an arbitrary number of states.
+ */
+using NFAStateSet = boost::dynamic_bitset<>;
/**
* Populates the squash mask for each vertex (i.e. the set of states to be left
@@ -55,16 +55,16 @@ using NFAStateSet = boost::dynamic_bitset<>;
*
* The NFAStateSet in the output map is indexed by vertex_index.
*/
-std::unordered_map<NFAVertex, NFAStateSet>
-findSquashers(const NGHolder &g, som_type som = SOM_NONE);
+std::unordered_map<NFAVertex, NFAStateSet>
+findSquashers(const NGHolder &g, som_type som = SOM_NONE);
/** Filters out squash states intended only for use in DFA construction. */
void filterSquashers(const NGHolder &g,
- std::unordered_map<NFAVertex, NFAStateSet> &squash);
+ std::unordered_map<NFAVertex, NFAStateSet> &squash);
/** Populates squash masks for states that can be switched off by highlander
* (single match) reporters. */
-std::unordered_map<NFAVertex, NFAStateSet>
+std::unordered_map<NFAVertex, NFAStateSet>
findHighlanderSquashers(const NGHolder &g, const ReportManager &rm);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_stop.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_stop.cpp
index 2b4adf5c642..5e627bb5934 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_stop.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_stop.cpp
@@ -60,9 +60,9 @@ namespace {
/** Depths from start, startDs for this graph. */
struct InitDepths {
- explicit InitDepths(const NGHolder &g)
- : start(calcDepthsFrom(g, g.start)),
- startDs(calcDepthsFrom(g, g.startDs)) {}
+ explicit InitDepths(const NGHolder &g)
+ : start(calcDepthsFrom(g, g.start)),
+ startDs(calcDepthsFrom(g, g.startDs)) {}
depth maxDist(const NGHolder &g, NFAVertex v) const {
u32 idx = g[v].index;
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.cpp
index 1bdc0980b97..4ad5ff7875a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -54,52 +54,52 @@
#include <set>
#include <vector>
-#include <boost/range/adaptor/map.hpp>
-
+#include <boost/range/adaptor/map.hpp>
+
using namespace std;
-using boost::adaptors::map_values;
+using boost::adaptors::map_values;
namespace ue2 {
static const u32 FAST_STATE_LIMIT = 256; /**< largest possible desirable NFA */
/** Sentinel value meaning no component has yet been selected. */
-static const u32 NO_COMPONENT = ~0U;
-
-static const u32 UNUSED_STATE = ~0U;
-
-namespace {
-struct ranking_info {
- explicit ranking_info(const NGHolder &h) : to_vertex(getTopoOrdering(h)) {
- u32 rank = 0;
-
- reverse(to_vertex.begin(), to_vertex.end());
-
- for (NFAVertex v : to_vertex) {
- to_rank[v] = rank++;
+static const u32 NO_COMPONENT = ~0U;
+
+static const u32 UNUSED_STATE = ~0U;
+
+namespace {
+struct ranking_info {
+ explicit ranking_info(const NGHolder &h) : to_vertex(getTopoOrdering(h)) {
+ u32 rank = 0;
+
+ reverse(to_vertex.begin(), to_vertex.end());
+
+ for (NFAVertex v : to_vertex) {
+ to_rank[v] = rank++;
+ }
+
+ for (NFAVertex v : vertices_range(h)) {
+ if (!contains(to_rank, v)) {
+ to_rank[v] = UNUSED_STATE;
+ }
}
-
- for (NFAVertex v : vertices_range(h)) {
- if (!contains(to_rank, v)) {
- to_rank[v] = UNUSED_STATE;
- }
- }
}
- NFAVertex at(u32 ranking) const { return to_vertex.at(ranking); }
- u32 get(NFAVertex v) const { return to_rank.at(v); }
- u32 size() const { return (u32)to_vertex.size(); }
- u32 add_to_tail(NFAVertex v) {
- u32 rank = size();
- to_rank[v] = rank;
- to_vertex.push_back(v);
- return rank;
+ NFAVertex at(u32 ranking) const { return to_vertex.at(ranking); }
+ u32 get(NFAVertex v) const { return to_rank.at(v); }
+ u32 size() const { return (u32)to_vertex.size(); }
+ u32 add_to_tail(NFAVertex v) {
+ u32 rank = size();
+ to_rank[v] = rank;
+ to_vertex.push_back(v);
+ return rank;
}
-private:
- vector<NFAVertex> to_vertex;
- unordered_map<NFAVertex, u32> to_rank;
-};
+private:
+ vector<NFAVertex> to_vertex;
+ unordered_map<NFAVertex, u32> to_rank;
+};
}
static never_inline
@@ -131,9 +131,9 @@ bool cplVerticesMatch(const NGHolder &ga, NFAVertex va,
}
static never_inline
-u32 cplCommonReachAndSimple(const NGHolder &ga, const ranking_info &a_ranking,
- const NGHolder &gb, const ranking_info &b_ranking) {
- u32 ml = min(a_ranking.size(), b_ranking.size());
+u32 cplCommonReachAndSimple(const NGHolder &ga, const ranking_info &a_ranking,
+ const NGHolder &gb, const ranking_info &b_ranking) {
+ u32 ml = min(a_ranking.size(), b_ranking.size());
if (ml > 65535) {
ml = 65535;
}
@@ -142,7 +142,7 @@ u32 cplCommonReachAndSimple(const NGHolder &ga, const ranking_info &a_ranking,
// "startedness" properties.
u32 max = 0;
for (; max < ml; max++) {
- if (!cplVerticesMatch(ga, a_ranking.at(max), gb, b_ranking.at(max))) {
+ if (!cplVerticesMatch(ga, a_ranking.at(max), gb, b_ranking.at(max))) {
break;
}
}
@@ -150,30 +150,30 @@ u32 cplCommonReachAndSimple(const NGHolder &ga, const ranking_info &a_ranking,
return max;
}
-static
-u32 commonPrefixLength(const NGHolder &ga, const ranking_info &a_ranking,
- const NGHolder &gb, const ranking_info &b_ranking) {
+static
+u32 commonPrefixLength(const NGHolder &ga, const ranking_info &a_ranking,
+ const NGHolder &gb, const ranking_info &b_ranking) {
/* upper bound on the common region based on local properties */
- u32 max = cplCommonReachAndSimple(ga, a_ranking, gb, b_ranking);
+ u32 max = cplCommonReachAndSimple(ga, a_ranking, gb, b_ranking);
DEBUG_PRINTF("cpl upper bound %u\n", max);
while (max > 0) {
/* shrink max region based on in-edges from outside the region */
for (size_t j = max; j > 0; j--) {
- NFAVertex a_v = a_ranking.at(j - 1);
- NFAVertex b_v = b_ranking.at(j - 1);
- for (auto u : inv_adjacent_vertices_range(a_v, ga)) {
- u32 state_id = a_ranking.get(u);
- if (state_id != UNUSED_STATE && state_id >= max) {
+ NFAVertex a_v = a_ranking.at(j - 1);
+ NFAVertex b_v = b_ranking.at(j - 1);
+ for (auto u : inv_adjacent_vertices_range(a_v, ga)) {
+ u32 state_id = a_ranking.get(u);
+ if (state_id != UNUSED_STATE && state_id >= max) {
max = j - 1;
DEBUG_PRINTF("lowering max to %u\n", max);
goto next_vertex;
}
}
- for (auto u : inv_adjacent_vertices_range(b_v, gb)) {
- u32 state_id = b_ranking.get(u);
- if (state_id != UNUSED_STATE && state_id >= max) {
+ for (auto u : inv_adjacent_vertices_range(b_v, gb)) {
+ u32 state_id = b_ranking.get(u);
+ if (state_id != UNUSED_STATE && state_id >= max) {
max = j - 1;
DEBUG_PRINTF("lowering max to %u\n", max);
goto next_vertex;
@@ -185,37 +185,37 @@ u32 commonPrefixLength(const NGHolder &ga, const ranking_info &a_ranking,
/* Ensure that every pair of vertices has same out-edges to vertices in
the region. */
- for (size_t i = 0; i < max; i++) {
+ for (size_t i = 0; i < max; i++) {
size_t a_count = 0;
size_t b_count = 0;
- for (NFAEdge a_edge : out_edges_range(a_ranking.at(i), ga)) {
- u32 sid = a_ranking.get(target(a_edge, ga));
- if (sid == UNUSED_STATE || sid >= max) {
+ for (NFAEdge a_edge : out_edges_range(a_ranking.at(i), ga)) {
+ u32 sid = a_ranking.get(target(a_edge, ga));
+ if (sid == UNUSED_STATE || sid >= max) {
continue;
}
a_count++;
- NFAEdge b_edge = edge(b_ranking.at(i), b_ranking.at(sid), gb);
+ NFAEdge b_edge = edge(b_ranking.at(i), b_ranking.at(sid), gb);
- if (!b_edge) {
+ if (!b_edge) {
max = i;
DEBUG_PRINTF("lowering max to %u due to edge %zu->%u\n",
max, i, sid);
- goto try_smaller;
+ goto try_smaller;
}
- if (ga[a_edge].tops != gb[b_edge].tops) {
+ if (ga[a_edge].tops != gb[b_edge].tops) {
max = i;
- DEBUG_PRINTF("tops don't match on edge %zu->%u\n", i, sid);
- goto try_smaller;
+ DEBUG_PRINTF("tops don't match on edge %zu->%u\n", i, sid);
+ goto try_smaller;
}
}
- for (NFAVertex b_v : adjacent_vertices_range(b_ranking.at(i), gb)) {
- u32 sid = b_ranking.get(b_v);
- if (sid == UNUSED_STATE || sid >= max) {
+ for (NFAVertex b_v : adjacent_vertices_range(b_ranking.at(i), gb)) {
+ u32 sid = b_ranking.get(b_v);
+ if (sid == UNUSED_STATE || sid >= max) {
continue;
}
@@ -224,54 +224,54 @@ u32 commonPrefixLength(const NGHolder &ga, const ranking_info &a_ranking,
if (a_count != b_count) {
max = i;
- DEBUG_PRINTF("lowering max to %u due to a,b count (a_count=%zu,"
- " b_count=%zu)\n", max, a_count, b_count);
- goto try_smaller;
+ DEBUG_PRINTF("lowering max to %u due to a,b count (a_count=%zu,"
+ " b_count=%zu)\n", max, a_count, b_count);
+ goto try_smaller;
}
}
- DEBUG_PRINTF("survived checks, returning cpl %u\n", max);
- return max;
- try_smaller:;
+ DEBUG_PRINTF("survived checks, returning cpl %u\n", max);
+ return max;
+ try_smaller:;
}
DEBUG_PRINTF("failed to find any common region\n");
return 0;
}
-u32 commonPrefixLength(const NGHolder &ga, const NGHolder &gb) {
- return commonPrefixLength(ga, ranking_info(ga), gb, ranking_info(gb));
-}
-
+u32 commonPrefixLength(const NGHolder &ga, const NGHolder &gb) {
+ return commonPrefixLength(ga, ranking_info(ga), gb, ranking_info(gb));
+}
+
static never_inline
-void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
- assert(&dest != &vic);
-
- auto dest_info = ranking_info(dest);
- auto vic_info = ranking_info(vic);
-
+void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
+ assert(&dest != &vic);
+
+ auto dest_info = ranking_info(dest);
+ auto vic_info = ranking_info(vic);
+
map<NFAVertex, NFAVertex> vmap; // vic -> dest
vmap[vic.start] = dest.start;
vmap[vic.startDs] = dest.startDs;
vmap[vic.accept] = dest.accept;
vmap[vic.acceptEod] = dest.acceptEod;
- vmap[NGHolder::null_vertex()] = NGHolder::null_vertex();
+ vmap[NGHolder::null_vertex()] = NGHolder::null_vertex();
// For vertices in the common len, add to vmap and merge in the reports, if
// any.
for (u32 i = 0; i < common_len; i++) {
- NFAVertex v_old = vic_info.at(i);
- NFAVertex v = dest_info.at(i);
+ NFAVertex v_old = vic_info.at(i);
+ NFAVertex v = dest_info.at(i);
vmap[v_old] = v;
const auto &reports = vic[v_old].reports;
dest[v].reports.insert(reports.begin(), reports.end());
}
- // Add in vertices beyond the common len
- for (u32 i = common_len; i < vic_info.size(); i++) {
- NFAVertex v_old = vic_info.at(i);
+ // Add in vertices beyond the common len
+ for (u32 i = common_len; i < vic_info.size(); i++) {
+ NFAVertex v_old = vic_info.at(i);
if (is_special(v_old, vic)) {
// Dest already has start vertices, just merge the reports.
@@ -283,17 +283,17 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
}
NFAVertex v = add_vertex(vic[v_old], dest);
- dest_info.add_to_tail(v);
+ dest_info.add_to_tail(v);
vmap[v_old] = v;
}
/* add edges */
DEBUG_PRINTF("common_len=%zu\n", common_len);
for (const auto &e : edges_range(vic)) {
- NFAVertex u_old = source(e, vic);
- NFAVertex v_old = target(e, vic);
- NFAVertex u = vmap[u_old];
- NFAVertex v = vmap[v_old];
+ NFAVertex u_old = source(e, vic);
+ NFAVertex v_old = target(e, vic);
+ NFAVertex u = vmap[u_old];
+ NFAVertex v = vmap[v_old];
bool uspecial = is_special(u, dest);
bool vspecial = is_special(v, dest);
@@ -304,14 +304,14 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
// We're in the common region if v's state ID is low enough, unless v
// is a special (an accept), in which case we use u's state ID.
- bool in_common_region = dest_info.get(v) < common_len;
- if (vspecial && dest_info.get(u) < common_len) {
+ bool in_common_region = dest_info.get(v) < common_len;
+ if (vspecial && dest_info.get(u) < common_len) {
in_common_region = true;
}
- DEBUG_PRINTF("adding idx=%zu (state %u) -> idx=%zu (state %u)%s\n",
- dest[u].index, dest_info.get(u),
- dest[v].index, dest_info.get(v),
+ DEBUG_PRINTF("adding idx=%zu (state %u) -> idx=%zu (state %u)%s\n",
+ dest[u].index, dest_info.get(u),
+ dest[v].index, dest_info.get(v),
in_common_region ? " [common]" : "");
if (in_common_region) {
@@ -319,7 +319,7 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
DEBUG_PRINTF("skipping common edge\n");
assert(edge(u, v, dest).second);
// Should never merge edges with different top values.
- assert(vic[e].tops == dest[edge(u, v, dest)].tops);
+ assert(vic[e].tops == dest[edge(u, v, dest)].tops);
continue;
} else {
assert(is_any_accept(v, dest));
@@ -335,8 +335,8 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) {
add_edge(u, v, vic[e], dest);
}
- renumber_edges(dest);
- renumber_vertices(dest);
+ renumber_edges(dest);
+ renumber_vertices(dest);
}
namespace {
@@ -363,20 +363,20 @@ struct NfaMergeCandidateH {
/** Returns true if graphs \p h1 and \p h2 can (and should) be merged. */
static
-bool shouldMerge(const NGHolder &ha, const NGHolder &hb, size_t cpl,
- const ReportManager *rm, const CompileContext &cc) {
- size_t combinedStateCount = num_vertices(ha) + num_vertices(hb) - cpl;
-
- combinedStateCount -= 2 * 2; /* discount accepts from both */
-
- if (is_triggered(ha)) {
- /* allow for a state for each top, ignore existing starts */
- combinedStateCount -= 2; /* for start, startDs */
- auto tops = getTops(ha);
- insert(&tops, getTops(hb));
- combinedStateCount += tops.size();
- }
-
+bool shouldMerge(const NGHolder &ha, const NGHolder &hb, size_t cpl,
+ const ReportManager *rm, const CompileContext &cc) {
+ size_t combinedStateCount = num_vertices(ha) + num_vertices(hb) - cpl;
+
+ combinedStateCount -= 2 * 2; /* discount accepts from both */
+
+ if (is_triggered(ha)) {
+ /* allow for a state for each top, ignore existing starts */
+ combinedStateCount -= 2; /* for start, startDs */
+ auto tops = getTops(ha);
+ insert(&tops, getTops(hb));
+ combinedStateCount += tops.size();
+ }
+
if (combinedStateCount > FAST_STATE_LIMIT) {
// More complex implementability check.
NGHolder h_temp;
@@ -418,13 +418,13 @@ void buildNfaMergeQueue(const vector<NGHolder *> &cluster,
// First, make sure all holders have numbered states and collect their
// counts.
- vector<ranking_info> states_map;
- states_map.reserve(cs);
+ vector<ranking_info> states_map;
+ states_map.reserve(cs);
for (size_t i = 0; i < cs; i++) {
assert(cluster[i]);
- assert(states_map.size() == i);
- const NGHolder &g = *(cluster[i]);
- states_map.emplace_back(g);
+ assert(states_map.size() == i);
+ const NGHolder &g = *(cluster[i]);
+ states_map.emplace_back(g);
}
vector<u16> seen_cpl(cs * cs, 0);
@@ -482,46 +482,46 @@ void buildNfaMergeQueue(const vector<NGHolder *> &cluster,
}
}
-/**
- * True if the graphs have mergeable starts.
- *
- * Nowadays, this means that any vacuous edges must have the same tops. In
- * addition, mixed-accept cases need to have matching reports.
- */
+/**
+ * True if the graphs have mergeable starts.
+ *
+ * Nowadays, this means that any vacuous edges must have the same tops. In
+ * addition, mixed-accept cases need to have matching reports.
+ */
static
bool mergeableStarts(const NGHolder &h1, const NGHolder &h2) {
- if (!isVacuous(h1) || !isVacuous(h2)) {
- return true;
- }
-
- // Vacuous edges from startDs should not occur: we have better ways to
- // implement true dot-star relationships. Just in case they do, ban them
- // from being merged unless they have identical reports.
- if (is_match_vertex(h1.startDs, h1) || is_match_vertex(h2.startDs, h2)) {
- assert(0);
- return false;
+ if (!isVacuous(h1) || !isVacuous(h2)) {
+ return true;
}
-
- /* TODO: relax top checks if reports match */
-
- // If both graphs have edge (start, accept), the tops must match.
- NFAEdge e1_accept = edge(h1.start, h1.accept, h1);
- NFAEdge e2_accept = edge(h2.start, h2.accept, h2);
- if (e1_accept && e2_accept && h1[e1_accept].tops != h2[e2_accept].tops) {
- return false;
+
+ // Vacuous edges from startDs should not occur: we have better ways to
+ // implement true dot-star relationships. Just in case they do, ban them
+ // from being merged unless they have identical reports.
+ if (is_match_vertex(h1.startDs, h1) || is_match_vertex(h2.startDs, h2)) {
+ assert(0);
+ return false;
}
- // If both graphs have edge (start, acceptEod), the tops must match.
- NFAEdge e1_eod = edge(h1.start, h1.acceptEod, h1);
- NFAEdge e2_eod = edge(h2.start, h2.acceptEod, h2);
- if (e1_eod && e2_eod && h1[e1_eod].tops != h2[e2_eod].tops) {
- return false;
- }
-
- // If one graph has an edge to accept and the other has an edge to
- // acceptEod, the reports must match for the merge to be safe.
- if ((e1_accept && e2_eod) || (e2_accept && e1_eod)) {
- if (h1[h1.start].reports != h2[h2.start].reports) {
+ /* TODO: relax top checks if reports match */
+
+ // If both graphs have edge (start, accept), the tops must match.
+ NFAEdge e1_accept = edge(h1.start, h1.accept, h1);
+ NFAEdge e2_accept = edge(h2.start, h2.accept, h2);
+ if (e1_accept && e2_accept && h1[e1_accept].tops != h2[e2_accept].tops) {
+ return false;
+ }
+
+ // If both graphs have edge (start, acceptEod), the tops must match.
+ NFAEdge e1_eod = edge(h1.start, h1.acceptEod, h1);
+ NFAEdge e2_eod = edge(h2.start, h2.acceptEod, h2);
+ if (e1_eod && e2_eod && h1[e1_eod].tops != h2[e2_eod].tops) {
+ return false;
+ }
+
+ // If one graph has an edge to accept and the other has an edge to
+ // acceptEod, the reports must match for the merge to be safe.
+ if ((e1_accept && e2_eod) || (e2_accept && e1_eod)) {
+ if (h1[h1.start].reports != h2[h2.start].reports) {
return false;
}
}
@@ -530,19 +530,19 @@ bool mergeableStarts(const NGHolder &h1, const NGHolder &h2) {
}
/** Merge graph \p ga into graph \p gb. Returns false on failure. */
-bool mergeNfaPair(const NGHolder &ga, NGHolder &gb, const ReportManager *rm,
+bool mergeNfaPair(const NGHolder &ga, NGHolder &gb, const ReportManager *rm,
const CompileContext &cc) {
assert(ga.kind == gb.kind);
- // Vacuous NFAs require special checks on their starts to ensure that tops
- // match, and that reports match for mixed-accept cases.
+ // Vacuous NFAs require special checks on their starts to ensure that tops
+ // match, and that reports match for mixed-accept cases.
if (!mergeableStarts(ga, gb)) {
DEBUG_PRINTF("starts aren't mergeable\n");
return false;
}
- u32 cpl = commonPrefixLength(ga, gb);
- if (!shouldMerge(gb, ga, cpl, rm, cc)) {
+ u32 cpl = commonPrefixLength(ga, gb);
+ if (!shouldMerge(gb, ga, cpl, rm, cc)) {
return false;
}
@@ -551,13 +551,13 @@ bool mergeNfaPair(const NGHolder &ga, NGHolder &gb, const ReportManager *rm,
return true;
}
-map<NGHolder *, NGHolder *> mergeNfaCluster(const vector<NGHolder *> &cluster,
- const ReportManager *rm,
- const CompileContext &cc) {
- map<NGHolder *, NGHolder *> merged;
-
+map<NGHolder *, NGHolder *> mergeNfaCluster(const vector<NGHolder *> &cluster,
+ const ReportManager *rm,
+ const CompileContext &cc) {
+ map<NGHolder *, NGHolder *> merged;
+
if (cluster.size() < 2) {
- return merged;
+ return merged;
}
DEBUG_PRINTF("new cluster, size %zu\n", cluster.size());
@@ -589,8 +589,8 @@ map<NGHolder *, NGHolder *> mergeNfaCluster(const vector<NGHolder *> &cluster,
}
}
}
-
- return merged;
+
+ return merged;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.h b/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.h
index 9336a78108a..b0f42670a36 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_uncalc_components.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -49,16 +49,16 @@ class ReportManager;
* The CPL is calculated based the topological ordering given by the state
* indices for each graph.
*/
-u32 commonPrefixLength(const NGHolder &ga, const NGHolder &gb);
+u32 commonPrefixLength(const NGHolder &ga, const NGHolder &gb);
/**
* \brief Merge the group of graphs in \p cluster where possible.
*
- * The (from, to) mapping of merged graphs is returned.
+ * The (from, to) mapping of merged graphs is returned.
*/
-std::map<NGHolder *, NGHolder *>
-mergeNfaCluster(const std::vector<NGHolder *> &cluster, const ReportManager *rm,
- const CompileContext &cc);
+std::map<NGHolder *, NGHolder *>
+mergeNfaCluster(const std::vector<NGHolder *> &cluster, const ReportManager *rm,
+ const CompileContext &cc);
/**
* \brief Merge graph \p ga into graph \p gb.
@@ -66,7 +66,7 @@ mergeNfaCluster(const std::vector<NGHolder *> &cluster, const ReportManager *rm,
* Returns false on failure. On success, \p gb is reduced via \ref
* reduceImplementableGraph and renumbered.
*/
-bool mergeNfaPair(const NGHolder &ga, NGHolder &gb, const ReportManager *rm,
+bool mergeNfaPair(const NGHolder &ga, NGHolder &gb, const ReportManager *rm,
const CompileContext &cc);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_utf8.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_utf8.cpp
index fa062a05da0..89500fe39ec 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_utf8.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_utf8.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@
#include "ng.h"
#include "ng_prune.h"
#include "ng_util.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "util/graph_range.h"
#include "util/unicode_def.h"
@@ -46,14 +46,14 @@ using namespace std;
namespace ue2 {
static
-void allowIllegal(NGHolder &g, NFAVertex v, u8 pred_char) {
- if (in_degree(v, g) != 1) {
+void allowIllegal(NGHolder &g, NFAVertex v, u8 pred_char) {
+ if (in_degree(v, g) != 1) {
DEBUG_PRINTF("unexpected pred\n");
assert(0); /* should be true due to the early stage of this analysis */
return;
}
- CharReach &cr = g[v].char_reach;
+ CharReach &cr = g[v].char_reach;
if (pred_char == 0xe0) {
assert(cr.isSubsetOf(CharReach(0xa0, 0xbf)));
if (cr == CharReach(0xa0, 0xbf)) {
@@ -80,8 +80,8 @@ void allowIllegal(NGHolder &g, NFAVertex v, u8 pred_char) {
* above \\x{10ffff} or they represent overlong encodings. As we require valid
* UTF-8 input, we have no defined behaviour in these cases, as a result we can
* accept them if it simplifies the graph. */
-void relaxForbiddenUtf8(NGHolder &g, const ExpressionInfo &expr) {
- if (!expr.utf8) {
+void relaxForbiddenUtf8(NGHolder &g, const ExpressionInfo &expr) {
+ if (!expr.utf8) {
return;
}
@@ -89,12 +89,12 @@ void relaxForbiddenUtf8(NGHolder &g, const ExpressionInfo &expr) {
const CharReach f0(0xf0);
const CharReach f4(0xf4);
- for (auto v : vertices_range(g)) {
- const CharReach &cr = g[v].char_reach;
+ for (auto v : vertices_range(g)) {
+ const CharReach &cr = g[v].char_reach;
if (cr == e0 || cr == f0 || cr == f4) {
u8 pred_char = cr.find_first();
- for (auto t : adjacent_vertices_range(v, g)) {
- allowIllegal(g, t, pred_char);
+ for (auto t : adjacent_vertices_range(v, g)) {
+ allowIllegal(g, t, pred_char);
}
}
}
@@ -177,7 +177,7 @@ void findSeeds(const NGHolder &h, const bool som, vector<NFAVertex> *seeds) {
continue;
}
- DEBUG_PRINTF("%zu is a seed\n", h[v].index);
+ DEBUG_PRINTF("%zu is a seed\n", h[v].index);
seeds->push_back(v);
already_seeds.insert(v);
}
@@ -185,12 +185,12 @@ void findSeeds(const NGHolder &h, const bool som, vector<NFAVertex> *seeds) {
static
bool expandCyclic(NGHolder &h, NFAVertex v) {
- DEBUG_PRINTF("inspecting %zu\n", h[v].index);
+ DEBUG_PRINTF("inspecting %zu\n", h[v].index);
bool changes = false;
- auto v_preds = preds(v, h);
- auto v_succs = succs(v, h);
-
+ auto v_preds = preds(v, h);
+ auto v_succs = succs(v, h);
+
set<NFAVertex> start_siblings;
set<NFAVertex> end_siblings;
@@ -199,10 +199,10 @@ bool expandCyclic(NGHolder &h, NFAVertex v) {
/* We need to find start vertices which have all of our preds.
* As we have a self loop, it must be one of our succs. */
for (auto a : adjacent_vertices_range(v, h)) {
- auto a_preds = preds(a, h);
+ auto a_preds = preds(a, h);
if (a_preds == v_preds && isutf8start(h[a].char_reach)) {
- DEBUG_PRINTF("%zu is a start v\n", h[a].index);
+ DEBUG_PRINTF("%zu is a start v\n", h[a].index);
start_siblings.insert(a);
}
}
@@ -210,10 +210,10 @@ bool expandCyclic(NGHolder &h, NFAVertex v) {
/* We also need to find full cont vertices which have all our own succs;
* As we have a self loop, it must be one of our preds. */
for (auto a : inv_adjacent_vertices_range(v, h)) {
- auto a_succs = succs(a, h);
+ auto a_succs = succs(a, h);
if (a_succs == v_succs && h[a].char_reach == UTF_CONT_CR) {
- DEBUG_PRINTF("%zu is a full tail cont\n", h[a].index);
+ DEBUG_PRINTF("%zu is a full tail cont\n", h[a].index);
end_siblings.insert(a);
}
}
@@ -227,7 +227,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) {
if (cr.isSubsetOf(UTF_TWO_START_CR)) {
if (end_siblings.find(*adjacent_vertices(s, h).first)
== end_siblings.end()) {
- DEBUG_PRINTF("%zu is odd\n", h[s].index);
+ DEBUG_PRINTF("%zu is odd\n", h[s].index);
continue;
}
} else if (cr.isSubsetOf(UTF_THREE_START_CR)) {
@@ -239,7 +239,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) {
}
if (end_siblings.find(*adjacent_vertices(m, h).first)
== end_siblings.end()) {
- DEBUG_PRINTF("%zu is odd\n", h[s].index);
+ DEBUG_PRINTF("%zu is odd\n", h[s].index);
continue;
}
} else if (cr.isSubsetOf(UTF_FOUR_START_CR)) {
@@ -259,11 +259,11 @@ bool expandCyclic(NGHolder &h, NFAVertex v) {
if (end_siblings.find(*adjacent_vertices(m2, h).first)
== end_siblings.end()) {
- DEBUG_PRINTF("%zu is odd\n", h[s].index);
+ DEBUG_PRINTF("%zu is odd\n", h[s].index);
continue;
}
} else {
- DEBUG_PRINTF("%zu is bad\n", h[s].index);
+ DEBUG_PRINTF("%zu is bad\n", h[s].index);
continue;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_utf8.h b/contrib/libs/hyperscan/src/nfagraph/ng_utf8.h
index 1a9a8572f9d..7c4288336ff 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_utf8.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_utf8.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
namespace ue2 {
-class ExpressionInfo;
+class ExpressionInfo;
class NGHolder;
/** \brief Relax forbidden UTF-8 sequences.
@@ -44,7 +44,7 @@ class NGHolder;
* above \\x{10ffff} or they represent overlong encodings. As we require valid
* UTF-8 input, we have no defined behaviour in these cases, as a result we can
* accept them if it simplifies the graph. */
-void relaxForbiddenUtf8(NGHolder &g, const ExpressionInfo &expr);
+void relaxForbiddenUtf8(NGHolder &g, const ExpressionInfo &expr);
/** \brief Contract cycles of UTF-8 code points down to a single cyclic vertex
* where possible, based on the assumption that we will always be matching
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_util.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_util.cpp
index c3b9603b166..cb2b7103582 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_util.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_util.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,54 +33,54 @@
#include "grey.h"
#include "ng_dump.h"
-#include "ng_prune.h"
+#include "ng_prune.h"
#include "ue2common.h"
#include "nfa/limex_limits.h" // for NFA_MAX_TOP_MASKS.
#include "parser/position.h"
#include "util/graph_range.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include "util/make_unique.h"
#include "util/order_check.h"
#include "util/ue2string.h"
#include "util/report_manager.h"
-#include <limits>
+#include <limits>
#include <map>
#include <set>
-#include <unordered_map>
-#include <unordered_set>
-
+#include <unordered_map>
+#include <unordered_set>
+
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/range/adaptor/map.hpp>
using namespace std;
-using boost::make_filtered_graph;
+using boost::make_filtered_graph;
using boost::make_assoc_property_map;
namespace ue2 {
NFAVertex getSoleDestVertex(const NGHolder &g, NFAVertex a) {
- assert(a != NGHolder::null_vertex());
+ assert(a != NGHolder::null_vertex());
- NGHolder::out_edge_iterator ii, iie;
+ NGHolder::out_edge_iterator ii, iie;
tie(ii, iie) = out_edges(a, g);
if (ii == iie) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
NFAVertex b = target(*ii, g);
if (a == b) {
++ii;
if (ii == iie) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
b = target(*ii, g);
if (++ii != iie) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
} else if (++ii != iie && (target(*ii, g) != a || ++ii != iie)) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
assert(a != b);
@@ -88,23 +88,23 @@ NFAVertex getSoleDestVertex(const NGHolder &g, NFAVertex a) {
}
NFAVertex getSoleSourceVertex(const NGHolder &g, NFAVertex a) {
- assert(a != NGHolder::null_vertex());
+ assert(a != NGHolder::null_vertex());
u32 idegree = in_degree(a, g);
if (idegree != 1 && !(idegree == 2 && hasSelfLoop(a, g))) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
- NGHolder::in_edge_iterator ii, iie;
+ NGHolder::in_edge_iterator ii, iie;
tie(ii, iie) = in_edges(a, g);
if (ii == iie) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
NFAVertex b = source(*ii, g);
if (a == b) {
++ii;
if (ii == iie) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
b = source(*ii, g);
@@ -129,7 +129,7 @@ void clone_out_edges(NGHolder &g, NFAVertex source, NFAVertex dest) {
if (edge(dest, t, g).second) {
continue;
}
- NFAEdge clone = add_edge(dest, t, g);
+ NFAEdge clone = add_edge(dest, t, g);
u32 idx = g[clone].index;
g[clone] = g[e];
g[clone].index = idx;
@@ -140,7 +140,7 @@ void clone_in_edges(NGHolder &g, NFAVertex s, NFAVertex dest) {
for (const auto &e : in_edges_range(s, g)) {
NFAVertex ss = source(e, g);
assert(!edge(ss, dest, g).second);
- NFAEdge clone = add_edge(ss, dest, g);
+ NFAEdge clone = add_edge(ss, dest, g);
u32 idx = g[clone].index;
g[clone] = g[e];
g[clone].index = idx;
@@ -148,21 +148,21 @@ void clone_in_edges(NGHolder &g, NFAVertex s, NFAVertex dest) {
}
bool onlyOneTop(const NGHolder &g) {
- return getTops(g).size() == 1;
+ return getTops(g).size() == 1;
}
namespace {
struct CycleFound {};
struct DetectCycles : public boost::default_dfs_visitor {
explicit DetectCycles(const NGHolder &g) : startDs(g.startDs) {}
- void back_edge(const NFAEdge &e, const NGHolder &g) const {
+ void back_edge(const NFAEdge &e, const NGHolder &g) const {
NFAVertex u = source(e, g), v = target(e, g);
// We ignore the startDs self-loop.
if (u == startDs && v == startDs) {
return;
}
// Any other back-edge indicates a cycle.
- DEBUG_PRINTF("back edge %zu->%zu found\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("back edge %zu->%zu found\n", g[u].index, g[v].index);
throw CycleFound();
}
private:
@@ -186,19 +186,19 @@ bool isAnchored(const NGHolder &g) {
return true;
}
-bool isFloating(const NGHolder &g) {
- for (auto v : adjacent_vertices_range(g.start, g)) {
- if (v != g.startDs && !edge(g.startDs, v, g).second) {
- return false;
- }
- }
- return true;
-}
-
+bool isFloating(const NGHolder &g) {
+ for (auto v : adjacent_vertices_range(g.start, g)) {
+ if (v != g.startDs && !edge(g.startDs, v, g).second) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool isAcyclic(const NGHolder &g) {
try {
- boost::depth_first_search(g, DetectCycles(g), make_small_color_map(g),
- g.start);
+ boost::depth_first_search(g, DetectCycles(g), make_small_color_map(g),
+ g.start);
} catch (const CycleFound &) {
return false;
}
@@ -213,9 +213,9 @@ bool hasReachableCycle(const NGHolder &g, NFAVertex src) {
try {
// Use depth_first_visit, rather than depth_first_search, so that we
// only search from src.
- boost::depth_first_visit(g, src, DetectCycles(g),
- make_small_color_map(g));
- } catch (const CycleFound &) {
+ boost::depth_first_visit(g, src, DetectCycles(g),
+ make_small_color_map(g));
+ } catch (const CycleFound &) {
return true;
}
@@ -226,8 +226,8 @@ bool hasBigCycles(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
set<NFAEdge> dead;
BackEdges<set<NFAEdge>> backEdgeVisitor(dead);
- boost::depth_first_search(g, backEdgeVisitor, make_small_color_map(g),
- g.start);
+ boost::depth_first_search(g, backEdgeVisitor, make_small_color_map(g),
+ g.start);
for (const auto &e : dead) {
if (source(e, g) != target(e, g)) {
@@ -238,15 +238,15 @@ bool hasBigCycles(const NGHolder &g) {
return false;
}
-bool hasNarrowReachVertex(const NGHolder &g, size_t max_reach_count) {
- return any_of_in(vertices_range(g), [&](NFAVertex v) {
- return !is_special(v, g) && g[v].char_reach.count() < max_reach_count;
- });
+bool hasNarrowReachVertex(const NGHolder &g, size_t max_reach_count) {
+ return any_of_in(vertices_range(g), [&](NFAVertex v) {
+ return !is_special(v, g) && g[v].char_reach.count() < max_reach_count;
+ });
}
bool can_never_match(const NGHolder &g) {
assert(edge(g.accept, g.acceptEod, g).second);
- if (in_degree(g.accept, g) == 0 && in_degree(g.acceptEod, g) == 1) {
+ if (in_degree(g.accept, g) == 0 && in_degree(g.acceptEod, g) == 1) {
DEBUG_PRINTF("no paths into accept\n");
return true;
}
@@ -255,7 +255,7 @@ bool can_never_match(const NGHolder &g) {
}
bool can_match_at_eod(const NGHolder &h) {
- if (in_degree(h.acceptEod, h) > 1) {
+ if (in_degree(h.acceptEod, h) > 1) {
DEBUG_PRINTF("more than one edge to acceptEod\n");
return true;
}
@@ -272,90 +272,90 @@ bool can_match_at_eod(const NGHolder &h) {
}
bool can_only_match_at_eod(const NGHolder &g) {
- NGHolder::in_edge_iterator ie, ee;
+ NGHolder::in_edge_iterator ie, ee;
tie(ie, ee) = in_edges(g.accept, g);
return ie == ee;
}
bool matches_everywhere(const NGHolder &h) {
- NFAEdge e = edge(h.startDs, h.accept, h);
+ NFAEdge e = edge(h.startDs, h.accept, h);
- return e && !h[e].assert_flags;
+ return e && !h[e].assert_flags;
}
bool is_virtual_start(NFAVertex v, const NGHolder &g) {
return g[v].assert_flags & POS_FLAG_VIRTUAL_START;
}
-static
-void reorderSpecials(const NGHolder &g, vector<NFAVertex> &topoOrder) {
- // Start is last element of reverse topo ordering.
- auto it = find(topoOrder.begin(), topoOrder.end(), g.start);
- if (it != topoOrder.end() - 1) {
- DEBUG_PRINTF("repositioning start\n");
- assert(it != topoOrder.end());
- topoOrder.erase(it);
- topoOrder.insert(topoOrder.end(), g.start);
- }
-
- // StartDs is second-to-last element of reverse topo ordering.
- it = find(topoOrder.begin(), topoOrder.end(), g.startDs);
- if (it != topoOrder.end() - 2) {
- DEBUG_PRINTF("repositioning start ds\n");
- assert(it != topoOrder.end());
- topoOrder.erase(it);
- topoOrder.insert(topoOrder.end() - 1, g.startDs);
- }
-
- // AcceptEOD is first element of reverse topo ordering.
- it = find(topoOrder.begin(), topoOrder.end(), g.acceptEod);
- if (it != topoOrder.begin()) {
- DEBUG_PRINTF("repositioning accept\n");
- assert(it != topoOrder.end());
- topoOrder.erase(it);
- topoOrder.insert(topoOrder.begin(), g.acceptEod);
- }
-
- // Accept is second element of reverse topo ordering, if it's connected.
- it = find(topoOrder.begin(), topoOrder.end(), g.accept);
- if (it != topoOrder.begin() + 1) {
- DEBUG_PRINTF("repositioning accept\n");
- assert(it != topoOrder.end());
- topoOrder.erase(it);
- if (in_degree(g.accept, g) != 0) {
- topoOrder.insert(topoOrder.begin() + 1, g.accept);
- }
- }
-}
-
+static
+void reorderSpecials(const NGHolder &g, vector<NFAVertex> &topoOrder) {
+ // Start is last element of reverse topo ordering.
+ auto it = find(topoOrder.begin(), topoOrder.end(), g.start);
+ if (it != topoOrder.end() - 1) {
+ DEBUG_PRINTF("repositioning start\n");
+ assert(it != topoOrder.end());
+ topoOrder.erase(it);
+ topoOrder.insert(topoOrder.end(), g.start);
+ }
+
+ // StartDs is second-to-last element of reverse topo ordering.
+ it = find(topoOrder.begin(), topoOrder.end(), g.startDs);
+ if (it != topoOrder.end() - 2) {
+ DEBUG_PRINTF("repositioning start ds\n");
+ assert(it != topoOrder.end());
+ topoOrder.erase(it);
+ topoOrder.insert(topoOrder.end() - 1, g.startDs);
+ }
+
+ // AcceptEOD is first element of reverse topo ordering.
+ it = find(topoOrder.begin(), topoOrder.end(), g.acceptEod);
+ if (it != topoOrder.begin()) {
+ DEBUG_PRINTF("repositioning accept\n");
+ assert(it != topoOrder.end());
+ topoOrder.erase(it);
+ topoOrder.insert(topoOrder.begin(), g.acceptEod);
+ }
+
+ // Accept is second element of reverse topo ordering, if it's connected.
+ it = find(topoOrder.begin(), topoOrder.end(), g.accept);
+ if (it != topoOrder.begin() + 1) {
+ DEBUG_PRINTF("repositioning accept\n");
+ assert(it != topoOrder.end());
+ topoOrder.erase(it);
+ if (in_degree(g.accept, g) != 0) {
+ topoOrder.insert(topoOrder.begin() + 1, g.accept);
+ }
+ }
+}
+
vector<NFAVertex> getTopoOrdering(const NGHolder &g) {
assert(hasCorrectlyNumberedVertices(g));
// Use the same colour map for both DFS and topological_sort below: avoids
// having to reallocate it, etc.
- auto colors = make_small_color_map(g);
+ auto colors = make_small_color_map(g);
- using EdgeSet = unordered_set<NFAEdge>;
+ using EdgeSet = unordered_set<NFAEdge>;
EdgeSet backEdges;
BackEdges<EdgeSet> be(backEdges);
- depth_first_search(g, visitor(be).root_vertex(g.start).color_map(colors));
+ depth_first_search(g, visitor(be).root_vertex(g.start).color_map(colors));
- auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&backEdges));
+ auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&backEdges));
vector<NFAVertex> ordering;
- ordering.reserve(num_vertices(g));
- topological_sort(acyclic_g, back_inserter(ordering), color_map(colors));
+ ordering.reserve(num_vertices(g));
+ topological_sort(acyclic_g, back_inserter(ordering), color_map(colors));
+
+ reorderSpecials(g, ordering);
- reorderSpecials(g, ordering);
-
return ordering;
}
static
void mustBeSetBefore_int(NFAVertex u, const NGHolder &g,
- decltype(make_small_color_map(NGHolder())) &colors) {
+ decltype(make_small_color_map(NGHolder())) &colors) {
set<NFAVertex> s;
insert(&s, adjacent_vertices(u, g));
@@ -370,10 +370,10 @@ void mustBeSetBefore_int(NFAVertex u, const NGHolder &g,
}
}
- auto prefix = make_filtered_graph(g, make_bad_edge_filter(&dead));
+ auto prefix = make_filtered_graph(g, make_bad_edge_filter(&dead));
- depth_first_visit(prefix, g.start, make_dfs_visitor(boost::null_visitor()),
- colors);
+ depth_first_visit(prefix, g.start, make_dfs_visitor(boost::null_visitor()),
+ colors);
}
bool mustBeSetBefore(NFAVertex u, NFAVertex v, const NGHolder &g,
@@ -386,18 +386,18 @@ bool mustBeSetBefore(NFAVertex u, NFAVertex v, const NGHolder &g,
return cache.cache[key];
}
- auto colors = make_small_color_map(g);
- mustBeSetBefore_int(u, g, colors);
+ auto colors = make_small_color_map(g);
+ mustBeSetBefore_int(u, g, colors);
for (auto vi : vertices_range(g)) {
- auto key2 = make_pair(g[u].index, g[vi].index);
- DEBUG_PRINTF("adding %zu %zu\n", key2.first, key2.second);
+ auto key2 = make_pair(g[u].index, g[vi].index);
+ DEBUG_PRINTF("adding %zu %zu\n", key2.first, key2.second);
assert(!contains(cache.cache, key2));
- bool value = get(colors, vi) == small_color::white;
+ bool value = get(colors, vi) == small_color::white;
cache.cache[key2] = value;
assert(contains(cache.cache, key2));
}
- DEBUG_PRINTF("cache miss %zu %zu (%zu)\n", key.first, key.second,
+ DEBUG_PRINTF("cache miss %zu %zu (%zu)\n", key.first, key.second,
cache.cache.size());
return cache.cache[key];
}
@@ -430,27 +430,27 @@ void appendLiteral(NGHolder &h, const ue2_literal &s) {
}
}
-flat_set<u32> getTops(const NGHolder &h) {
- flat_set<u32> tops;
+flat_set<u32> getTops(const NGHolder &h) {
+ flat_set<u32> tops;
+ for (const auto &e : out_edges_range(h.start, h)) {
+ insert(&tops, h[e].tops);
+ }
+ return tops;
+}
+
+void setTops(NGHolder &h, u32 top) {
for (const auto &e : out_edges_range(h.start, h)) {
- insert(&tops, h[e].tops);
- }
- return tops;
-}
-
-void setTops(NGHolder &h, u32 top) {
- for (const auto &e : out_edges_range(h.start, h)) {
- assert(h[e].tops.empty());
- if (target(e, h) == h.startDs) {
+ assert(h[e].tops.empty());
+ if (target(e, h) == h.startDs) {
continue;
}
- h[e].tops.insert(top);
+ h[e].tops.insert(top);
}
}
void clearReports(NGHolder &g) {
DEBUG_PRINTF("clearing reports without an accept edge\n");
- unordered_set<NFAVertex> allow;
+ unordered_set<NFAVertex> allow;
insert(&allow, inv_adjacent_vertices(g.accept, g));
insert(&allow, inv_adjacent_vertices(g.acceptEod, g));
allow.erase(g.accept); // due to stylised edge.
@@ -474,7 +474,7 @@ void duplicateReport(NGHolder &g, ReportID r_old, ReportID r_new) {
static
void fillHolderOutEdges(NGHolder &out, const NGHolder &in,
- const unordered_map<NFAVertex, NFAVertex> &v_map,
+ const unordered_map<NFAVertex, NFAVertex> &v_map,
NFAVertex u) {
NFAVertex u_new = v_map.at(u);
@@ -496,9 +496,9 @@ void fillHolderOutEdges(NGHolder &out, const NGHolder &in,
}
void fillHolder(NGHolder *outp, const NGHolder &in, const deque<NFAVertex> &vv,
- unordered_map<NFAVertex, NFAVertex> *v_map_out) {
+ unordered_map<NFAVertex, NFAVertex> *v_map_out) {
NGHolder &out = *outp;
- unordered_map<NFAVertex, NFAVertex> &v_map = *v_map_out;
+ unordered_map<NFAVertex, NFAVertex> &v_map = *v_map_out;
out.kind = in.kind;
@@ -525,13 +525,13 @@ void fillHolder(NGHolder *outp, const NGHolder &in, const deque<NFAVertex> &vv,
fillHolderOutEdges(out, in, v_map, u);
}
- renumber_edges(out);
- renumber_vertices(out);
+ renumber_edges(out);
+ renumber_vertices(out);
}
void cloneHolder(NGHolder &out, const NGHolder &in) {
assert(hasCorrectlyNumberedVertices(in));
- assert(hasCorrectlyNumberedVertices(out));
+ assert(hasCorrectlyNumberedVertices(out));
out.kind = in.kind;
// Note: depending on the state of the input graph, some stylized edges
@@ -541,7 +541,7 @@ void cloneHolder(NGHolder &out, const NGHolder &in) {
/* remove the existing special edges */
clear_vertex(out.startDs, out);
clear_vertex(out.accept, out);
- renumber_edges(out);
+ renumber_edges(out);
vector<NFAVertex> out_mapping(num_vertices(in));
out_mapping[NODE_START] = out.start;
@@ -569,18 +569,18 @@ void cloneHolder(NGHolder &out, const NGHolder &in) {
NFAVertex s = out_mapping[si];
NFAVertex t = out_mapping[ti];
- NFAEdge e2 = add_edge(s, t, out);
+ NFAEdge e2 = add_edge(s, t, out);
out[e2] = in[e];
}
// Safety checks.
- assert(num_vertices(in) == num_vertices(out));
- assert(num_edges(in) == num_edges(out));
+ assert(num_vertices(in) == num_vertices(out));
+ assert(num_edges(in) == num_edges(out));
assert(hasCorrectlyNumberedVertices(out));
}
void cloneHolder(NGHolder &out, const NGHolder &in,
- unordered_map<NFAVertex, NFAVertex> *mapping) {
+ unordered_map<NFAVertex, NFAVertex> *mapping) {
cloneHolder(out, in);
vector<NFAVertex> out_verts(num_vertices(in));
for (auto v : vertices_range(out)) {
@@ -601,191 +601,191 @@ unique_ptr<NGHolder> cloneHolder(const NGHolder &in) {
return h;
}
-void reverseHolder(const NGHolder &g_in, NGHolder &g) {
- // Make the BGL do the grunt work.
- unordered_map<NFAVertex, NFAVertex> vertexMap;
- boost::transpose_graph(g_in, g,
- orig_to_copy(boost::make_assoc_property_map(vertexMap)));
-
- // The transpose_graph operation will have created extra copies of our
- // specials. We have to rewire their neighbours to the 'real' specials and
- // delete them.
- NFAVertex start = vertexMap[g_in.acceptEod];
- NFAVertex startDs = vertexMap[g_in.accept];
- NFAVertex accept = vertexMap[g_in.startDs];
- NFAVertex acceptEod = vertexMap[g_in.start];
-
- // Successors of starts.
- for (const auto &e : out_edges_range(start, g)) {
- NFAVertex v = target(e, g);
- add_edge(g.start, v, g[e], g);
- }
- for (const auto &e : out_edges_range(startDs, g)) {
- NFAVertex v = target(e, g);
- add_edge(g.startDs, v, g[e], g);
- }
-
- // Predecessors of accepts.
- for (const auto &e : in_edges_range(accept, g)) {
- NFAVertex u = source(e, g);
- add_edge(u, g.accept, g[e], g);
- }
- for (const auto &e : in_edges_range(acceptEod, g)) {
- NFAVertex u = source(e, g);
- add_edge(u, g.acceptEod, g[e], g);
- }
-
- // Remove our impostors.
- clear_vertex(start, g);
- remove_vertex(start, g);
- clear_vertex(startDs, g);
- remove_vertex(startDs, g);
- clear_vertex(accept, g);
- remove_vertex(accept, g);
- clear_vertex(acceptEod, g);
- remove_vertex(acceptEod, g);
-
- // Renumber so that g's properties (number of vertices, edges) are
- // accurate.
- renumber_vertices(g);
- renumber_edges(g);
-
- assert(num_vertices(g) == num_vertices(g_in));
- assert(num_edges(g) == num_edges(g_in));
-}
-
-u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
- u32 max_delay, bool overhang_ok) {
- assert(isCorrectlyTopped(g));
- if (max_delay == numeric_limits<u32>::max()) {
- max_delay--;
- }
-
- DEBUG_PRINTF("killing off '%s'\n", dumpString(lit).c_str());
- set<NFAVertex> curr, next;
- curr.insert(g.accept);
-
- auto it = lit.rbegin();
- for (u32 delay = max_delay; delay > 0 && it != lit.rend(); delay--, ++it) {
- next.clear();
- for (auto v : curr) {
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (u == g.start) {
- if (overhang_ok) {
- DEBUG_PRINTF("bail\n");
- goto bail; /* things got complicated */
- } else {
- continue; /* it is not possible for a lhs literal to
- * overhang the start */
- }
- }
-
- const CharReach &cr = g[u].char_reach;
- if (!overlaps(*it, cr)) {
- DEBUG_PRINTF("skip\n");
- continue;
- }
- if (isSubsetOf(*it, cr)) {
- next.insert(u);
- } else {
- DEBUG_PRINTF("bail\n");
- goto bail; /* things got complicated */
- }
- }
- }
-
- curr.swap(next);
- }
- bail:
- if (curr.empty()) {
- /* This can happen when we have an edge representing a cross from two
- * sides of an alternation. This whole edge needs to be marked as
- * dead */
- assert(0); /* should have been picked up by can match */
- return numeric_limits<u32>::max();
- }
-
- u32 delay = distance(lit.rbegin(), it);
- assert(delay <= max_delay);
- assert(delay <= lit.length());
- DEBUG_PRINTF("managed delay %u (of max %u)\n", delay, max_delay);
-
- set<NFAVertex> pred;
- for (auto v : curr) {
- insert(&pred, inv_adjacent_vertices_range(v, g));
- }
-
- clear_in_edges(g.accept, g);
- clearReports(g);
-
- for (auto v : pred) {
- NFAEdge e = add_edge(v, g.accept, g);
- g[v].reports.insert(0);
- if (is_triggered(g) && v == g.start) {
- g[e].tops.insert(DEFAULT_TOP);
- }
- }
-
- pruneUseless(g);
- assert(allMatchStatesHaveReports(g));
- assert(isCorrectlyTopped(g));
-
- DEBUG_PRINTF("graph has %zu vertices left\n", num_vertices(g));
- return delay;
-}
-
+void reverseHolder(const NGHolder &g_in, NGHolder &g) {
+ // Make the BGL do the grunt work.
+ unordered_map<NFAVertex, NFAVertex> vertexMap;
+ boost::transpose_graph(g_in, g,
+ orig_to_copy(boost::make_assoc_property_map(vertexMap)));
+
+ // The transpose_graph operation will have created extra copies of our
+ // specials. We have to rewire their neighbours to the 'real' specials and
+ // delete them.
+ NFAVertex start = vertexMap[g_in.acceptEod];
+ NFAVertex startDs = vertexMap[g_in.accept];
+ NFAVertex accept = vertexMap[g_in.startDs];
+ NFAVertex acceptEod = vertexMap[g_in.start];
+
+ // Successors of starts.
+ for (const auto &e : out_edges_range(start, g)) {
+ NFAVertex v = target(e, g);
+ add_edge(g.start, v, g[e], g);
+ }
+ for (const auto &e : out_edges_range(startDs, g)) {
+ NFAVertex v = target(e, g);
+ add_edge(g.startDs, v, g[e], g);
+ }
+
+ // Predecessors of accepts.
+ for (const auto &e : in_edges_range(accept, g)) {
+ NFAVertex u = source(e, g);
+ add_edge(u, g.accept, g[e], g);
+ }
+ for (const auto &e : in_edges_range(acceptEod, g)) {
+ NFAVertex u = source(e, g);
+ add_edge(u, g.acceptEod, g[e], g);
+ }
+
+ // Remove our impostors.
+ clear_vertex(start, g);
+ remove_vertex(start, g);
+ clear_vertex(startDs, g);
+ remove_vertex(startDs, g);
+ clear_vertex(accept, g);
+ remove_vertex(accept, g);
+ clear_vertex(acceptEod, g);
+ remove_vertex(acceptEod, g);
+
+ // Renumber so that g's properties (number of vertices, edges) are
+ // accurate.
+ renumber_vertices(g);
+ renumber_edges(g);
+
+ assert(num_vertices(g) == num_vertices(g_in));
+ assert(num_edges(g) == num_edges(g_in));
+}
+
+u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
+ u32 max_delay, bool overhang_ok) {
+ assert(isCorrectlyTopped(g));
+ if (max_delay == numeric_limits<u32>::max()) {
+ max_delay--;
+ }
+
+ DEBUG_PRINTF("killing off '%s'\n", dumpString(lit).c_str());
+ set<NFAVertex> curr, next;
+ curr.insert(g.accept);
+
+ auto it = lit.rbegin();
+ for (u32 delay = max_delay; delay > 0 && it != lit.rend(); delay--, ++it) {
+ next.clear();
+ for (auto v : curr) {
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (u == g.start) {
+ if (overhang_ok) {
+ DEBUG_PRINTF("bail\n");
+ goto bail; /* things got complicated */
+ } else {
+ continue; /* it is not possible for a lhs literal to
+ * overhang the start */
+ }
+ }
+
+ const CharReach &cr = g[u].char_reach;
+ if (!overlaps(*it, cr)) {
+ DEBUG_PRINTF("skip\n");
+ continue;
+ }
+ if (isSubsetOf(*it, cr)) {
+ next.insert(u);
+ } else {
+ DEBUG_PRINTF("bail\n");
+ goto bail; /* things got complicated */
+ }
+ }
+ }
+
+ curr.swap(next);
+ }
+ bail:
+ if (curr.empty()) {
+ /* This can happen when we have an edge representing a cross from two
+ * sides of an alternation. This whole edge needs to be marked as
+ * dead */
+ assert(0); /* should have been picked up by can match */
+ return numeric_limits<u32>::max();
+ }
+
+ u32 delay = distance(lit.rbegin(), it);
+ assert(delay <= max_delay);
+ assert(delay <= lit.length());
+ DEBUG_PRINTF("managed delay %u (of max %u)\n", delay, max_delay);
+
+ set<NFAVertex> pred;
+ for (auto v : curr) {
+ insert(&pred, inv_adjacent_vertices_range(v, g));
+ }
+
+ clear_in_edges(g.accept, g);
+ clearReports(g);
+
+ for (auto v : pred) {
+ NFAEdge e = add_edge(v, g.accept, g);
+ g[v].reports.insert(0);
+ if (is_triggered(g) && v == g.start) {
+ g[e].tops.insert(DEFAULT_TOP);
+ }
+ }
+
+ pruneUseless(g);
+ assert(allMatchStatesHaveReports(g));
+ assert(isCorrectlyTopped(g));
+
+ DEBUG_PRINTF("graph has %zu vertices left\n", num_vertices(g));
+ return delay;
+}
+
#ifndef NDEBUG
-
+
bool allMatchStatesHaveReports(const NGHolder &g) {
- unordered_set<NFAVertex> reporters;
+ unordered_set<NFAVertex> reporters;
for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
if (g[v].reports.empty()) {
- DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index);
return false;
}
- reporters.insert(v);
+ reporters.insert(v);
}
-
+
for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
if (v == g.accept) {
continue; // stylised edge
}
if (g[v].reports.empty()) {
- DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index);
return false;
}
- reporters.insert(v);
+ reporters.insert(v);
}
for (auto v : vertices_range(g)) {
- if (!contains(reporters, v) && !g[v].reports.empty()) {
- DEBUG_PRINTF("vertex %zu is not a match state, but has reports!\n",
- g[v].index);
- return false;
+ if (!contains(reporters, v) && !g[v].reports.empty()) {
+ DEBUG_PRINTF("vertex %zu is not a match state, but has reports!\n",
+ g[v].index);
+ return false;
}
}
-
- return true;
+
+ return true;
}
-bool isCorrectlyTopped(const NGHolder &g) {
- if (is_triggered(g)) {
- for (const auto &e : out_edges_range(g.start, g)) {
- if (g[e].tops.empty() != (target(e, g) == g.startDs)) {
- return false;
- }
+bool isCorrectlyTopped(const NGHolder &g) {
+ if (is_triggered(g)) {
+ for (const auto &e : out_edges_range(g.start, g)) {
+ if (g[e].tops.empty() != (target(e, g) == g.startDs)) {
+ return false;
+ }
+ }
+ } else {
+ for (const auto &e : out_edges_range(g.start, g)) {
+ if (!g[e].tops.empty()) {
+ return false;
+ }
}
- } else {
- for (const auto &e : out_edges_range(g.start, g)) {
- if (!g[e].tops.empty()) {
- return false;
- }
- }
}
-
- return true;
+
+ return true;
}
-
+
#endif // NDEBUG
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_util.h b/contrib/libs/hyperscan/src/nfagraph/ng_util.h
index cbd5760df46..a2d0d9b7d66 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_util.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,47 +32,47 @@
#ifndef NG_UTIL_H
#define NG_UTIL_H
-#include "ng_depth.h"
+#include "ng_depth.h"
#include "ng_holder.h"
#include "ue2common.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/graph_range.h"
-#include <boost/graph/depth_first_search.hpp> // for default_dfs_visitor
-
-#include <algorithm>
-#include <map>
-#include <unordered_map>
-#include <vector>
-
+#include <boost/graph/depth_first_search.hpp> // for default_dfs_visitor
+
+#include <algorithm>
+#include <map>
+#include <unordered_map>
+#include <vector>
+
namespace ue2 {
struct Grey;
struct ue2_literal;
class ReportManager;
-template<class VertexDepth>
-depth maxDistFromInit(const VertexDepth &vd) {
- if (vd.fromStart.max.is_unreachable()) {
- return vd.fromStartDotStar.max;
- } else if (vd.fromStartDotStar.max.is_unreachable()) {
- return vd.fromStart.max;
- } else {
- return std::max(vd.fromStartDotStar.max, vd.fromStart.max);
- }
-}
-
-template<class VertexDepth>
-depth maxDistFromStartOfData(const VertexDepth &vd) {
- if (vd.fromStartDotStar.max.is_reachable()) {
- /* the irrepressible nature of floating literals cannot be contained */
- return depth::infinity();
- } else {
- return vd.fromStart.max;
- }
-}
-
+template<class VertexDepth>
+depth maxDistFromInit(const VertexDepth &vd) {
+ if (vd.fromStart.max.is_unreachable()) {
+ return vd.fromStartDotStar.max;
+ } else if (vd.fromStartDotStar.max.is_unreachable()) {
+ return vd.fromStart.max;
+ } else {
+ return std::max(vd.fromStartDotStar.max, vd.fromStart.max);
+ }
+}
+
+template<class VertexDepth>
+depth maxDistFromStartOfData(const VertexDepth &vd) {
+ if (vd.fromStartDotStar.max.is_reachable()) {
+ /* the irrepressible nature of floating literals cannot be contained */
+ return depth::infinity();
+ } else {
+ return vd.fromStart.max;
+ }
+}
+
/** True if the given vertex is a dot (reachable on any character). */
template<class GraphT>
static really_inline
@@ -84,81 +84,81 @@ bool is_dot(NFAVertex v, const GraphT &g) {
template<class U>
static really_inline
void succ(const NGHolder &g, NFAVertex v, U *s) {
- auto rv = adjacent_vertices(v, g);
- s->insert(rv.first, rv.second);
+ auto rv = adjacent_vertices(v, g);
+ s->insert(rv.first, rv.second);
+}
+
+template<class ContTemp = flat_set<NFAVertex>>
+ContTemp succs(NFAVertex u, const NGHolder &g) {
+ ContTemp rv;
+ succ(g, u, &rv);
+ return rv;
}
-template<class ContTemp = flat_set<NFAVertex>>
-ContTemp succs(NFAVertex u, const NGHolder &g) {
- ContTemp rv;
- succ(g, u, &rv);
- return rv;
-}
-
/** adds predecessors of v to s */
template<class U>
static really_inline
void pred(const NGHolder &g, NFAVertex v, U *p) {
- auto rv = inv_adjacent_vertices(v, g);
- p->insert(rv.first, rv.second);
+ auto rv = inv_adjacent_vertices(v, g);
+ p->insert(rv.first, rv.second);
+}
+
+template<class ContTemp = flat_set<NFAVertex>>
+ContTemp preds(NFAVertex u, const NGHolder &g) {
+ ContTemp rv;
+ pred(g, u, &rv);
+ return rv;
}
-template<class ContTemp = flat_set<NFAVertex>>
-ContTemp preds(NFAVertex u, const NGHolder &g) {
- ContTemp rv;
- pred(g, u, &rv);
- return rv;
-}
-
/** returns a vertex with an out edge from v and is not v.
* v must have exactly one out-edge excluding self-loops.
- * will return NGHolder::null_vertex() if the preconditions don't hold.
+ * will return NGHolder::null_vertex() if the preconditions don't hold.
*/
NFAVertex getSoleDestVertex(const NGHolder &g, NFAVertex v);
/** Like getSoleDestVertex but for in-edges */
NFAVertex getSoleSourceVertex(const NGHolder &g, NFAVertex v);
-/** \brief edge filtered graph.
- *
- * This will give you a view over the graph that has none of the edges from
- * the provided set included.
- *
- * If this is provided with the back edges of the graph, this will result in an
- * acyclic subgraph view. This is useful for topological_sort and other
- * algorithms that require a DAG.
- */
-template<typename EdgeSet>
-struct bad_edge_filter {
- bad_edge_filter() {}
- explicit bad_edge_filter(const EdgeSet *bad_e) : bad_edges(bad_e) {}
- bool operator()(const typename EdgeSet::value_type &e) const {
- return !contains(*bad_edges, e); /* keep edges not in the bad set */
- }
- const EdgeSet *bad_edges = nullptr;
-};
-
-template<typename EdgeSet>
-bad_edge_filter<EdgeSet> make_bad_edge_filter(const EdgeSet *e) {
- return bad_edge_filter<EdgeSet>(e);
-}
-
-/** \brief vertex graph filter. */
-template<typename VertexSet>
-struct bad_vertex_filter {
- bad_vertex_filter() = default;
- explicit bad_vertex_filter(const VertexSet *bad_v) : bad_vertices(bad_v) {}
- bool operator()(const typename VertexSet::value_type &v) const {
- return !contains(*bad_vertices, v); /* keep vertices not in bad set */
- }
- const VertexSet *bad_vertices = nullptr;
-};
-
-template<typename VertexSet>
-bad_vertex_filter<VertexSet> make_bad_vertex_filter(const VertexSet *v) {
- return bad_vertex_filter<VertexSet>(v);
-}
-
+/** \brief edge filtered graph.
+ *
+ * This will give you a view over the graph that has none of the edges from
+ * the provided set included.
+ *
+ * If this is provided with the back edges of the graph, this will result in an
+ * acyclic subgraph view. This is useful for topological_sort and other
+ * algorithms that require a DAG.
+ */
+template<typename EdgeSet>
+struct bad_edge_filter {
+ bad_edge_filter() {}
+ explicit bad_edge_filter(const EdgeSet *bad_e) : bad_edges(bad_e) {}
+ bool operator()(const typename EdgeSet::value_type &e) const {
+ return !contains(*bad_edges, e); /* keep edges not in the bad set */
+ }
+ const EdgeSet *bad_edges = nullptr;
+};
+
+template<typename EdgeSet>
+bad_edge_filter<EdgeSet> make_bad_edge_filter(const EdgeSet *e) {
+ return bad_edge_filter<EdgeSet>(e);
+}
+
+/** \brief vertex graph filter. */
+template<typename VertexSet>
+struct bad_vertex_filter {
+ bad_vertex_filter() = default;
+ explicit bad_vertex_filter(const VertexSet *bad_v) : bad_vertices(bad_v) {}
+ bool operator()(const typename VertexSet::value_type &v) const {
+ return !contains(*bad_vertices, v); /* keep vertices not in bad set */
+ }
+ const VertexSet *bad_vertices = nullptr;
+};
+
+template<typename VertexSet>
+bad_vertex_filter<VertexSet> make_bad_vertex_filter(const VertexSet *v) {
+ return bad_vertex_filter<VertexSet>(v);
+}
+
/** Visitor that records back edges */
template <typename BackEdgeSet>
class BackEdges : public boost::default_dfs_visitor {
@@ -175,7 +175,7 @@ public:
* NODE_START_DOTSTAR). */
template <typename GraphT>
static really_inline
-bool is_any_start(typename GraphT::vertex_descriptor v, const GraphT &g) {
+bool is_any_start(typename GraphT::vertex_descriptor v, const GraphT &g) {
u32 i = g[v].index;
return i == NODE_START || i == NODE_START_DOTSTAR;
}
@@ -183,34 +183,34 @@ bool is_any_start(typename GraphT::vertex_descriptor v, const GraphT &g) {
bool is_virtual_start(NFAVertex v, const NGHolder &g);
template <typename GraphT>
-bool is_any_accept(typename GraphT::vertex_descriptor v, const GraphT &g) {
+bool is_any_accept(typename GraphT::vertex_descriptor v, const GraphT &g) {
u32 i = g[v].index;
return i == NODE_ACCEPT || i == NODE_ACCEPT_EOD;
}
/** returns true iff v has an edge to accept or acceptEod */
template <typename GraphT>
-bool is_match_vertex(typename GraphT::vertex_descriptor v, const GraphT &g) {
+bool is_match_vertex(typename GraphT::vertex_descriptor v, const GraphT &g) {
return edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second;
}
/** Generate a reverse topological ordering for a back-edge filtered version of
- * our graph (as it must be a DAG and correctly numbered).
- *
- * Note: we ensure that we produce a topo ordering that begins with acceptEod
- * and accept (if present) and ends with startDs followed by start.
- */
+ * our graph (as it must be a DAG and correctly numbered).
+ *
+ * Note: we ensure that we produce a topo ordering that begins with acceptEod
+ * and accept (if present) and ends with startDs followed by start.
+ */
std::vector<NFAVertex> getTopoOrdering(const NGHolder &g);
bool onlyOneTop(const NGHolder &g);
-/** Return the set of the tops on the given graph. */
+/** Return the set of the tops on the given graph. */
flat_set<u32> getTops(const NGHolder &h);
-/** Initialise the tops on h to the provide top. Assumes that h is triggered and
- * no tops have been set on h. */
-void setTops(NGHolder &h, u32 top = DEFAULT_TOP);
-
+/** Initialise the tops on h to the provide top. Assumes that h is triggered and
+ * no tops have been set on h. */
+void setTops(NGHolder &h, u32 top = DEFAULT_TOP);
+
/** adds a vertex to g with all the same vertex properties as \p v (aside from
* index) */
NFAVertex clone_vertex(NGHolder &g, NFAVertex v);
@@ -238,10 +238,10 @@ bool isVacuous(const NGHolder &h);
* proper successors). */
bool isAnchored(const NGHolder &h);
-/** \brief True if the graph contains no anchored vertices (start has no
- * successors aside from startDs or vertices connected to startDs). */
-bool isFloating(const NGHolder &h);
-
+/** \brief True if the graph contains no anchored vertices (start has no
+ * successors aside from startDs or vertices connected to startDs). */
+bool isFloating(const NGHolder &h);
+
/** True if the graph contains no back-edges at all, other than the
* startDs self-loop. */
bool isAcyclic(const NGHolder &g);
@@ -252,12 +252,12 @@ bool hasReachableCycle(const NGHolder &g, NFAVertex src);
/** True if g has any cycles which are not self-loops. */
bool hasBigCycles(const NGHolder &g);
-/**
- * \brief True if g has at least one non-special vertex with reach smaller than
- * max_reach_count. The default of 200 is pretty conservative.
- */
-bool hasNarrowReachVertex(const NGHolder &g, size_t max_reach_count = 200);
-
+/**
+ * \brief True if g has at least one non-special vertex with reach smaller than
+ * max_reach_count. The default of 200 is pretty conservative.
+ */
+bool hasNarrowReachVertex(const NGHolder &g, size_t max_reach_count = 200);
+
/** Returns the set of all vertices that appear in any of the graph's cycles. */
std::set<NFAVertex> findVerticesInCycles(const NGHolder &g);
@@ -291,12 +291,12 @@ void appendLiteral(NGHolder &h, const ue2_literal &s);
* \a in). A vertex mapping is returned in \a v_map_out. */
void fillHolder(NGHolder *outp, const NGHolder &in,
const std::deque<NFAVertex> &vv,
- std::unordered_map<NFAVertex, NFAVertex> *v_map_out);
+ std::unordered_map<NFAVertex, NFAVertex> *v_map_out);
/** \brief Clone the graph in \a in into graph \a out, returning a vertex
* mapping in \a v_map_out. */
void cloneHolder(NGHolder &out, const NGHolder &in,
- std::unordered_map<NFAVertex, NFAVertex> *v_map_out);
+ std::unordered_map<NFAVertex, NFAVertex> *v_map_out);
/** \brief Clone the graph in \a in into graph \a out. */
void cloneHolder(NGHolder &out, const NGHolder &in);
@@ -312,33 +312,33 @@ void clearReports(NGHolder &g);
* r_old. */
void duplicateReport(NGHolder &g, ReportID r_old, ReportID r_new);
-/** Construct a reversed copy of an arbitrary NGHolder, mapping starts to
- * accepts. */
-void reverseHolder(const NGHolder &g, NGHolder &out);
-
-/** \brief Returns the delay or ~0U if the graph cannot match with
- * the trailing literal. */
-u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
- u32 max_delay, bool overhang_ok = true);
-
+/** Construct a reversed copy of an arbitrary NGHolder, mapping starts to
+ * accepts. */
+void reverseHolder(const NGHolder &g, NGHolder &out);
+
+/** \brief Returns the delay or ~0U if the graph cannot match with
+ * the trailing literal. */
+u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
+ u32 max_delay, bool overhang_ok = true);
+
#ifndef NDEBUG
-// Assertions: only available in internal builds.
-
-/**
- * Used in sanity-checking assertions: returns true if all vertices
- * with edges to accept or acceptEod have at least one report ID. Additionally,
- * checks that ONLY vertices with edges to accept or acceptEod has reports.
- */
+// Assertions: only available in internal builds.
+
+/**
+ * Used in sanity-checking assertions: returns true if all vertices
+ * with edges to accept or acceptEod have at least one report ID. Additionally,
+ * checks that ONLY vertices with edges to accept or acceptEod has reports.
+ */
bool allMatchStatesHaveReports(const NGHolder &g);
-/**
- * Assertion: returns true if the graph is triggered and all edges out of start
- * have tops OR if the graph is not-triggered and all edges out of start have no
- * tops.
- */
-bool isCorrectlyTopped(const NGHolder &g);
-#endif // NDEBUG
+/**
+ * Assertion: returns true if the graph is triggered and all edges out of start
+ * have tops OR if the graph is not-triggered and all edges out of start have no
+ * tops.
+ */
+bool isCorrectlyTopped(const NGHolder &g);
+#endif // NDEBUG
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.cpp
index 05525ec06de..d1123dff49a 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,31 +34,31 @@
#include "grey.h"
#include "ng.h"
#include "ng_util.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
using namespace std;
namespace ue2 {
static
-ReportID getInternalId(ReportManager &rm, const ExpressionInfo &expr) {
- Report ir = rm.getBasicInternalReport(expr);
+ReportID getInternalId(ReportManager &rm, const ExpressionInfo &expr) {
+ Report ir = rm.getBasicInternalReport(expr);
// Apply any extended params.
- if (expr.min_offset || expr.max_offset != MAX_OFFSET) {
- ir.minOffset = expr.min_offset;
- ir.maxOffset = expr.max_offset;
+ if (expr.min_offset || expr.max_offset != MAX_OFFSET) {
+ ir.minOffset = expr.min_offset;
+ ir.maxOffset = expr.max_offset;
}
- assert(!expr.min_length); // should be handled elsewhere.
+ assert(!expr.min_length); // should be handled elsewhere.
return rm.getInternalId(ir);
}
static
-void makeFirehose(BoundaryReports &boundary, ReportManager &rm, NGHolder &g,
- const ExpressionInfo &expr) {
- const ReportID r = getInternalId(rm, expr);
+void makeFirehose(BoundaryReports &boundary, ReportManager &rm, NGHolder &g,
+ const ExpressionInfo &expr) {
+ const ReportID r = getInternalId(rm, expr);
boundary.report_at_0_eod.insert(r);
boundary.report_at_0.insert(r);
@@ -83,8 +83,8 @@ void makeFirehose(BoundaryReports &boundary, ReportManager &rm, NGHolder &g,
static
void makeAnchoredAcceptor(BoundaryReports &boundary, ReportManager &rm,
- NGHolder &g, const ExpressionInfo &expr) {
- boundary.report_at_0.insert(getInternalId(rm, expr));
+ NGHolder &g, const ExpressionInfo &expr) {
+ boundary.report_at_0.insert(getInternalId(rm, expr));
remove_edge(g.start, g.accept, g);
remove_edge(g.start, g.acceptEod, g);
g[g.start].reports.clear();
@@ -92,8 +92,8 @@ void makeAnchoredAcceptor(BoundaryReports &boundary, ReportManager &rm,
static
void makeEndAnchoredAcceptor(BoundaryReports &boundary, ReportManager &rm,
- NGHolder &g, const ExpressionInfo &expr) {
- boundary.report_at_eod.insert(getInternalId(rm, expr));
+ NGHolder &g, const ExpressionInfo &expr) {
+ boundary.report_at_eod.insert(getInternalId(rm, expr));
remove_edge(g.startDs, g.acceptEod, g);
remove_edge(g.start, g.acceptEod, g);
g[g.start].reports.clear();
@@ -102,18 +102,18 @@ void makeEndAnchoredAcceptor(BoundaryReports &boundary, ReportManager &rm,
static
void makeNothingAcceptor(BoundaryReports &boundary, ReportManager &rm,
- NGHolder &g, const ExpressionInfo &expr) {
- boundary.report_at_0_eod.insert(getInternalId(rm, expr));
+ NGHolder &g, const ExpressionInfo &expr) {
+ boundary.report_at_0_eod.insert(getInternalId(rm, expr));
remove_edge(g.start, g.acceptEod, g);
g[g.start].reports.clear();
}
bool splitOffVacuous(BoundaryReports &boundary, ReportManager &rm,
- NGHolder &g, const ExpressionInfo &expr) {
+ NGHolder &g, const ExpressionInfo &expr) {
if (edge(g.startDs, g.accept, g).second) {
// e.g. '.*'; match "between" every byte
DEBUG_PRINTF("graph is firehose\n");
- makeFirehose(boundary, rm, g, expr);
+ makeFirehose(boundary, rm, g, expr);
return true;
}
@@ -121,19 +121,19 @@ bool splitOffVacuous(BoundaryReports &boundary, ReportManager &rm,
if (edge(g.start, g.accept, g).second) {
DEBUG_PRINTF("creating anchored acceptor\n");
- makeAnchoredAcceptor(boundary, rm, g, expr);
+ makeAnchoredAcceptor(boundary, rm, g, expr);
work_done = true;
}
if (edge(g.startDs, g.acceptEod, g).second) {
DEBUG_PRINTF("creating end-anchored acceptor\n");
- makeEndAnchoredAcceptor(boundary, rm, g, expr);
+ makeEndAnchoredAcceptor(boundary, rm, g, expr);
work_done = true;
}
if (edge(g.start, g.acceptEod, g).second) {
DEBUG_PRINTF("creating nothing acceptor\n");
- makeNothingAcceptor(boundary, rm, g, expr);
+ makeNothingAcceptor(boundary, rm, g, expr);
work_done = true;
}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.h b/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.h
index 50590c0ded5..c33cb312de7 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_vacuous.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,13 +36,13 @@
namespace ue2 {
struct BoundaryReports;
-class ExpressionInfo;
-class NGHolder;
+class ExpressionInfo;
+class NGHolder;
class ReportManager;
// Returns true if a "vacuous" reporter was created.
bool splitOffVacuous(BoundaryReports &boundary, ReportManager &rm,
- NGHolder &g, const ExpressionInfo &expr);
+ NGHolder &g, const ExpressionInfo &expr);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_violet.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_violet.cpp
index 4eb4196da14..685d452150e 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_violet.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_violet.cpp
@@ -1,3068 +1,3068 @@
-/*
+/*
* Copyright (c) 2016-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "config.h"
-
-#include "ng_violet.h"
-
-#include "grey.h"
-#include "ng_depth.h"
-#include "ng_dominators.h"
-#include "ng_dump.h"
-#include "ng_equivalence.h"
-#include "ng_holder.h"
-#include "ng_is_equal.h"
-#include "ng_literal_analysis.h"
-#include "ng_limex.h"
-#include "ng_mcclellan.h"
-#include "ng_netflow.h"
-#include "ng_prune.h"
-#include "ng_redundancy.h"
-#include "ng_region.h"
-#include "ng_reports.h"
-#include "ng_split.h"
-#include "ng_util.h"
-#include "ng_width.h"
-#include "nfa/rdfa.h"
-#include "rose/rose_build.h"
-#include "rose/rose_build_util.h"
-#include "rose/rose_in_dump.h"
-#include "rose/rose_in_graph.h"
-#include "rose/rose_in_util.h"
-#include "util/compare.h"
-#include "util/compile_context.h"
-#include "util/container.h"
-#include "util/flat_containers.h"
-#include "util/graph.h"
-#include "util/graph_range.h"
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "config.h"
+
+#include "ng_violet.h"
+
+#include "grey.h"
+#include "ng_depth.h"
+#include "ng_dominators.h"
+#include "ng_dump.h"
+#include "ng_equivalence.h"
+#include "ng_holder.h"
+#include "ng_is_equal.h"
+#include "ng_literal_analysis.h"
+#include "ng_limex.h"
+#include "ng_mcclellan.h"
+#include "ng_netflow.h"
+#include "ng_prune.h"
+#include "ng_redundancy.h"
+#include "ng_region.h"
+#include "ng_reports.h"
+#include "ng_split.h"
+#include "ng_util.h"
+#include "ng_width.h"
+#include "nfa/rdfa.h"
+#include "rose/rose_build.h"
+#include "rose/rose_build_util.h"
+#include "rose/rose_in_dump.h"
+#include "rose/rose_in_graph.h"
+#include "rose/rose_in_util.h"
+#include "util/compare.h"
+#include "util/compile_context.h"
+#include "util/container.h"
+#include "util/flat_containers.h"
+#include "util/graph.h"
+#include "util/graph_range.h"
#include "util/graph_small_color_map.h"
-#include "util/insertion_ordered.h"
-#include "util/make_unique.h"
-#include "util/order_check.h"
-#include "util/target_info.h"
-#include "util/ue2string.h"
-
-#include <set>
-#include <utility>
-#include <vector>
-#include <boost/dynamic_bitset.hpp>
-#include <boost/range/adaptor/map.hpp>
-
-#define STAGE_DEBUG_PRINTF DEBUG_PRINTF
-
-using namespace std;
-using boost::adaptors::map_values;
-
-namespace ue2 {
-
-/* createsAnchoredLHS() is conservative as the depths take into account
- * back edges that come from beyond the split point and would be missing after
- * the graph is split. */
-static
-bool createsAnchoredLHS(const NGHolder &g, const vector<NFAVertex> &vv,
- const vector<NFAVertexDepth> &depths,
- const Grey &grey, depth max_depth = depth::infinity()) {
- max_depth = min(max_depth, depth(grey.maxAnchoredRegion));
-
- for (auto v : vv) {
- /* avoid issues of self loops blowing out depths:
- * look at preds, add 1 */
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (u == v) {
- continue;
- }
-
- u32 idx = g[u].index;
- assert(idx < depths.size());
- if (maxDistFromStartOfData(depths.at(idx)) >= max_depth) {
- return false;
- }
- }
- }
- return true;
-}
-
-/* createsTransientLHS() is conservative as the depths take into account
- * back edges that come from beyond the split point and would be missing after
- * the graph is split. */
-static
-bool createsTransientLHS(const NGHolder &g, const vector<NFAVertex> &vv,
- const vector<NFAVertexDepth> &depths,
- const Grey &grey) {
- const depth max_depth(grey.maxHistoryAvailable);
-
- for (auto v : vv) {
- /* avoid issues of self loops blowing out depths:
- * look at preds, add 1 */
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (u == v) {
- continue;
- }
-
- u32 idx = g[u].index;
- assert(idx < depths.size());
- if (maxDistFromInit(depths.at(idx)) >= max_depth) {
- return false;
- }
- }
- }
- return true;
-}
-
+#include "util/insertion_ordered.h"
+#include "util/make_unique.h"
+#include "util/order_check.h"
+#include "util/target_info.h"
+#include "util/ue2string.h"
+
+#include <set>
+#include <utility>
+#include <vector>
+#include <boost/dynamic_bitset.hpp>
+#include <boost/range/adaptor/map.hpp>
+
+#define STAGE_DEBUG_PRINTF DEBUG_PRINTF
+
+using namespace std;
+using boost::adaptors::map_values;
+
+namespace ue2 {
+
+/* createsAnchoredLHS() is conservative as the depths take into account
+ * back edges that come from beyond the split point and would be missing after
+ * the graph is split. */
+static
+bool createsAnchoredLHS(const NGHolder &g, const vector<NFAVertex> &vv,
+ const vector<NFAVertexDepth> &depths,
+ const Grey &grey, depth max_depth = depth::infinity()) {
+ max_depth = min(max_depth, depth(grey.maxAnchoredRegion));
+
+ for (auto v : vv) {
+ /* avoid issues of self loops blowing out depths:
+ * look at preds, add 1 */
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (u == v) {
+ continue;
+ }
+
+ u32 idx = g[u].index;
+ assert(idx < depths.size());
+ if (maxDistFromStartOfData(depths.at(idx)) >= max_depth) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/* createsTransientLHS() is conservative as the depths take into account
+ * back edges that come from beyond the split point and would be missing after
+ * the graph is split. */
+static
+bool createsTransientLHS(const NGHolder &g, const vector<NFAVertex> &vv,
+ const vector<NFAVertexDepth> &depths,
+ const Grey &grey) {
+ const depth max_depth(grey.maxHistoryAvailable);
+
+ for (auto v : vv) {
+ /* avoid issues of self loops blowing out depths:
+ * look at preds, add 1 */
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (u == v) {
+ continue;
+ }
+
+ u32 idx = g[u].index;
+ assert(idx < depths.size());
+ if (maxDistFromInit(depths.at(idx)) >= max_depth) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/**
* Counts the number of vertices that are reachable from the set of sources
* given.
*/
-static
+static
size_t count_reachable(const NGHolder &g, const vector<NFAVertex> &sources,
small_color_map<decltype(get(vertex_index, g))> &color_map) {
auto null_visitor = boost::make_dfs_visitor(boost::null_visitor());
color_map.fill(small_color::white);
-
+
for (auto v : sources) {
boost::depth_first_visit(g, v, null_visitor, color_map);
}
return color_map.count(small_color::black);
-}
-
-static
-size_t shorter_than(const set<ue2_literal> &s, size_t limit) {
- return count_if(s.begin(), s.end(),
- [&](const ue2_literal &a) { return a.length() < limit; });
-}
-
-static
-u32 min_len(const set<ue2_literal> &s) {
- u32 rv = ~0U;
-
- for (const auto &lit : s) {
- rv = min(rv, (u32)lit.length());
- }
-
- return rv;
-}
-
-static
-u32 min_period(const set<ue2_literal> &s) {
- u32 rv = ~0U;
-
- for (const auto &lit : s) {
- rv = min(rv, (u32)minStringPeriod(lit));
- }
- DEBUG_PRINTF("min period %u\n", rv);
- return rv;
-}
-
-namespace {
-/**
- * Information on a cut: vertices and literals.
- */
-struct VertLitInfo {
- VertLitInfo() {}
- VertLitInfo(NFAVertex v, const set<ue2_literal> &litlit, bool c_anch,
- bool c_tran = false)
- : vv(vector<NFAVertex>(1, v)), lit(litlit), creates_anchored(c_anch),
- creates_transient(c_tran) {}
- VertLitInfo(const vector<NFAVertex> &vv_in, const set<ue2_literal> &lit_in,
- bool c_anch)
- : vv(vv_in), lit(lit_in), creates_anchored(c_anch) {}
- vector<NFAVertex> vv;
- set<ue2_literal> lit;
-
- bool creates_anchored = false;
- bool creates_transient = false;
- double split_ratio = 0;
-};
-
-#define LAST_CHANCE_STRONG_LEN 1
-
-/**
- * \brief Comparator class for comparing different literal cuts.
- */
-class LitComparator {
-public:
- LitComparator(const NGHolder &g_in, bool sa, bool st, bool lc)
- : g(g_in), seeking_anchored(sa), seeking_transient(st),
- last_chance(lc) {}
- bool operator()(const unique_ptr<VertLitInfo> &a,
- const unique_ptr<VertLitInfo> &b) const {
- assert(a && b);
-
- if (seeking_anchored) {
- if (a->creates_anchored != b->creates_anchored) {
- return a->creates_anchored < b->creates_anchored;
- }
- }
-
- if (seeking_transient) {
- if (a->creates_transient != b->creates_transient) {
- return a->creates_transient < b->creates_transient;
- }
- }
-
- if (last_chance
- && min_len(a->lit) > LAST_CHANCE_STRONG_LEN
- && min_len(b->lit) > LAST_CHANCE_STRONG_LEN) {
- DEBUG_PRINTF("using split ratio %g , %g\n", a->split_ratio,
- b->split_ratio);
- return a->split_ratio < b->split_ratio;
- }
-
- u64a score_a = scoreSet(a->lit);
- u64a score_b = scoreSet(b->lit);
-
- if (score_a != score_b) {
- return score_a > score_b;
- }
-
- /* vertices should only be in one candidate cut */
- assert(a->vv == b->vv || a->vv.front() != b->vv.front());
- return g[a->vv.front()].index > g[b->vv.front()].index;
- }
-
-private:
- const NGHolder &g; /**< graph on which cuts are found */
-
- bool seeking_anchored;
- bool seeking_transient;
- bool last_chance;
-};
-}
-
-#define MIN_ANCHORED_LEN 2
-#define MIN_ANCHORED_DESPERATE_LEN 1
-
-/* anchored here means that the cut creates a 'usefully' anchored LHS */
-static
-bool validateRoseLiteralSetQuality(const set<ue2_literal> &s, u64a score,
- bool anchored, u32 min_allowed_floating_len,
- bool desperation, bool last_chance) {
- u32 min_allowed_len = anchored ? MIN_ANCHORED_LEN
- : min_allowed_floating_len;
- if (anchored && last_chance) {
- min_allowed_len = MIN_ANCHORED_DESPERATE_LEN;
- }
- if (last_chance) {
- desperation = true;
- }
-
- DEBUG_PRINTF("validating%s set, min allowed len %u\n",
- anchored ? " anchored" : "", min_allowed_len);
-
- assert(none_of(begin(s), end(s), bad_mixed_sensitivity));
-
- if (score >= NO_LITERAL_AT_EDGE_SCORE) {
- DEBUG_PRINTF("candidate is too bad %llu/%zu\n", score, s.size());
- return false;
- }
-
- assert(!s.empty());
- if (s.empty()) {
- DEBUG_PRINTF("candidate is too bad/something went wrong\n");
- return false;
- }
-
- u32 s_min_len = min_len(s);
- u32 s_min_period = min_period(s);
- size_t short_count = shorter_than(s, 5);
-
- DEBUG_PRINTF("cand '%s': score %llu count=%zu min_len=%u min_period=%u"
- " short_count=%zu desp=%d\n",
- dumpString(*s.begin()).c_str(), score, s.size(), s_min_len,
- s_min_period, short_count, (int)desperation);
-
- bool ok = true;
-
- if (s.size() > 10 /* magic number is magic */
- || s_min_len < min_allowed_len
- || (s_min_period <= 1 && min_allowed_len != 1)) {
- DEBUG_PRINTF("candidate may be bad\n");
- ok = false;
- }
-
- if (!ok && desperation
- && s.size() <= 20 /* more magic numbers are magical */
- && (s_min_len > 5 || (s_min_len > 2 && short_count <= 10))
- && s_min_period > 1) {
- DEBUG_PRINTF("candidate is ok\n");
- ok = true;
- }
-
- if (!ok && desperation
- && s.size() <= 50 /* more magic numbers are magical */
- && s_min_len > 10
- && s_min_period > 1) {
- DEBUG_PRINTF("candidate is ok\n");
- ok = true;
- }
-
- if (!ok) {
- DEBUG_PRINTF("candidate is too shitty\n");
- return false;
- }
-
- return true;
-}
-
-static UNUSED
-void dumpRoseLiteralSet(const set<ue2_literal> &s) {
- for (UNUSED const auto &lit : s) {
- DEBUG_PRINTF(" lit: %s\n", dumpString(lit).c_str());
- }
-}
-
-static
-void getSimpleRoseLiterals(const NGHolder &g, bool seeking_anchored,
- const vector<NFAVertexDepth> *depths,
- const set<NFAVertex> &a_dom,
- vector<unique_ptr<VertLitInfo>> *lits,
- u32 min_allowed_len, bool desperation,
- bool last_chance, const CompileContext &cc) {
- assert(depths || !seeking_anchored);
-
- map<NFAVertex, u64a> scores;
- map<NFAVertex, unique_ptr<VertLitInfo>> lit_info;
- set<ue2_literal> s;
-
- for (auto v : a_dom) {
- s = getLiteralSet(g, v, true); /* RHS will take responsibility for any
- revisits to the target vertex */
-
- if (s.empty()) {
- DEBUG_PRINTF("candidate is too shitty\n");
- continue;
- }
-
- DEBUG_PRINTF("|candidate raw literal set| = %zu\n", s.size());
- dumpRoseLiteralSet(s);
- u64a score = sanitizeAndCompressAndScore(s);
-
- bool anchored = false;
- if (seeking_anchored) {
- anchored = createsAnchoredLHS(g, {v}, *depths, cc.grey);
- }
-
- if (!validateRoseLiteralSetQuality(s, score, anchored, min_allowed_len,
- desperation, last_chance)) {
- continue;
- }
-
- DEBUG_PRINTF("candidate is a candidate\n");
- scores[v] = score;
- lit_info[v] = std::make_unique<VertLitInfo>(v, s, anchored);
- }
-
- /* try to filter out cases where appending some characters produces worse
- * literals. Only bother to look back one byte, TODO make better */
- for (auto u : a_dom) {
- if (out_degree(u, g) != 1 || !scores[u]) {
- continue;
- }
- NFAVertex v = *adjacent_vertices(u, g).first;
- if (contains(scores, v) && scores[v] >= scores[u]) {
- DEBUG_PRINTF("killing off v as score %llu >= %llu\n",
- scores[v], scores[u]);
- lit_info.erase(v);
- }
- }
-
- lits->reserve(lit_info.size());
- for (auto &m : lit_info) {
- lits->push_back(move(m.second));
- }
- DEBUG_PRINTF("%zu candidate literal sets\n", lits->size());
-}
-
-static
-void getRegionRoseLiterals(const NGHolder &g, bool seeking_anchored,
- const vector<NFAVertexDepth> *depths,
- const set<NFAVertex> &bad,
- const set<NFAVertex> *allowed,
- vector<unique_ptr<VertLitInfo>> *lits,
- u32 min_allowed_len, bool desperation,
- bool last_chance, const CompileContext &cc) {
- /* This allows us to get more places to split the graph as we are not
- limited to points where there is a single vertex to split at. */
-
- assert(depths || !seeking_anchored);
-
- /* TODO: operate over 'proto-regions' which ignore back edges */
- auto regions = assignRegions(g);
-
- set<u32> mand, optional;
- map<u32, vector<NFAVertex> > exits;
-
- for (auto v : vertices_range(g)) {
- u32 region = regions[v];
- if (is_any_start(v, g) || region == 0) {
- continue;
- }
-
- if (is_any_accept(v, g)) {
- continue;
- }
-
- if (!generates_callbacks(g) && is_match_vertex(v, g)) {
- /* we cannot leave a completely vacuous infix */
- continue;
- }
-
- if (isRegionExit(g, v, regions)) {
- exits[region].push_back(v);
- }
-
- if (isRegionEntry(g, v, regions)) {
- // Determine whether this region is mandatory or optional. We only
- // need to do this check for the first entry vertex we encounter
- // for this region.
- if (!contains(mand, region) && !contains(optional, region)) {
- if (isOptionalRegion(g, v, regions)) {
- optional.insert(region);
- } else {
- mand.insert(region);
- }
- }
- }
- }
-
- for (const auto &m : exits) {
- if (false) {
- next_cand:
- continue;
- }
-
- const u32 region = m.first;
- const vector<NFAVertex> &vv = m.second;
- assert(!vv.empty());
-
- if (!contains(mand, region)) {
- continue;
- }
-
- for (auto v : vv) {
- /* if an exit is in bad, the region is already handled well
- * by getSimpleRoseLiterals or is otherwise bad */
- if (contains(bad, v)) {
- goto next_cand;
- }
- /* if we are only allowed to consider some vertices, v must be in
- the list; */
- if (allowed && !contains(*allowed, v)) {
- goto next_cand;
- }
- }
-
- /* the final region may not have a neat exit. validate that all exits
- * have an edge to each accept or none do */
- bool edge_to_a = edge(vv[0], g.accept, g).second;
- bool edge_to_aeod = edge(vv[0], g.acceptEod, g).second;
- const auto &reports = g[vv[0]].reports;
- for (auto v : vv) {
- if (edge_to_a != edge(v, g.accept, g).second) {
- goto next_cand;
- }
-
- if (edge_to_aeod != edge(v, g.acceptEod, g).second) {
- goto next_cand;
- }
-
- if (g[v].reports != reports) {
- goto next_cand;
- }
- }
-
- DEBUG_PRINTF("inspecting region %u\n", region);
- set<ue2_literal> s;
- for (auto v : vv) {
- DEBUG_PRINTF(" exit vertex: %zu\n", g[v].index);
- /* Note: RHS can not be depended on to take all subsequent revisits
- * to this vertex */
- set<ue2_literal> ss = getLiteralSet(g, v, false);
- if (ss.empty()) {
- DEBUG_PRINTF("candidate is too shitty\n");
- goto next_cand;
- }
- insert(&s, ss);
- }
-
- assert(!s.empty());
-
- DEBUG_PRINTF("|candidate raw literal set| = %zu\n", s.size());
- dumpRoseLiteralSet(s);
- u64a score = sanitizeAndCompressAndScore(s);
-
- DEBUG_PRINTF("|candidate literal set| = %zu\n", s.size());
- dumpRoseLiteralSet(s);
-
- bool anchored = false;
- if (seeking_anchored) {
- anchored = createsAnchoredLHS(g, vv, *depths, cc.grey);
- }
-
- if (!validateRoseLiteralSetQuality(s, score, anchored, min_allowed_len,
- desperation, last_chance)) {
- goto next_cand;
- }
-
- DEBUG_PRINTF("candidate is a candidate\n");
- lits->push_back(std::make_unique<VertLitInfo>(vv, s, anchored));
- }
-}
-
-static
-void filterCandPivots(const NGHolder &g, const set<NFAVertex> &cand_raw,
- set<NFAVertex> *out) {
- for (auto u : cand_raw) {
- const CharReach &u_cr = g[u].char_reach;
- if (u_cr.count() > 40) {
- continue; /* too wide to be plausible */
- }
-
- if (u_cr.count() > 2) {
- /* include u as a candidate as successor may have backed away from
- * expanding through it */
- out->insert(u);
- continue;
- }
-
- NFAVertex v = getSoleDestVertex(g, u);
- if (v && in_degree(v, g) == 1 && out_degree(u, g) == 1) {
- const CharReach &v_cr = g[v].char_reach;
- if (v_cr.count() == 1 || v_cr.isCaselessChar()) {
- continue; /* v will always generate better literals */
- }
- }
-
- out->insert(u);
- }
-}
-
-/* cand_raw is the candidate set before filtering points which are clearly
- * a bad idea. */
-static
-void getCandidatePivots(const NGHolder &g, set<NFAVertex> *cand,
- set<NFAVertex> *cand_raw) {
- auto dominators = findDominators(g);
-
- set<NFAVertex> accepts;
-
- for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
- if (is_special(v, g)) {
- continue;
- }
- accepts.insert(v);
- }
- for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
- if (is_special(v, g)) {
- continue;
- }
- accepts.insert(v);
- }
-
- assert(!accepts.empty());
-
- vector<NFAVertex> dom_trace;
- auto ait = accepts.begin();
- assert(ait != accepts.end());
- NFAVertex curr = *ait;
- while (curr && !is_special(curr, g)) {
- dom_trace.push_back(curr);
- curr = dominators[curr];
- }
- reverse(dom_trace.begin(), dom_trace.end());
- for (++ait; ait != accepts.end(); ++ait) {
- curr = *ait;
- vector<NFAVertex> dom_trace2;
- while (curr && !is_special(curr, g)) {
- dom_trace2.push_back(curr);
- curr = dominators[curr];
- }
- reverse(dom_trace2.begin(), dom_trace2.end());
- auto dti = dom_trace.begin(), dtie = dom_trace.end();
- auto dtj = dom_trace2.begin(), dtje = dom_trace2.end();
- while (dti != dtie && dtj != dtje && *dti == *dtj) {
- ++dti;
- ++dtj;
- }
- dom_trace.erase(dti, dtie);
- }
-
- cand_raw->insert(dom_trace.begin(), dom_trace.end());
-
- filterCandPivots(g, *cand_raw, cand);
-}
-
-static
-unique_ptr<VertLitInfo> findBestSplit(const NGHolder &g,
- const vector<NFAVertexDepth> *depths,
- bool for_prefix, u32 min_len,
- const set<NFAVertex> *allowed_cand,
- const set<NFAVertex> *disallowed_cand,
- bool last_chance,
- const CompileContext &cc) {
- assert(!for_prefix || depths);
-
- /* look for a single simple split point */
- set<NFAVertex> cand;
- set<NFAVertex> cand_raw;
-
- getCandidatePivots(g, &cand, &cand_raw);
-
- if (allowed_cand) {
- set<NFAVertex> cand2;
- set<NFAVertex> cand2_raw;
- set_intersection(allowed_cand->begin(), allowed_cand->end(),
- cand.begin(), cand.end(),
- inserter(cand2, cand2.begin()));
-
- set_intersection(allowed_cand->begin(), allowed_cand->end(),
- cand_raw.begin(), cand_raw.end(),
- inserter(cand2_raw, cand2_raw.begin()));
-
- cand = std::move(cand2);
- cand_raw = std::move(cand2_raw);
- }
- if (disallowed_cand) {
- DEBUG_PRINTF("%zu disallowed candidates\n", disallowed_cand->size());
- DEBUG_PRINTF("|old cand| = %zu\n", cand.size());
- erase_all(&cand, *disallowed_cand);
- insert(&cand_raw, *disallowed_cand);
- }
-
- if (!generates_callbacks(g)) {
- /* not output exposed so must leave some RHS */
- for (NFAVertex v : inv_adjacent_vertices_range(g.accept, g)) {
- cand.erase(v);
- cand_raw.erase(v);
- }
-
- for (NFAVertex v : inv_adjacent_vertices_range(g.acceptEod, g)) {
- cand.erase(v);
- cand_raw.erase(v);
- }
- }
-
- DEBUG_PRINTF("|cand| = %zu\n", cand.size());
-
- bool seeking_anchored = for_prefix;
- bool seeking_transient = for_prefix;
-
- bool desperation = for_prefix && cc.streaming;
-
- vector<unique_ptr<VertLitInfo>> lits; /**< sorted list of potential cuts */
-
- getSimpleRoseLiterals(g, seeking_anchored, depths, cand, &lits, min_len,
- desperation, last_chance, cc);
- getRegionRoseLiterals(g, seeking_anchored, depths, cand_raw, allowed_cand,
- &lits, min_len, desperation, last_chance, cc);
-
- if (lits.empty()) {
- DEBUG_PRINTF("no literals found\n");
- return nullptr;
- }
-
- if (seeking_transient) {
- for (auto &a : lits) {
- a->creates_transient
- = createsTransientLHS(g, a->vv, *depths, cc.grey);
- }
- }
-
- if (last_chance) {
+}
+
+static
+size_t shorter_than(const set<ue2_literal> &s, size_t limit) {
+ return count_if(s.begin(), s.end(),
+ [&](const ue2_literal &a) { return a.length() < limit; });
+}
+
+static
+u32 min_len(const set<ue2_literal> &s) {
+ u32 rv = ~0U;
+
+ for (const auto &lit : s) {
+ rv = min(rv, (u32)lit.length());
+ }
+
+ return rv;
+}
+
+static
+u32 min_period(const set<ue2_literal> &s) {
+ u32 rv = ~0U;
+
+ for (const auto &lit : s) {
+ rv = min(rv, (u32)minStringPeriod(lit));
+ }
+ DEBUG_PRINTF("min period %u\n", rv);
+ return rv;
+}
+
+namespace {
+/**
+ * Information on a cut: vertices and literals.
+ */
+struct VertLitInfo {
+ VertLitInfo() {}
+ VertLitInfo(NFAVertex v, const set<ue2_literal> &litlit, bool c_anch,
+ bool c_tran = false)
+ : vv(vector<NFAVertex>(1, v)), lit(litlit), creates_anchored(c_anch),
+ creates_transient(c_tran) {}
+ VertLitInfo(const vector<NFAVertex> &vv_in, const set<ue2_literal> &lit_in,
+ bool c_anch)
+ : vv(vv_in), lit(lit_in), creates_anchored(c_anch) {}
+ vector<NFAVertex> vv;
+ set<ue2_literal> lit;
+
+ bool creates_anchored = false;
+ bool creates_transient = false;
+ double split_ratio = 0;
+};
+
+#define LAST_CHANCE_STRONG_LEN 1
+
+/**
+ * \brief Comparator class for comparing different literal cuts.
+ */
+class LitComparator {
+public:
+ LitComparator(const NGHolder &g_in, bool sa, bool st, bool lc)
+ : g(g_in), seeking_anchored(sa), seeking_transient(st),
+ last_chance(lc) {}
+ bool operator()(const unique_ptr<VertLitInfo> &a,
+ const unique_ptr<VertLitInfo> &b) const {
+ assert(a && b);
+
+ if (seeking_anchored) {
+ if (a->creates_anchored != b->creates_anchored) {
+ return a->creates_anchored < b->creates_anchored;
+ }
+ }
+
+ if (seeking_transient) {
+ if (a->creates_transient != b->creates_transient) {
+ return a->creates_transient < b->creates_transient;
+ }
+ }
+
+ if (last_chance
+ && min_len(a->lit) > LAST_CHANCE_STRONG_LEN
+ && min_len(b->lit) > LAST_CHANCE_STRONG_LEN) {
+ DEBUG_PRINTF("using split ratio %g , %g\n", a->split_ratio,
+ b->split_ratio);
+ return a->split_ratio < b->split_ratio;
+ }
+
+ u64a score_a = scoreSet(a->lit);
+ u64a score_b = scoreSet(b->lit);
+
+ if (score_a != score_b) {
+ return score_a > score_b;
+ }
+
+ /* vertices should only be in one candidate cut */
+ assert(a->vv == b->vv || a->vv.front() != b->vv.front());
+ return g[a->vv.front()].index > g[b->vv.front()].index;
+ }
+
+private:
+ const NGHolder &g; /**< graph on which cuts are found */
+
+ bool seeking_anchored;
+ bool seeking_transient;
+ bool last_chance;
+};
+}
+
+#define MIN_ANCHORED_LEN 2
+#define MIN_ANCHORED_DESPERATE_LEN 1
+
+/* anchored here means that the cut creates a 'usefully' anchored LHS */
+static
+bool validateRoseLiteralSetQuality(const set<ue2_literal> &s, u64a score,
+ bool anchored, u32 min_allowed_floating_len,
+ bool desperation, bool last_chance) {
+ u32 min_allowed_len = anchored ? MIN_ANCHORED_LEN
+ : min_allowed_floating_len;
+ if (anchored && last_chance) {
+ min_allowed_len = MIN_ANCHORED_DESPERATE_LEN;
+ }
+ if (last_chance) {
+ desperation = true;
+ }
+
+ DEBUG_PRINTF("validating%s set, min allowed len %u\n",
+ anchored ? " anchored" : "", min_allowed_len);
+
+ assert(none_of(begin(s), end(s), bad_mixed_sensitivity));
+
+ if (score >= NO_LITERAL_AT_EDGE_SCORE) {
+ DEBUG_PRINTF("candidate is too bad %llu/%zu\n", score, s.size());
+ return false;
+ }
+
+ assert(!s.empty());
+ if (s.empty()) {
+ DEBUG_PRINTF("candidate is too bad/something went wrong\n");
+ return false;
+ }
+
+ u32 s_min_len = min_len(s);
+ u32 s_min_period = min_period(s);
+ size_t short_count = shorter_than(s, 5);
+
+ DEBUG_PRINTF("cand '%s': score %llu count=%zu min_len=%u min_period=%u"
+ " short_count=%zu desp=%d\n",
+ dumpString(*s.begin()).c_str(), score, s.size(), s_min_len,
+ s_min_period, short_count, (int)desperation);
+
+ bool ok = true;
+
+ if (s.size() > 10 /* magic number is magic */
+ || s_min_len < min_allowed_len
+ || (s_min_period <= 1 && min_allowed_len != 1)) {
+ DEBUG_PRINTF("candidate may be bad\n");
+ ok = false;
+ }
+
+ if (!ok && desperation
+ && s.size() <= 20 /* more magic numbers are magical */
+ && (s_min_len > 5 || (s_min_len > 2 && short_count <= 10))
+ && s_min_period > 1) {
+ DEBUG_PRINTF("candidate is ok\n");
+ ok = true;
+ }
+
+ if (!ok && desperation
+ && s.size() <= 50 /* more magic numbers are magical */
+ && s_min_len > 10
+ && s_min_period > 1) {
+ DEBUG_PRINTF("candidate is ok\n");
+ ok = true;
+ }
+
+ if (!ok) {
+ DEBUG_PRINTF("candidate is too shitty\n");
+ return false;
+ }
+
+ return true;
+}
+
+static UNUSED
+void dumpRoseLiteralSet(const set<ue2_literal> &s) {
+ for (UNUSED const auto &lit : s) {
+ DEBUG_PRINTF(" lit: %s\n", dumpString(lit).c_str());
+ }
+}
+
+static
+void getSimpleRoseLiterals(const NGHolder &g, bool seeking_anchored,
+ const vector<NFAVertexDepth> *depths,
+ const set<NFAVertex> &a_dom,
+ vector<unique_ptr<VertLitInfo>> *lits,
+ u32 min_allowed_len, bool desperation,
+ bool last_chance, const CompileContext &cc) {
+ assert(depths || !seeking_anchored);
+
+ map<NFAVertex, u64a> scores;
+ map<NFAVertex, unique_ptr<VertLitInfo>> lit_info;
+ set<ue2_literal> s;
+
+ for (auto v : a_dom) {
+ s = getLiteralSet(g, v, true); /* RHS will take responsibility for any
+ revisits to the target vertex */
+
+ if (s.empty()) {
+ DEBUG_PRINTF("candidate is too shitty\n");
+ continue;
+ }
+
+ DEBUG_PRINTF("|candidate raw literal set| = %zu\n", s.size());
+ dumpRoseLiteralSet(s);
+ u64a score = sanitizeAndCompressAndScore(s);
+
+ bool anchored = false;
+ if (seeking_anchored) {
+ anchored = createsAnchoredLHS(g, {v}, *depths, cc.grey);
+ }
+
+ if (!validateRoseLiteralSetQuality(s, score, anchored, min_allowed_len,
+ desperation, last_chance)) {
+ continue;
+ }
+
+ DEBUG_PRINTF("candidate is a candidate\n");
+ scores[v] = score;
+ lit_info[v] = std::make_unique<VertLitInfo>(v, s, anchored);
+ }
+
+ /* try to filter out cases where appending some characters produces worse
+ * literals. Only bother to look back one byte, TODO make better */
+ for (auto u : a_dom) {
+ if (out_degree(u, g) != 1 || !scores[u]) {
+ continue;
+ }
+ NFAVertex v = *adjacent_vertices(u, g).first;
+ if (contains(scores, v) && scores[v] >= scores[u]) {
+ DEBUG_PRINTF("killing off v as score %llu >= %llu\n",
+ scores[v], scores[u]);
+ lit_info.erase(v);
+ }
+ }
+
+ lits->reserve(lit_info.size());
+ for (auto &m : lit_info) {
+ lits->push_back(move(m.second));
+ }
+ DEBUG_PRINTF("%zu candidate literal sets\n", lits->size());
+}
+
+static
+void getRegionRoseLiterals(const NGHolder &g, bool seeking_anchored,
+ const vector<NFAVertexDepth> *depths,
+ const set<NFAVertex> &bad,
+ const set<NFAVertex> *allowed,
+ vector<unique_ptr<VertLitInfo>> *lits,
+ u32 min_allowed_len, bool desperation,
+ bool last_chance, const CompileContext &cc) {
+ /* This allows us to get more places to split the graph as we are not
+ limited to points where there is a single vertex to split at. */
+
+ assert(depths || !seeking_anchored);
+
+ /* TODO: operate over 'proto-regions' which ignore back edges */
+ auto regions = assignRegions(g);
+
+ set<u32> mand, optional;
+ map<u32, vector<NFAVertex> > exits;
+
+ for (auto v : vertices_range(g)) {
+ u32 region = regions[v];
+ if (is_any_start(v, g) || region == 0) {
+ continue;
+ }
+
+ if (is_any_accept(v, g)) {
+ continue;
+ }
+
+ if (!generates_callbacks(g) && is_match_vertex(v, g)) {
+ /* we cannot leave a completely vacuous infix */
+ continue;
+ }
+
+ if (isRegionExit(g, v, regions)) {
+ exits[region].push_back(v);
+ }
+
+ if (isRegionEntry(g, v, regions)) {
+ // Determine whether this region is mandatory or optional. We only
+ // need to do this check for the first entry vertex we encounter
+ // for this region.
+ if (!contains(mand, region) && !contains(optional, region)) {
+ if (isOptionalRegion(g, v, regions)) {
+ optional.insert(region);
+ } else {
+ mand.insert(region);
+ }
+ }
+ }
+ }
+
+ for (const auto &m : exits) {
+ if (false) {
+ next_cand:
+ continue;
+ }
+
+ const u32 region = m.first;
+ const vector<NFAVertex> &vv = m.second;
+ assert(!vv.empty());
+
+ if (!contains(mand, region)) {
+ continue;
+ }
+
+ for (auto v : vv) {
+ /* if an exit is in bad, the region is already handled well
+ * by getSimpleRoseLiterals or is otherwise bad */
+ if (contains(bad, v)) {
+ goto next_cand;
+ }
+ /* if we are only allowed to consider some vertices, v must be in
+ the list; */
+ if (allowed && !contains(*allowed, v)) {
+ goto next_cand;
+ }
+ }
+
+ /* the final region may not have a neat exit. validate that all exits
+ * have an edge to each accept or none do */
+ bool edge_to_a = edge(vv[0], g.accept, g).second;
+ bool edge_to_aeod = edge(vv[0], g.acceptEod, g).second;
+ const auto &reports = g[vv[0]].reports;
+ for (auto v : vv) {
+ if (edge_to_a != edge(v, g.accept, g).second) {
+ goto next_cand;
+ }
+
+ if (edge_to_aeod != edge(v, g.acceptEod, g).second) {
+ goto next_cand;
+ }
+
+ if (g[v].reports != reports) {
+ goto next_cand;
+ }
+ }
+
+ DEBUG_PRINTF("inspecting region %u\n", region);
+ set<ue2_literal> s;
+ for (auto v : vv) {
+ DEBUG_PRINTF(" exit vertex: %zu\n", g[v].index);
+ /* Note: RHS can not be depended on to take all subsequent revisits
+ * to this vertex */
+ set<ue2_literal> ss = getLiteralSet(g, v, false);
+ if (ss.empty()) {
+ DEBUG_PRINTF("candidate is too shitty\n");
+ goto next_cand;
+ }
+ insert(&s, ss);
+ }
+
+ assert(!s.empty());
+
+ DEBUG_PRINTF("|candidate raw literal set| = %zu\n", s.size());
+ dumpRoseLiteralSet(s);
+ u64a score = sanitizeAndCompressAndScore(s);
+
+ DEBUG_PRINTF("|candidate literal set| = %zu\n", s.size());
+ dumpRoseLiteralSet(s);
+
+ bool anchored = false;
+ if (seeking_anchored) {
+ anchored = createsAnchoredLHS(g, vv, *depths, cc.grey);
+ }
+
+ if (!validateRoseLiteralSetQuality(s, score, anchored, min_allowed_len,
+ desperation, last_chance)) {
+ goto next_cand;
+ }
+
+ DEBUG_PRINTF("candidate is a candidate\n");
+ lits->push_back(std::make_unique<VertLitInfo>(vv, s, anchored));
+ }
+}
+
+static
+void filterCandPivots(const NGHolder &g, const set<NFAVertex> &cand_raw,
+ set<NFAVertex> *out) {
+ for (auto u : cand_raw) {
+ const CharReach &u_cr = g[u].char_reach;
+ if (u_cr.count() > 40) {
+ continue; /* too wide to be plausible */
+ }
+
+ if (u_cr.count() > 2) {
+ /* include u as a candidate as successor may have backed away from
+ * expanding through it */
+ out->insert(u);
+ continue;
+ }
+
+ NFAVertex v = getSoleDestVertex(g, u);
+ if (v && in_degree(v, g) == 1 && out_degree(u, g) == 1) {
+ const CharReach &v_cr = g[v].char_reach;
+ if (v_cr.count() == 1 || v_cr.isCaselessChar()) {
+ continue; /* v will always generate better literals */
+ }
+ }
+
+ out->insert(u);
+ }
+}
+
+/* cand_raw is the candidate set before filtering points which are clearly
+ * a bad idea. */
+static
+void getCandidatePivots(const NGHolder &g, set<NFAVertex> *cand,
+ set<NFAVertex> *cand_raw) {
+ auto dominators = findDominators(g);
+
+ set<NFAVertex> accepts;
+
+ for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
+ if (is_special(v, g)) {
+ continue;
+ }
+ accepts.insert(v);
+ }
+ for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
+ if (is_special(v, g)) {
+ continue;
+ }
+ accepts.insert(v);
+ }
+
+ assert(!accepts.empty());
+
+ vector<NFAVertex> dom_trace;
+ auto ait = accepts.begin();
+ assert(ait != accepts.end());
+ NFAVertex curr = *ait;
+ while (curr && !is_special(curr, g)) {
+ dom_trace.push_back(curr);
+ curr = dominators[curr];
+ }
+ reverse(dom_trace.begin(), dom_trace.end());
+ for (++ait; ait != accepts.end(); ++ait) {
+ curr = *ait;
+ vector<NFAVertex> dom_trace2;
+ while (curr && !is_special(curr, g)) {
+ dom_trace2.push_back(curr);
+ curr = dominators[curr];
+ }
+ reverse(dom_trace2.begin(), dom_trace2.end());
+ auto dti = dom_trace.begin(), dtie = dom_trace.end();
+ auto dtj = dom_trace2.begin(), dtje = dom_trace2.end();
+ while (dti != dtie && dtj != dtje && *dti == *dtj) {
+ ++dti;
+ ++dtj;
+ }
+ dom_trace.erase(dti, dtie);
+ }
+
+ cand_raw->insert(dom_trace.begin(), dom_trace.end());
+
+ filterCandPivots(g, *cand_raw, cand);
+}
+
+static
+unique_ptr<VertLitInfo> findBestSplit(const NGHolder &g,
+ const vector<NFAVertexDepth> *depths,
+ bool for_prefix, u32 min_len,
+ const set<NFAVertex> *allowed_cand,
+ const set<NFAVertex> *disallowed_cand,
+ bool last_chance,
+ const CompileContext &cc) {
+ assert(!for_prefix || depths);
+
+ /* look for a single simple split point */
+ set<NFAVertex> cand;
+ set<NFAVertex> cand_raw;
+
+ getCandidatePivots(g, &cand, &cand_raw);
+
+ if (allowed_cand) {
+ set<NFAVertex> cand2;
+ set<NFAVertex> cand2_raw;
+ set_intersection(allowed_cand->begin(), allowed_cand->end(),
+ cand.begin(), cand.end(),
+ inserter(cand2, cand2.begin()));
+
+ set_intersection(allowed_cand->begin(), allowed_cand->end(),
+ cand_raw.begin(), cand_raw.end(),
+ inserter(cand2_raw, cand2_raw.begin()));
+
+ cand = std::move(cand2);
+ cand_raw = std::move(cand2_raw);
+ }
+ if (disallowed_cand) {
+ DEBUG_PRINTF("%zu disallowed candidates\n", disallowed_cand->size());
+ DEBUG_PRINTF("|old cand| = %zu\n", cand.size());
+ erase_all(&cand, *disallowed_cand);
+ insert(&cand_raw, *disallowed_cand);
+ }
+
+ if (!generates_callbacks(g)) {
+ /* not output exposed so must leave some RHS */
+ for (NFAVertex v : inv_adjacent_vertices_range(g.accept, g)) {
+ cand.erase(v);
+ cand_raw.erase(v);
+ }
+
+ for (NFAVertex v : inv_adjacent_vertices_range(g.acceptEod, g)) {
+ cand.erase(v);
+ cand_raw.erase(v);
+ }
+ }
+
+ DEBUG_PRINTF("|cand| = %zu\n", cand.size());
+
+ bool seeking_anchored = for_prefix;
+ bool seeking_transient = for_prefix;
+
+ bool desperation = for_prefix && cc.streaming;
+
+ vector<unique_ptr<VertLitInfo>> lits; /**< sorted list of potential cuts */
+
+ getSimpleRoseLiterals(g, seeking_anchored, depths, cand, &lits, min_len,
+ desperation, last_chance, cc);
+ getRegionRoseLiterals(g, seeking_anchored, depths, cand_raw, allowed_cand,
+ &lits, min_len, desperation, last_chance, cc);
+
+ if (lits.empty()) {
+ DEBUG_PRINTF("no literals found\n");
+ return nullptr;
+ }
+
+ if (seeking_transient) {
+ for (auto &a : lits) {
+ a->creates_transient
+ = createsTransientLHS(g, a->vv, *depths, cc.grey);
+ }
+ }
+
+ if (last_chance) {
const size_t num_verts = num_vertices(g);
auto color_map = make_small_color_map(g);
- for (auto &a : lits) {
+ for (auto &a : lits) {
size_t num_reachable = count_reachable(g, a->vv, color_map);
double ratio = (double)num_reachable / (double)num_verts;
a->split_ratio = ratio > 0.5 ? 1 - ratio : ratio;
- }
- }
-
- auto cmp = LitComparator(g, seeking_anchored, seeking_transient,
- last_chance);
-
- unique_ptr<VertLitInfo> best = move(lits.back());
- lits.pop_back();
- while (!lits.empty()) {
- if (cmp(best, lits.back())) {
- best = move(lits.back());
- }
- lits.pop_back();
- }
-
- DEBUG_PRINTF("best is '%s' %zu a%d t%d\n",
- dumpString(*best->lit.begin()).c_str(),
- g[best->vv.front()].index,
- depths ? (int)createsAnchoredLHS(g, best->vv, *depths, cc.grey) : 0,
- depths ? (int)createsTransientLHS(g, best->vv, *depths, cc.grey) : 0);
-
- return best;
-}
-
-static
-void poisonFromSuccessor(const NGHolder &h, const ue2_literal &succ,
- bool overhang_ok, flat_set<NFAEdge> &bad) {
- DEBUG_PRINTF("poisoning holder of size %zu, succ len %zu\n",
- num_vertices(h), succ.length());
-
- using EdgeSet = boost::dynamic_bitset<>;
-
- const size_t edge_count = num_edges(h);
- EdgeSet bad_edges(edge_count);
-
- unordered_map<NFAVertex, EdgeSet> curr;
- for (const auto &e : in_edges_range(h.accept, h)) {
- auto &path_set = curr[source(e, h)];
- if (path_set.empty()) {
- path_set.resize(edge_count);
- }
- path_set.set(h[e].index);
- }
-
- unordered_map<NFAVertex, EdgeSet> next;
- for (auto it = succ.rbegin(); it != succ.rend(); ++it) {
- for (const auto &path : curr) {
- NFAVertex u = path.first;
- const auto &path_set = path.second;
- if (u == h.start && overhang_ok) {
- DEBUG_PRINTF("poisoning early %zu [overhang]\n",
- path_set.count());
- bad_edges |= path_set;
- continue;
- }
- if (overlaps(h[u].char_reach, *it)) {
- for (const auto &e : in_edges_range(u, h)) {
- auto &new_path_set = next[source(e, h)];
- if (new_path_set.empty()) {
- new_path_set.resize(edge_count);
- }
- new_path_set |= path_set;
- new_path_set.set(h[e].index);
- }
- }
- }
- DEBUG_PRINTF("succ char matches at %zu paths\n", next.size());
- assert(overhang_ok || !curr.empty());
- swap(curr, next);
- next.clear();
- }
-
- assert(overhang_ok || !curr.empty());
- for (const auto &path : curr) {
- bad_edges |= path.second;
- DEBUG_PRINTF("poisoning %zu vertices\n", path.second.count());
- }
-
- for (const auto &e : edges_range(h)) {
- if (bad_edges.test(h[e].index)) {
- bad.insert(e);
- }
- }
-}
-
-static
-void poisonForGoodPrefix(const NGHolder &h,
- const vector<NFAVertexDepth> &depths,
- flat_set<NFAEdge> &bad, const Grey &grey) {
- for (const auto &v : vertices_range(h)) {
- if (!createsAnchoredLHS(h, {v}, depths, grey)
- && !createsTransientLHS(h, {v}, depths, grey)) {
- insert(&bad, in_edges_range(v, h));
- }
- }
-}
-
-static UNUSED
-bool is_any_accept_type(RoseInVertexType t) {
- return t == RIV_ACCEPT || t == RIV_ACCEPT_EOD;
-}
-
-static
-flat_set<NFAEdge> poisonEdges(const NGHolder &h,
- const vector<NFAVertexDepth> *depths,
- const RoseInGraph &vg, const vector<RoseInEdge> &ee,
- bool for_prefix, const Grey &grey) {
- DEBUG_PRINTF("poisoning edges %zu successor edges\n", ee.size());
-
- /* poison edges covered by successor literal */
-
- set<pair<ue2_literal, bool> > succs;
- for (const RoseInEdge &ve : ee) {
- if (vg[target(ve, vg)].type != RIV_LITERAL) {
- /* nothing to poison in suffixes/outfixes */
- assert(generates_callbacks(h));
- assert(is_any_accept_type(vg[target(ve, vg)].type));
- continue;
- }
- succs.insert({vg[target(ve, vg)].s,
- vg[source(ve, vg)].type == RIV_LITERAL});
-
- }
-
- DEBUG_PRINTF("poisoning edges %zu successor literals\n", succs.size());
-
- flat_set<NFAEdge> bad;
- for (const auto &p : succs) {
- poisonFromSuccessor(h, p.first, p.second, bad);
- }
-
- /* poison edges which don't significantly improve a prefix */
-
- if (for_prefix) {
- poisonForGoodPrefix(h, *depths, bad, grey);
- }
-
- return bad;
-}
-
-static
-set<NFAVertex> poisonVertices(const NGHolder &h, const RoseInGraph &vg,
- const vector<RoseInEdge> &ee, const Grey &grey) {
- flat_set<NFAEdge> bad_edges = poisonEdges(h, nullptr, vg, ee, false, grey);
- set<NFAVertex> bad_vertices;
- for (const NFAEdge &e : bad_edges) {
- bad_vertices.insert(target(e, h));
- DEBUG_PRINTF("bad: %zu->%zu\n", h[source(e, h)].index,
- h[target(e, h)].index);
- }
-
- return bad_vertices;
-}
-
-static
-unique_ptr<VertLitInfo> findBestNormalSplit(const NGHolder &g,
- const RoseInGraph &vg,
- const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- assert(g.kind == NFA_OUTFIX || g.kind == NFA_INFIX || g.kind == NFA_SUFFIX);
- set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
-
- return findBestSplit(g, nullptr, false, cc.grey.minRoseLiteralLength,
- nullptr, &bad_vertices, false, cc);
-}
-
-static
-unique_ptr<VertLitInfo> findBestLastChanceSplit(const NGHolder &g,
- const RoseInGraph &vg,
- const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- assert(g.kind == NFA_OUTFIX || g.kind == NFA_INFIX || g.kind == NFA_SUFFIX);
- set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
-
- return findBestSplit(g, nullptr, false, cc.grey.minRoseLiteralLength,
- nullptr, &bad_vertices, true, cc);
-}
-
-static
-unique_ptr<VertLitInfo> findSimplePrefixSplit(const NGHolder &g,
- const CompileContext &cc) {
- DEBUG_PRINTF("looking for simple prefix split\n");
- bool anchored = !proper_out_degree(g.startDs, g);
- NFAVertex u = anchored ? g.start : g.startDs;
-
- if (out_degree(u, g) != 2) { /* startDs + succ */
- return nullptr;
- }
-
- NFAVertex v = NGHolder::null_vertex();
- for (NFAVertex t : adjacent_vertices_range(u, g)) {
- if (t != g.startDs) {
- assert(!v);
- v = t;
- }
- }
- assert(v);
-
- if (!anchored) {
- if (out_degree(g.start, g) > 2) {
- return nullptr;
- }
- if (out_degree(g.start, g) == 2 && !edge(g.start, v, g).second) {
- return nullptr;
- }
- }
-
- NFAVertex best_v = NGHolder::null_vertex();
- ue2_literal best_lit;
-
- u32 limit = cc.grey.maxHistoryAvailable;
- if (anchored) {
- LIMIT_TO_AT_MOST(&limit, cc.grey.maxAnchoredRegion);
- }
-
- ue2_literal curr_lit;
- for (u32 i = 0; i < limit; i++) {
- const auto &v_cr = g[v].char_reach;
- if (v_cr.count() == 1 || v_cr.isCaselessChar()) {
- curr_lit.push_back(v_cr.find_first(), v_cr.isCaselessChar());
- } else {
- curr_lit.clear();
- }
-
- if (curr_lit.length() > best_lit.length()) {
- best_lit = curr_lit;
- best_v = v;
- }
-
- if (out_degree(v, g) != 1) {
- break;
- }
- v = *adjacent_vertices(v, g).first;
- }
-
- if (best_lit.length() < cc.grey.minRoseLiteralLength) {
- return nullptr;
- }
-
- set<ue2_literal> best_lit_set({best_lit});
- if (bad_mixed_sensitivity(best_lit)) {
- sanitizeAndCompressAndScore(best_lit_set);
- }
-
- return ue2::make_unique<VertLitInfo>(best_v, best_lit_set, anchored, true);
-}
-
-static
-unique_ptr<VertLitInfo> findBestPrefixSplit(const NGHolder &g,
- const vector<NFAVertexDepth> &depths,
- const RoseInGraph &vg,
- const vector<RoseInEdge> &ee,
- bool last_chance,
- const CompileContext &cc) {
- assert(g.kind == NFA_PREFIX || g.kind == NFA_OUTFIX);
- set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
- auto rv = findBestSplit(g, &depths, true, cc.grey.minRoseLiteralLength,
- nullptr, &bad_vertices, last_chance, cc);
-
- /* large back edges may prevent us identifying anchored or transient cases
- * properly - use a simple walk instead */
- if (!rv || !(rv->creates_transient || rv->creates_anchored)) {
- auto rv2 = findSimplePrefixSplit(g, cc);
- if (rv2) {
- return rv2;
- }
- }
-
- return rv;
-}
-
-static
-unique_ptr<VertLitInfo> findBestCleanSplit(const NGHolder &g,
- const CompileContext &cc) {
- assert(g.kind != NFA_PREFIX);
- set<NFAVertex> cleanSplits;
- for (NFAVertex v : vertices_range(g)) {
- if (!g[v].char_reach.all() || !edge(v, v, g).second) {
- continue;
- }
- insert(&cleanSplits, inv_adjacent_vertices(v, g));
- cleanSplits.erase(v);
- }
- cleanSplits.erase(g.start);
- if (cleanSplits.empty()) {
- return nullptr;
- }
- return findBestSplit(g, nullptr, false, cc.grey.violetEarlyCleanLiteralLen,
- &cleanSplits, nullptr, false, cc);
-}
-
-static
-bool can_match(const NGHolder &g, const ue2_literal &lit, bool overhang_ok) {
- set<NFAVertex> curr, next;
- curr.insert(g.accept);
-
- for (auto it = lit.rbegin(); it != lit.rend(); ++it) {
- next.clear();
-
- for (auto v : curr) {
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (u == g.start) {
- if (overhang_ok) {
- DEBUG_PRINTF("bail\n");
- return true;
- } else {
- continue; /* it is not possible for a lhs literal to
- * overhang the start */
- }
- }
-
- const CharReach &cr = g[u].char_reach;
- if (!overlaps(*it, cr)) {
- continue;
- }
-
- next.insert(u);
- }
- }
-
- curr.swap(next);
- }
-
- return !curr.empty();
-}
-
-static
-bool splitRoseEdge(const NGHolder &base_graph, RoseInGraph &vg,
- const vector<RoseInEdge> &ee, const VertLitInfo &split) {
- const vector<NFAVertex> &splitters = split.vv;
- assert(!splitters.empty());
-
- shared_ptr<NGHolder> lhs = make_shared<NGHolder>();
- shared_ptr<NGHolder> rhs = make_shared<NGHolder>();
-
- unordered_map<NFAVertex, NFAVertex> lhs_map;
- unordered_map<NFAVertex, NFAVertex> rhs_map;
-
- splitGraph(base_graph, splitters, lhs.get(), &lhs_map, rhs.get(), &rhs_map);
- DEBUG_PRINTF("split %s:%zu into %s:%zu + %s:%zu\n",
- to_string(base_graph.kind).c_str(), num_vertices(base_graph),
- to_string(lhs->kind).c_str(), num_vertices(*lhs),
- to_string(rhs->kind).c_str(), num_vertices(*rhs));
-
- bool suffix = generates_callbacks(base_graph);
-
- if (is_triggered(base_graph)) {
- /* if we are already guarded, check if the split reduces the size of
- * the problem before continuing with the split */
- if (num_vertices(*lhs) >= num_vertices(base_graph)
- && !(suffix && isVacuous(*rhs))) {
- DEBUG_PRINTF("split's lhs is no smaller\n");
- return false;
- }
-
- if (num_vertices(*rhs) >= num_vertices(base_graph)) {
- DEBUG_PRINTF("split's rhs is no smaller\n");
- return false;
- }
- }
-
- bool do_accept = false;
- bool do_accept_eod = false;
- assert(rhs);
- if (isVacuous(*rhs) && suffix) {
- if (edge(rhs->start, rhs->accept, *rhs).second) {
- DEBUG_PRINTF("rhs has a cliche\n");
- do_accept = true;
- remove_edge(rhs->start, rhs->accept, *rhs);
- }
-
- if (edge(rhs->start, rhs->acceptEod, *rhs).second) {
- DEBUG_PRINTF("rhs has an eod cliche\n");
- do_accept_eod = true;
- remove_edge(rhs->start, rhs->acceptEod, *rhs);
- }
-
- renumber_edges(*rhs);
- }
-
- /* check if we still have a useful graph left over */
- bool do_norm = out_degree(rhs->start, *rhs) != 1;
-
- set<ReportID> splitter_reports;
- for (auto v : splitters) {
- insert(&splitter_reports, base_graph[v].reports);
- }
-
- /* find the targets of each source vertex; insertion_ordered_map used to
- * preserve deterministic ordering */
- insertion_ordered_map<RoseInVertex, vector<RoseInVertex>> images;
- for (const RoseInEdge &e : ee) {
- RoseInVertex src = source(e, vg);
- RoseInVertex dest = target(e, vg);
- images[src].push_back(dest);
- remove_edge(e, vg);
- }
-
- map<vector<RoseInVertex>, vector<RoseInVertex>> verts_by_image;
-
- for (const auto &m : images) {
- const auto &u = m.first;
- const auto &image = m.second;
-
- if (contains(verts_by_image, image)) {
- for (RoseInVertex v : verts_by_image[image]) {
- add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
- }
- continue;
- }
-
- for (const auto &lit : split.lit) {
- assert(!bad_mixed_sensitivity(lit));
-
- /* don't allow overhang in can_match() as literals should
- * correspond to the edge graph being split; overhanging the graph
- * would indicate a false path.*/
- if (!can_match(*lhs, lit, false)) {
- DEBUG_PRINTF("'%s' did not match lhs\n",
- escapeString(lit).c_str());
- continue;
- }
-
- DEBUG_PRINTF("best is '%s'\n", escapeString(lit).c_str());
- auto v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
- add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
-
- /* work out delay later */
- if (do_accept) {
- DEBUG_PRINTF("rhs has a cliche\n");
- auto tt = add_vertex(RoseInVertexProps::makeAccept(
- splitter_reports), vg);
- add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
- }
-
- if (do_accept_eod) {
- DEBUG_PRINTF("rhs has an eod cliche\n");
- auto tt = add_vertex(RoseInVertexProps::makeAcceptEod(
- splitter_reports), vg);
- add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
- }
-
- if (do_norm) {
- assert(out_degree(rhs->start, *rhs) > 1);
- for (RoseInVertex dest : image) {
- add_edge(v, dest, RoseInEdgeProps(rhs, 0U), vg);
- }
- }
- verts_by_image[image].push_back(v);
- }
- }
-
- assert(hasCorrectlyNumberedVertices(*rhs));
- assert(hasCorrectlyNumberedEdges(*rhs));
- assert(isCorrectlyTopped(*rhs));
- assert(hasCorrectlyNumberedVertices(*lhs));
- assert(hasCorrectlyNumberedEdges(*lhs));
- assert(isCorrectlyTopped(*lhs));
-
- return true;
-}
-
-#define MAX_NETFLOW_CUT_WIDTH 40 /* magic number is magic */
-#define MAX_LEN_2_LITERALS_PER_CUT 3
-
-static
-bool checkValidNetflowLits(NGHolder &h, const vector<u64a> &scores,
- const map<NFAEdge, set<ue2_literal>> &cut_lits,
- u32 min_allowed_length) {
- DEBUG_PRINTF("cut width %zu; min allowed %u\n", cut_lits.size(),
- min_allowed_length);
- if (cut_lits.size() > MAX_NETFLOW_CUT_WIDTH) {
- return false;
- }
-
- u32 len_2_count = 0;
-
- for (const auto &cut : cut_lits) {
- if (scores[h[cut.first].index] >= NO_LITERAL_AT_EDGE_SCORE) {
- DEBUG_PRINTF("cut uses a forbidden edge\n");
- return false;
- }
-
- if (min_len(cut.second) < min_allowed_length) {
- DEBUG_PRINTF("cut uses a bad literal\n");
- return false;
- }
-
- for (const auto &lit : cut.second) {
- if (lit.length() == 2) {
- len_2_count++;
- }
- }
- }
-
- if (len_2_count > MAX_LEN_2_LITERALS_PER_CUT) {
- return false;
- }
-
- return true;
-}
-
-static
-void splitEdgesByCut(NGHolder &h, RoseInGraph &vg,
- const vector<RoseInEdge> &to_cut,
- const vector<NFAEdge> &cut,
- const map<NFAEdge, set<ue2_literal>> &cut_lits) {
- DEBUG_PRINTF("splitting %s (%zu vertices)\n", to_string(h.kind).c_str(),
- num_vertices(h));
-
- /* create literal vertices and connect preds */
- unordered_set<RoseInVertex> done_sources;
- map<RoseInVertex, vector<pair<RoseInVertex, NFAVertex>>> verts_by_source;
- for (const RoseInEdge &ve : to_cut) {
- assert(&h == &*vg[ve].graph);
- RoseInVertex src = source(ve, vg);
- if (!done_sources.insert(src).second) {
- continue; /* already processed */
- }
-
- /* iterate over cut for determinism */
- for (const auto &e : cut) {
- NFAVertex prev_v = source(e, h);
- NFAVertex pivot = target(e, h);
-
- DEBUG_PRINTF("splitting on pivot %zu\n", h[pivot].index);
- unordered_map<NFAVertex, NFAVertex> temp_map;
- shared_ptr<NGHolder> new_lhs = make_shared<NGHolder>();
- splitLHS(h, pivot, new_lhs.get(), &temp_map);
-
- /* want to cut off paths to pivot from things other than the pivot -
- * makes a more svelte graphy */
- clear_in_edges(temp_map[pivot], *new_lhs);
- NFAEdge pivot_edge = add_edge(temp_map[prev_v], temp_map[pivot],
- *new_lhs);
- if (is_triggered(h) && prev_v == h.start) {
- (*new_lhs)[pivot_edge].tops.insert(DEFAULT_TOP);
- }
-
- pruneUseless(*new_lhs, false);
- renumber_vertices(*new_lhs);
- renumber_edges(*new_lhs);
-
- DEBUG_PRINTF(" into lhs %s (%zu vertices)\n",
- to_string(new_lhs->kind).c_str(),
- num_vertices(*new_lhs));
-
- assert(hasCorrectlyNumberedVertices(*new_lhs));
- assert(hasCorrectlyNumberedEdges(*new_lhs));
- assert(isCorrectlyTopped(*new_lhs));
-
- const set<ue2_literal> &lits = cut_lits.at(e);
- for (const auto &lit : lits) {
- if (!can_match(*new_lhs, lit, is_triggered(h))) {
- continue;
- }
-
- RoseInVertex v
- = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
-
- /* if this is a prefix/infix an edge directly to accept should
- * represent a false path as we have poisoned vertices covered
- * by the literals. */
- if (generates_callbacks(h)) {
- if (edge(pivot, h.accept, h).second) {
- DEBUG_PRINTF("adding acceptEod\n");
- /* literal has a direct connection to accept */
- const flat_set<ReportID> &reports = h[pivot].reports;
- auto tt = add_vertex(
- RoseInVertexProps::makeAccept(reports), vg);
- add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
- }
-
- if (edge(pivot, h.acceptEod, h).second) {
- assert(generates_callbacks(h));
- DEBUG_PRINTF("adding acceptEod\n");
- /* literal has a direct connection to accept */
- const flat_set<ReportID> &reports = h[pivot].reports;
- auto tt = add_vertex(
- RoseInVertexProps::makeAcceptEod(reports), vg);
- add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
- }
- }
-
- add_edge(src, v, RoseInEdgeProps(new_lhs, 0), vg);
- verts_by_source[src].push_back({v, pivot});
- }
- }
- }
-
- /* wire the literal vertices up to successors */
- map<vector<NFAVertex>, shared_ptr<NGHolder> > done_rhs;
- for (const RoseInEdge &ve : to_cut) {
- RoseInVertex src = source(ve, vg);
- RoseInVertex dest = target(ve, vg);
-
- /* iterate over cut for determinism */
- for (const auto &elem : verts_by_source[src]) {
- NFAVertex pivot = elem.second;
- RoseInVertex v = elem.first;
-
- vector<NFAVertex> adj;
- insert(&adj, adj.end(), adjacent_vertices(pivot, h));
- /* we can ignore presence of accept, accepteod in adj as it is best
- effort */
-
- if (!contains(done_rhs, adj)) {
- unordered_map<NFAVertex, NFAVertex> temp_map;
- shared_ptr<NGHolder> new_rhs = make_shared<NGHolder>();
- splitRHS(h, adj, new_rhs.get(), &temp_map);
- remove_edge(new_rhs->start, new_rhs->accept, *new_rhs);
- remove_edge(new_rhs->start, new_rhs->acceptEod, *new_rhs);
- renumber_edges(*new_rhs);
- DEBUG_PRINTF(" into rhs %s (%zu vertices)\n",
- to_string(new_rhs->kind).c_str(),
- num_vertices(*new_rhs));
- done_rhs.emplace(adj, new_rhs);
- assert(isCorrectlyTopped(*new_rhs));
- }
-
- assert(done_rhs[adj].get());
- shared_ptr<NGHolder> new_rhs = done_rhs[adj];
-
- assert(hasCorrectlyNumberedVertices(*new_rhs));
- assert(hasCorrectlyNumberedEdges(*new_rhs));
- assert(isCorrectlyTopped(*new_rhs));
-
- if (vg[dest].type == RIV_LITERAL
- && !can_match(*new_rhs, vg[dest].s, true)) {
- continue;
- }
-
- if (out_degree(new_rhs->start, *new_rhs) != 1) {
- add_edge(v, dest, RoseInEdgeProps(new_rhs, 0), vg);
- }
- }
-
- remove_edge(ve, vg);
- }
-}
-
-static
-bool doNetflowCut(NGHolder &h,
- const vector<NFAVertexDepth> *depths,
- RoseInGraph &vg,
- const vector<RoseInEdge> &ee, bool for_prefix,
- const Grey &grey, u32 min_allowed_length = 0U) {
- ENSURE_AT_LEAST(&min_allowed_length, grey.minRoseNetflowLiteralLength);
-
- DEBUG_PRINTF("doing netflow cut\n");
- /* TODO: we should really get literals/scores from the full graph as this
- * allows us to overlap with previous cuts. */
- assert(!ee.empty());
- assert(&h == &*vg[ee.front()].graph);
- assert(!for_prefix || depths);
-
- if (num_edges(h) > grey.maxRoseNetflowEdges) {
- /* We have a limit on this because scoring edges and running netflow
- * gets very slow for big graphs. */
- DEBUG_PRINTF("too many edges, skipping netflow cut\n");
- return false;
- }
-
- assert(hasCorrectlyNumberedVertices(h));
- assert(hasCorrectlyNumberedEdges(h));
-
- auto known_bad = poisonEdges(h, depths, vg, ee, for_prefix, grey);
-
- /* Step 1: Get scores for all edges */
- vector<u64a> scores = scoreEdges(h, known_bad); /* scores by edge_index */
-
- /* Step 2: Find cutset based on scores */
- vector<NFAEdge> cut = findMinCut(h, scores);
-
- /* Step 3: Get literals corresponding to cut edges */
- map<NFAEdge, set<ue2_literal>> cut_lits;
- for (const auto &e : cut) {
- set<ue2_literal> lits = getLiteralSet(h, e);
- sanitizeAndCompressAndScore(lits);
-
- cut_lits[e] = lits;
- }
-
- /* if literals are underlength bail or if it involves a forbidden edge*/
- if (!checkValidNetflowLits(h, scores, cut_lits, min_allowed_length)) {
- return false;
- }
- DEBUG_PRINTF("splitting\n");
-
- /* Step 4: Split graph based on cuts */
- splitEdgesByCut(h, vg, ee, cut, cut_lits);
-
- return true;
-}
-
-static
-bool deanchorIfNeeded(NGHolder &g) {
- DEBUG_PRINTF("hi\n");
- if (proper_out_degree(g.startDs, g)) {
- return false;
- }
-
- /* look for a non-special dot with a loop following start */
- set<NFAVertex> succ_g;
- insert(&succ_g, adjacent_vertices(g.start, g));
- succ_g.erase(g.startDs);
-
- for (auto v : adjacent_vertices_range(g.start, g)) {
- DEBUG_PRINTF("inspecting cand %zu || = %zu\n", g[v].index,
- g[v].char_reach.count());
-
- if (v == g.startDs || !g[v].char_reach.all()) {
- continue;
- }
-
- set<NFAVertex> succ_v;
- insert(&succ_v, adjacent_vertices(v, g));
-
- if (succ_v == succ_g) {
- DEBUG_PRINTF("found ^.*\n");
- for (auto succ : adjacent_vertices_range(g.start, g)) {
- if (succ == g.startDs) {
- continue;
- }
- add_edge(g.startDs, succ, g);
- }
- clear_vertex(v, g);
- remove_vertex(v, g);
- renumber_vertices(g);
- return true;
- }
-
- if (succ_g.size() == 1 && hasSelfLoop(v, g)) {
- DEBUG_PRINTF("found ^.+\n");
- add_edge(g.startDs, v, g);
- remove_edge(v, v, g);
- return true;
- }
- }
-
- return false;
-}
-
-static
-RoseInGraph populateTrivialGraph(const NGHolder &h) {
- RoseInGraph g;
- shared_ptr<NGHolder> root_g = cloneHolder(h);
- bool orig_anch = isAnchored(*root_g);
- orig_anch |= deanchorIfNeeded(*root_g);
-
- DEBUG_PRINTF("orig_anch %d\n", (int)orig_anch);
-
- auto start = add_vertex(RoseInVertexProps::makeStart(orig_anch), g);
- auto accept = add_vertex(RoseInVertexProps::makeAccept(set<ReportID>()), g);
-
- add_edge(start, accept, RoseInEdgeProps(root_g, 0), g);
-
- return g;
-}
-
-static
-void avoidOutfixes(RoseInGraph &vg, bool last_chance,
- const CompileContext &cc) {
- STAGE_DEBUG_PRINTF("AVOIDING OUTFIX\n");
- assert(num_vertices(vg) == 2);
- assert(num_edges(vg) == 1);
-
- RoseInEdge e = *edges(vg).first;
-
- NGHolder &h = *vg[e].graph;
- assert(isCorrectlyTopped(h));
-
- renumber_vertices(h);
- renumber_edges(h);
-
- unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, {e}, cc);
-
- if (split && splitRoseEdge(h, vg, {e}, *split)) {
- DEBUG_PRINTF("split on simple literal\n");
- return;
- }
-
- if (last_chance) {
- /* look for a prefix split as it allows us to accept very weak anchored
- * literals. */
- auto depths = calcDepths(h);
-
- split = findBestPrefixSplit(h, depths, vg, {e}, last_chance, cc);
-
- if (split && splitRoseEdge(h, vg, {e}, *split)) {
- DEBUG_PRINTF("split on simple literal\n");
- return;
- }
- }
-
- doNetflowCut(h, nullptr, vg, {e}, false, cc.grey);
-}
-
-static
-void removeRedundantPrefixes(RoseInGraph &g) {
- STAGE_DEBUG_PRINTF("REMOVING REDUNDANT PREFIXES\n");
-
- for (const RoseInEdge &e : edges_range(g)) {
- RoseInVertex s = source(e, g);
- RoseInVertex t = target(e, g);
-
- if (g[s].type != RIV_START || g[t].type != RIV_LITERAL) {
- continue;
- }
-
- if (!g[e].graph) {
- continue;
- }
-
- assert(!g[t].delay);
- const ue2_literal &lit = g[t].s;
-
- if (!literalIsWholeGraph(*g[e].graph, lit)) {
- DEBUG_PRINTF("not whole graph\n");
- continue;
- }
-
- if (!isFloating(*g[e].graph)) {
- DEBUG_PRINTF("not floating\n");
- continue;
- }
- g[e].graph.reset();
- }
-}
-
-static
-u32 maxDelay(const CompileContext &cc) {
- if (!cc.streaming) {
- return MO_INVALID_IDX;
- }
- return cc.grey.maxHistoryAvailable;
-}
-
-static
-void removeRedundantLiteralsFromPrefixes(RoseInGraph &g,
- const CompileContext &cc) {
- STAGE_DEBUG_PRINTF("REMOVING LITERALS FROM PREFIXES\n");
-
- vector<RoseInEdge> to_anchor;
- for (const RoseInEdge &e : edges_range(g)) {
- RoseInVertex s = source(e, g);
- RoseInVertex t = target(e, g);
-
- if (g[s].type != RIV_START && g[s].type != RIV_ANCHORED_START) {
- continue;
- }
-
- if (g[t].type != RIV_LITERAL) {
- continue;
- }
-
- if (!g[e].graph) {
- continue;
- }
-
- if (g[e].graph_lag) {
- /* already removed redundant parts of literals */
- continue;
- }
-
- if (g[e].dfa) {
- /* if we removed any more states, we would need to rebuild the
- * the dfa which can be time consuming. */
- continue;
- }
-
- assert(!g[t].delay);
- const ue2_literal &lit = g[t].s;
-
- DEBUG_PRINTF("removing states for literal: %s\n",
- dumpString(lit).c_str());
-
- unique_ptr<NGHolder> h = cloneHolder(*g[e].graph);
- const u32 max_delay = maxDelay(cc);
-
- u32 delay = removeTrailingLiteralStates(*h, lit, max_delay,
- false /* can't overhang start */);
-
- DEBUG_PRINTF("got delay %u (max allowed %u)\n", delay, max_delay);
-
- if (edge(h->startDs, h->accept, *h).second) {
- /* we should have delay == lit.length(), but in really complex
- * cases we may fail to identify that we can remove the whole
- * graph. Regardless, the fact that sds is wired to accept means the
- * graph serves no purpose. */
- DEBUG_PRINTF("whole graph\n");
- g[e].graph.reset();
- continue;
- }
-
- if (delay == lit.length() && edge(h->start, h->accept, *h).second
- && num_vertices(*h) == N_SPECIALS) {
- to_anchor.push_back(e);
- continue;
- }
-
- /* if we got here we should still have an interesting graph */
- assert(delay == max_delay || num_vertices(*h) > N_SPECIALS);
-
- if (delay && delay != MO_INVALID_IDX) {
- DEBUG_PRINTF("setting delay %u on lhs %p\n", delay, h.get());
-
- g[e].graph = move(h);
- g[e].graph_lag = delay;
- }
- }
-
- if (!to_anchor.empty()) {
- RoseInVertex anch = add_vertex(RoseInVertexProps::makeStart(true), g);
-
- for (RoseInEdge e : to_anchor) {
- DEBUG_PRINTF("rehoming to anchor\n");
- RoseInVertex v = target(e, g);
- add_edge(anch, v, g);
- remove_edge(e, g);
- }
- }
-}
-
-static
-bool isStarCliche(const NGHolder &g) {
- DEBUG_PRINTF("checking graph with %zu vertices\n", num_vertices(g));
-
- bool nonspecials_seen = false;
-
- for (auto v : vertices_range(g)) {
- if (is_special(v, g)) {
- continue;
- }
-
- if (nonspecials_seen) {
- return false;
- }
- nonspecials_seen = true;
-
- if (!g[v].char_reach.all()) {
- return false;
- }
-
- if (!hasSelfLoop(v, g)) {
- return false;
- }
- if (!edge(v, g.accept, g).second) {
- return false;
- }
- }
-
- if (!nonspecials_seen) {
- return false;
- }
-
- if (!edge(g.start, g.accept, g).second) {
- return false;
- }
-
- return true;
-}
-
-static
-void removeRedundantLiteralsFromInfix(const NGHolder &h, RoseInGraph &ig,
- const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- /* TODO: This could be better by not creating a separate graph for each
- * successor literal. This would require using distinct report ids and also
- * taking into account overlap of successor literals. */
-
- set<ue2_literal> preds;
- set<ue2_literal> succs;
- for (const RoseInEdge &e : ee) {
- RoseInVertex u = source(e, ig);
- assert(ig[u].type == RIV_LITERAL);
- assert(!ig[u].delay);
- preds.insert(ig[u].s);
-
- RoseInVertex v = target(e, ig);
- assert(ig[v].type == RIV_LITERAL);
- assert(!ig[v].delay);
- succs.insert(ig[v].s);
-
- if (ig[e].graph_lag) {
- /* already removed redundant parts of literals */
- return;
- }
-
- assert(!ig[e].dfa);
- }
-
- map<ue2_literal, pair<shared_ptr<NGHolder>, u32> > graphs; /* + delay */
-
- for (const ue2_literal &right : succs) {
- size_t max_overlap = 0;
- for (const ue2_literal &left : preds) {
- size_t overlap = maxOverlap(left, right, 0);
- ENSURE_AT_LEAST(&max_overlap, overlap);
- }
-
- u32 max_allowed_delay = right.length() - max_overlap;
-
- if (cc.streaming) {
- LIMIT_TO_AT_MOST(&max_allowed_delay, cc.grey.maxHistoryAvailable);
- }
-
- if (!max_allowed_delay) {
- continue;
- }
-
- shared_ptr<NGHolder> h_new = cloneHolder(h);
-
- u32 delay = removeTrailingLiteralStates(*h_new, right,
- max_allowed_delay);
-
- if (delay == MO_INVALID_IDX) {
- /* successor literal could not match infix -> ignore false path */
- assert(0);
- continue;
- }
-
- if (!delay) {
- /* unable to trim graph --> no point swapping to new holder */
- continue;
- }
-
- assert(isCorrectlyTopped(*h_new));
- graphs[right] = make_pair(h_new, delay);
- }
-
- for (const RoseInEdge &e : ee) {
- RoseInVertex v = target(e, ig);
- const ue2_literal &succ = ig[v].s;
- if (!contains(graphs, succ)) {
- continue;
- }
-
- ig[e].graph = graphs[succ].first;
- ig[e].graph_lag = graphs[succ].second;
-
- if (isStarCliche(*ig[e].graph)) {
- DEBUG_PRINTF("is a X star!\n");
- ig[e].graph.reset();
- ig[e].graph_lag = 0;
- }
- }
-}
-
-static
-void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
- const CompileContext &cc) {
- insertion_ordered_map<NGHolder *, vector<RoseInEdge>> infixes;
-
- for (const RoseInEdge &e : edges_range(g)) {
- RoseInVertex s = source(e, g);
- RoseInVertex t = target(e, g);
-
- if (g[s].type != RIV_LITERAL || g[t].type != RIV_LITERAL) {
- continue;
- }
-
- if (!g[e].graph) {
- continue;
- }
-
- assert(!g[t].delay);
- if (g[e].dfa) {
- /* if we removed any more states, we would need to rebuild the
- * the dfa which can be time consuming. */
- continue;
- }
-
- NGHolder *h = g[e].graph.get();
- infixes[h].push_back(e);
- }
-
- for (const auto &m : infixes) {
- NGHolder *h = m.first;
- const auto &edges = m.second;
- removeRedundantLiteralsFromInfix(*h, g, edges, cc);
- }
-}
-
-static
-void removeRedundantLiterals(RoseInGraph &g, const CompileContext &cc) {
- removeRedundantLiteralsFromPrefixes(g, cc);
- removeRedundantLiteralsFromInfixes(g, cc);
-}
-
-static
-RoseInVertex getStart(RoseInGraph &vg) {
- for (RoseInVertex v : vertices_range(vg)) {
- if (vg[v].type == RIV_START || vg[v].type == RIV_ANCHORED_START) {
- return v;
- }
- }
- assert(0);
- return RoseInGraph::null_vertex();
-}
-
-/**
- * Finds the initial accept vertex created to which suffix/outfixes are
- * attached.
- */
-static
-RoseInVertex getPrimaryAccept(RoseInGraph &vg) {
- for (RoseInVertex v : vertices_range(vg)) {
- if (vg[v].type == RIV_ACCEPT && vg[v].reports.empty()) {
- return v;
- }
- }
- assert(0);
- return RoseInGraph::null_vertex();
-}
-
-static
-bool willBeTransient(const depth &max_depth, const CompileContext &cc) {
- if (!cc.streaming) {
- return max_depth <= depth(ROSE_BLOCK_TRANSIENT_MAX_WIDTH);
- } else {
- return max_depth <= depth(cc.grey.maxHistoryAvailable + 1);
- }
-}
-
-static
-bool willBeAnchoredTable(const depth &max_depth, const Grey &grey) {
- return max_depth <= depth(grey.maxAnchoredRegion);
-}
-
-static
-unique_ptr<NGHolder> make_chain(u32 count) {
- assert(count);
-
- auto rv = std::make_unique<NGHolder>(NFA_INFIX);
-
- NGHolder &h = *rv;
-
- NFAVertex u = h.start;
- for (u32 i = 0; i < count; i++) {
- NFAVertex v = add_vertex(h);
- h[v].char_reach = CharReach::dot();
- add_edge(u, v, h);
- u = v;
- }
- h[u].reports.insert(0);
- add_edge(u, h.accept, h);
-
- setTops(h);
-
- return rv;
-}
-
-#define SHORT_TRIGGER_LEN 16
-
-static
-bool makeTransientFromLongLiteral(NGHolder &h, RoseInGraph &vg,
- const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- /* check max width and literal lengths to see if possible */
- size_t min_lit = (size_t)~0ULL;
- for (const RoseInEdge &e : ee) {
- RoseInVertex v = target(e, vg);
- LIMIT_TO_AT_MOST(&min_lit, vg[v].s.length());
- }
-
- if (min_lit <= SHORT_TRIGGER_LEN || min_lit >= UINT_MAX) {
- return false;
- }
-
- depth max_width = findMaxWidth(h);
-
- u32 delta = min_lit - SHORT_TRIGGER_LEN;
-
- if (!willBeTransient(max_width - depth(delta), cc)
- && !willBeAnchoredTable(max_width - depth(delta), cc.grey)) {
- return false;
- }
-
- DEBUG_PRINTF("candidate for splitting long literal (len %zu)\n", min_lit);
- DEBUG_PRINTF("delta = %u\n", delta);
-
- /* try split */
- map<RoseInVertex, shared_ptr<NGHolder> > graphs;
- for (const RoseInEdge &e : ee) {
- RoseInVertex v = target(e, vg);
-
- shared_ptr<NGHolder> h_new = cloneHolder(h);
-
- u32 delay = removeTrailingLiteralStates(*h_new, vg[v].s, delta);
-
- DEBUG_PRINTF("delay %u\n", delay);
-
- if (delay != delta) {
- DEBUG_PRINTF("unable to trim literal\n");
- return false;
- }
-
- if (in_degree(v, vg) != 1) {
- DEBUG_PRINTF("complicated\n");
- return false;
- }
-
- DEBUG_PRINTF("new mw = %u\n", (u32)findMaxWidth(*h_new));
- assert(willBeTransient(findMaxWidth(*h_new), cc)
- || willBeAnchoredTable(findMaxWidth(*h_new), cc.grey));
-
- assert(isCorrectlyTopped(*h_new));
- graphs[v] = h_new;
- }
-
- /* add .{repeats} from prefixes to long literals */
- for (const RoseInEdge &e : ee) {
- RoseInVertex s = source(e, vg);
- RoseInVertex t = target(e, vg);
-
- remove_edge(e, vg);
- const ue2_literal &orig_lit = vg[t].s;
-
- ue2_literal lit(orig_lit.begin(), orig_lit.end() - delta);
-
- ue2_literal lit2(orig_lit.end() - delta, orig_lit.end());
-
- assert(lit.length() + delta == orig_lit.length());
-
- vg[t].s = lit2;
-
- RoseInVertex v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
- add_edge(s, v, RoseInEdgeProps(graphs[t], 0), vg);
- add_edge(v, t, RoseInEdgeProps(make_chain(delta), 0), vg);
- }
-
- DEBUG_PRINTF("success\n");
- /* TODO: alter split point to avoid pathological splits */
- return true;
-}
-
-static
-void restoreTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
- u32 delay, const vector<NFAVertex> &preds) {
- assert(delay <= lit.length());
- assert(isCorrectlyTopped(g));
- DEBUG_PRINTF("adding on '%s' %u\n", dumpString(lit).c_str(), delay);
-
- NFAVertex prev = g.accept;
- auto it = lit.rbegin();
- while (delay--) {
- NFAVertex curr = add_vertex(g);
- assert(it != lit.rend());
- g[curr].char_reach = *it;
- add_edge(curr, prev, g);
- ++it;
- prev = curr;
- }
-
- for (auto v : preds) {
- NFAEdge e = add_edge_if_not_present(v, prev, g);
- if (v == g.start && is_triggered(g)) {
- g[e].tops.insert(DEFAULT_TOP);
- }
- }
-
- // Every predecessor of accept must have a report.
- set_report(g, 0);
-
- renumber_vertices(g);
- renumber_edges(g);
- assert(allMatchStatesHaveReports(g));
- assert(isCorrectlyTopped(g));
-}
-
-static
-void restoreTrailingLiteralStates(NGHolder &g,
- const vector<pair<ue2_literal, u32>> &lits) {
- vector<NFAVertex> preds;
- insert(&preds, preds.end(), inv_adjacent_vertices(g.accept, g));
- clear_in_edges(g.accept, g);
-
- for (auto v : preds) {
- g[v].reports.clear(); /* clear report from old accepts */
- }
-
- for (const auto &p : lits) {
- const ue2_literal &lit = p.first;
- u32 delay = p.second;
-
- restoreTrailingLiteralStates(g, lit, delay, preds);
- }
-}
-
-static
-bool improvePrefix(NGHolder &h, RoseInGraph &vg, const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- DEBUG_PRINTF("trying to improve prefix %p, %zu verts\n", &h,
- num_vertices(h));
- assert(isCorrectlyTopped(h));
-
- renumber_vertices(h);
- renumber_edges(h);
-
- auto depths = calcDepths(h);
-
- /* If the reason the prefix is not transient is due to a very long literal
- * following, we can make it transient by restricting ourselves to using
- * just the head of the literal. */
- if (makeTransientFromLongLiteral(h, vg, ee, cc)) {
- return true;
- }
-
- auto split = findBestPrefixSplit(h, depths, vg, ee, false, cc);
-
- if (split && (split->creates_transient || split->creates_anchored)
- && splitRoseEdge(h, vg, ee, *split)) {
- DEBUG_PRINTF("split on simple literal\n");
- return true;
- }
-
- /* large back edges may prevent us identifing anchored or transient cases
- * properly - use a simple walk instead */
-
- if (doNetflowCut(h, &depths, vg, ee, true, cc.grey)) {
- return true;
- }
-
- if (split && splitRoseEdge(h, vg, ee, *split)) {
- /* use the simple split even though it doesn't create a transient
- * prefix */
- DEBUG_PRINTF("split on simple literal\n");
- return true;
- }
-
- /* look for netflow cuts which don't produce good prefixes */
- if (doNetflowCut(h, &depths, vg, ee, false, cc.grey)) {
- return true;
- }
-
- if (ee.size() > 1) {
- DEBUG_PRINTF("split the prefix apart based on succ literals\n");
- unordered_map<shared_ptr<NGHolder>, vector<pair<RoseInEdge, u32> >,
+ }
+ }
+
+ auto cmp = LitComparator(g, seeking_anchored, seeking_transient,
+ last_chance);
+
+ unique_ptr<VertLitInfo> best = move(lits.back());
+ lits.pop_back();
+ while (!lits.empty()) {
+ if (cmp(best, lits.back())) {
+ best = move(lits.back());
+ }
+ lits.pop_back();
+ }
+
+ DEBUG_PRINTF("best is '%s' %zu a%d t%d\n",
+ dumpString(*best->lit.begin()).c_str(),
+ g[best->vv.front()].index,
+ depths ? (int)createsAnchoredLHS(g, best->vv, *depths, cc.grey) : 0,
+ depths ? (int)createsTransientLHS(g, best->vv, *depths, cc.grey) : 0);
+
+ return best;
+}
+
+static
+void poisonFromSuccessor(const NGHolder &h, const ue2_literal &succ,
+ bool overhang_ok, flat_set<NFAEdge> &bad) {
+ DEBUG_PRINTF("poisoning holder of size %zu, succ len %zu\n",
+ num_vertices(h), succ.length());
+
+ using EdgeSet = boost::dynamic_bitset<>;
+
+ const size_t edge_count = num_edges(h);
+ EdgeSet bad_edges(edge_count);
+
+ unordered_map<NFAVertex, EdgeSet> curr;
+ for (const auto &e : in_edges_range(h.accept, h)) {
+ auto &path_set = curr[source(e, h)];
+ if (path_set.empty()) {
+ path_set.resize(edge_count);
+ }
+ path_set.set(h[e].index);
+ }
+
+ unordered_map<NFAVertex, EdgeSet> next;
+ for (auto it = succ.rbegin(); it != succ.rend(); ++it) {
+ for (const auto &path : curr) {
+ NFAVertex u = path.first;
+ const auto &path_set = path.second;
+ if (u == h.start && overhang_ok) {
+ DEBUG_PRINTF("poisoning early %zu [overhang]\n",
+ path_set.count());
+ bad_edges |= path_set;
+ continue;
+ }
+ if (overlaps(h[u].char_reach, *it)) {
+ for (const auto &e : in_edges_range(u, h)) {
+ auto &new_path_set = next[source(e, h)];
+ if (new_path_set.empty()) {
+ new_path_set.resize(edge_count);
+ }
+ new_path_set |= path_set;
+ new_path_set.set(h[e].index);
+ }
+ }
+ }
+ DEBUG_PRINTF("succ char matches at %zu paths\n", next.size());
+ assert(overhang_ok || !curr.empty());
+ swap(curr, next);
+ next.clear();
+ }
+
+ assert(overhang_ok || !curr.empty());
+ for (const auto &path : curr) {
+ bad_edges |= path.second;
+ DEBUG_PRINTF("poisoning %zu vertices\n", path.second.count());
+ }
+
+ for (const auto &e : edges_range(h)) {
+ if (bad_edges.test(h[e].index)) {
+ bad.insert(e);
+ }
+ }
+}
+
+static
+void poisonForGoodPrefix(const NGHolder &h,
+ const vector<NFAVertexDepth> &depths,
+ flat_set<NFAEdge> &bad, const Grey &grey) {
+ for (const auto &v : vertices_range(h)) {
+ if (!createsAnchoredLHS(h, {v}, depths, grey)
+ && !createsTransientLHS(h, {v}, depths, grey)) {
+ insert(&bad, in_edges_range(v, h));
+ }
+ }
+}
+
+static UNUSED
+bool is_any_accept_type(RoseInVertexType t) {
+ return t == RIV_ACCEPT || t == RIV_ACCEPT_EOD;
+}
+
+static
+flat_set<NFAEdge> poisonEdges(const NGHolder &h,
+ const vector<NFAVertexDepth> *depths,
+ const RoseInGraph &vg, const vector<RoseInEdge> &ee,
+ bool for_prefix, const Grey &grey) {
+ DEBUG_PRINTF("poisoning edges %zu successor edges\n", ee.size());
+
+ /* poison edges covered by successor literal */
+
+ set<pair<ue2_literal, bool> > succs;
+ for (const RoseInEdge &ve : ee) {
+ if (vg[target(ve, vg)].type != RIV_LITERAL) {
+ /* nothing to poison in suffixes/outfixes */
+ assert(generates_callbacks(h));
+ assert(is_any_accept_type(vg[target(ve, vg)].type));
+ continue;
+ }
+ succs.insert({vg[target(ve, vg)].s,
+ vg[source(ve, vg)].type == RIV_LITERAL});
+
+ }
+
+ DEBUG_PRINTF("poisoning edges %zu successor literals\n", succs.size());
+
+ flat_set<NFAEdge> bad;
+ for (const auto &p : succs) {
+ poisonFromSuccessor(h, p.first, p.second, bad);
+ }
+
+ /* poison edges which don't significantly improve a prefix */
+
+ if (for_prefix) {
+ poisonForGoodPrefix(h, *depths, bad, grey);
+ }
+
+ return bad;
+}
+
+static
+set<NFAVertex> poisonVertices(const NGHolder &h, const RoseInGraph &vg,
+ const vector<RoseInEdge> &ee, const Grey &grey) {
+ flat_set<NFAEdge> bad_edges = poisonEdges(h, nullptr, vg, ee, false, grey);
+ set<NFAVertex> bad_vertices;
+ for (const NFAEdge &e : bad_edges) {
+ bad_vertices.insert(target(e, h));
+ DEBUG_PRINTF("bad: %zu->%zu\n", h[source(e, h)].index,
+ h[target(e, h)].index);
+ }
+
+ return bad_vertices;
+}
+
+static
+unique_ptr<VertLitInfo> findBestNormalSplit(const NGHolder &g,
+ const RoseInGraph &vg,
+ const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ assert(g.kind == NFA_OUTFIX || g.kind == NFA_INFIX || g.kind == NFA_SUFFIX);
+ set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
+
+ return findBestSplit(g, nullptr, false, cc.grey.minRoseLiteralLength,
+ nullptr, &bad_vertices, false, cc);
+}
+
+static
+unique_ptr<VertLitInfo> findBestLastChanceSplit(const NGHolder &g,
+ const RoseInGraph &vg,
+ const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ assert(g.kind == NFA_OUTFIX || g.kind == NFA_INFIX || g.kind == NFA_SUFFIX);
+ set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
+
+ return findBestSplit(g, nullptr, false, cc.grey.minRoseLiteralLength,
+ nullptr, &bad_vertices, true, cc);
+}
+
+static
+unique_ptr<VertLitInfo> findSimplePrefixSplit(const NGHolder &g,
+ const CompileContext &cc) {
+ DEBUG_PRINTF("looking for simple prefix split\n");
+ bool anchored = !proper_out_degree(g.startDs, g);
+ NFAVertex u = anchored ? g.start : g.startDs;
+
+ if (out_degree(u, g) != 2) { /* startDs + succ */
+ return nullptr;
+ }
+
+ NFAVertex v = NGHolder::null_vertex();
+ for (NFAVertex t : adjacent_vertices_range(u, g)) {
+ if (t != g.startDs) {
+ assert(!v);
+ v = t;
+ }
+ }
+ assert(v);
+
+ if (!anchored) {
+ if (out_degree(g.start, g) > 2) {
+ return nullptr;
+ }
+ if (out_degree(g.start, g) == 2 && !edge(g.start, v, g).second) {
+ return nullptr;
+ }
+ }
+
+ NFAVertex best_v = NGHolder::null_vertex();
+ ue2_literal best_lit;
+
+ u32 limit = cc.grey.maxHistoryAvailable;
+ if (anchored) {
+ LIMIT_TO_AT_MOST(&limit, cc.grey.maxAnchoredRegion);
+ }
+
+ ue2_literal curr_lit;
+ for (u32 i = 0; i < limit; i++) {
+ const auto &v_cr = g[v].char_reach;
+ if (v_cr.count() == 1 || v_cr.isCaselessChar()) {
+ curr_lit.push_back(v_cr.find_first(), v_cr.isCaselessChar());
+ } else {
+ curr_lit.clear();
+ }
+
+ if (curr_lit.length() > best_lit.length()) {
+ best_lit = curr_lit;
+ best_v = v;
+ }
+
+ if (out_degree(v, g) != 1) {
+ break;
+ }
+ v = *adjacent_vertices(v, g).first;
+ }
+
+ if (best_lit.length() < cc.grey.minRoseLiteralLength) {
+ return nullptr;
+ }
+
+ set<ue2_literal> best_lit_set({best_lit});
+ if (bad_mixed_sensitivity(best_lit)) {
+ sanitizeAndCompressAndScore(best_lit_set);
+ }
+
+ return ue2::make_unique<VertLitInfo>(best_v, best_lit_set, anchored, true);
+}
+
+static
+unique_ptr<VertLitInfo> findBestPrefixSplit(const NGHolder &g,
+ const vector<NFAVertexDepth> &depths,
+ const RoseInGraph &vg,
+ const vector<RoseInEdge> &ee,
+ bool last_chance,
+ const CompileContext &cc) {
+ assert(g.kind == NFA_PREFIX || g.kind == NFA_OUTFIX);
+ set<NFAVertex> bad_vertices = poisonVertices(g, vg, ee, cc.grey);
+ auto rv = findBestSplit(g, &depths, true, cc.grey.minRoseLiteralLength,
+ nullptr, &bad_vertices, last_chance, cc);
+
+ /* large back edges may prevent us identifying anchored or transient cases
+ * properly - use a simple walk instead */
+ if (!rv || !(rv->creates_transient || rv->creates_anchored)) {
+ auto rv2 = findSimplePrefixSplit(g, cc);
+ if (rv2) {
+ return rv2;
+ }
+ }
+
+ return rv;
+}
+
+static
+unique_ptr<VertLitInfo> findBestCleanSplit(const NGHolder &g,
+ const CompileContext &cc) {
+ assert(g.kind != NFA_PREFIX);
+ set<NFAVertex> cleanSplits;
+ for (NFAVertex v : vertices_range(g)) {
+ if (!g[v].char_reach.all() || !edge(v, v, g).second) {
+ continue;
+ }
+ insert(&cleanSplits, inv_adjacent_vertices(v, g));
+ cleanSplits.erase(v);
+ }
+ cleanSplits.erase(g.start);
+ if (cleanSplits.empty()) {
+ return nullptr;
+ }
+ return findBestSplit(g, nullptr, false, cc.grey.violetEarlyCleanLiteralLen,
+ &cleanSplits, nullptr, false, cc);
+}
+
+static
+bool can_match(const NGHolder &g, const ue2_literal &lit, bool overhang_ok) {
+ set<NFAVertex> curr, next;
+ curr.insert(g.accept);
+
+ for (auto it = lit.rbegin(); it != lit.rend(); ++it) {
+ next.clear();
+
+ for (auto v : curr) {
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (u == g.start) {
+ if (overhang_ok) {
+ DEBUG_PRINTF("bail\n");
+ return true;
+ } else {
+ continue; /* it is not possible for a lhs literal to
+ * overhang the start */
+ }
+ }
+
+ const CharReach &cr = g[u].char_reach;
+ if (!overlaps(*it, cr)) {
+ continue;
+ }
+
+ next.insert(u);
+ }
+ }
+
+ curr.swap(next);
+ }
+
+ return !curr.empty();
+}
+
+static
+bool splitRoseEdge(const NGHolder &base_graph, RoseInGraph &vg,
+ const vector<RoseInEdge> &ee, const VertLitInfo &split) {
+ const vector<NFAVertex> &splitters = split.vv;
+ assert(!splitters.empty());
+
+ shared_ptr<NGHolder> lhs = make_shared<NGHolder>();
+ shared_ptr<NGHolder> rhs = make_shared<NGHolder>();
+
+ unordered_map<NFAVertex, NFAVertex> lhs_map;
+ unordered_map<NFAVertex, NFAVertex> rhs_map;
+
+ splitGraph(base_graph, splitters, lhs.get(), &lhs_map, rhs.get(), &rhs_map);
+ DEBUG_PRINTF("split %s:%zu into %s:%zu + %s:%zu\n",
+ to_string(base_graph.kind).c_str(), num_vertices(base_graph),
+ to_string(lhs->kind).c_str(), num_vertices(*lhs),
+ to_string(rhs->kind).c_str(), num_vertices(*rhs));
+
+ bool suffix = generates_callbacks(base_graph);
+
+ if (is_triggered(base_graph)) {
+ /* if we are already guarded, check if the split reduces the size of
+ * the problem before continuing with the split */
+ if (num_vertices(*lhs) >= num_vertices(base_graph)
+ && !(suffix && isVacuous(*rhs))) {
+ DEBUG_PRINTF("split's lhs is no smaller\n");
+ return false;
+ }
+
+ if (num_vertices(*rhs) >= num_vertices(base_graph)) {
+ DEBUG_PRINTF("split's rhs is no smaller\n");
+ return false;
+ }
+ }
+
+ bool do_accept = false;
+ bool do_accept_eod = false;
+ assert(rhs);
+ if (isVacuous(*rhs) && suffix) {
+ if (edge(rhs->start, rhs->accept, *rhs).second) {
+ DEBUG_PRINTF("rhs has a cliche\n");
+ do_accept = true;
+ remove_edge(rhs->start, rhs->accept, *rhs);
+ }
+
+ if (edge(rhs->start, rhs->acceptEod, *rhs).second) {
+ DEBUG_PRINTF("rhs has an eod cliche\n");
+ do_accept_eod = true;
+ remove_edge(rhs->start, rhs->acceptEod, *rhs);
+ }
+
+ renumber_edges(*rhs);
+ }
+
+ /* check if we still have a useful graph left over */
+ bool do_norm = out_degree(rhs->start, *rhs) != 1;
+
+ set<ReportID> splitter_reports;
+ for (auto v : splitters) {
+ insert(&splitter_reports, base_graph[v].reports);
+ }
+
+ /* find the targets of each source vertex; insertion_ordered_map used to
+ * preserve deterministic ordering */
+ insertion_ordered_map<RoseInVertex, vector<RoseInVertex>> images;
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex src = source(e, vg);
+ RoseInVertex dest = target(e, vg);
+ images[src].push_back(dest);
+ remove_edge(e, vg);
+ }
+
+ map<vector<RoseInVertex>, vector<RoseInVertex>> verts_by_image;
+
+ for (const auto &m : images) {
+ const auto &u = m.first;
+ const auto &image = m.second;
+
+ if (contains(verts_by_image, image)) {
+ for (RoseInVertex v : verts_by_image[image]) {
+ add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
+ }
+ continue;
+ }
+
+ for (const auto &lit : split.lit) {
+ assert(!bad_mixed_sensitivity(lit));
+
+ /* don't allow overhang in can_match() as literals should
+ * correspond to the edge graph being split; overhanging the graph
+ * would indicate a false path.*/
+ if (!can_match(*lhs, lit, false)) {
+ DEBUG_PRINTF("'%s' did not match lhs\n",
+ escapeString(lit).c_str());
+ continue;
+ }
+
+ DEBUG_PRINTF("best is '%s'\n", escapeString(lit).c_str());
+ auto v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
+ add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
+
+ /* work out delay later */
+ if (do_accept) {
+ DEBUG_PRINTF("rhs has a cliche\n");
+ auto tt = add_vertex(RoseInVertexProps::makeAccept(
+ splitter_reports), vg);
+ add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
+ }
+
+ if (do_accept_eod) {
+ DEBUG_PRINTF("rhs has an eod cliche\n");
+ auto tt = add_vertex(RoseInVertexProps::makeAcceptEod(
+ splitter_reports), vg);
+ add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
+ }
+
+ if (do_norm) {
+ assert(out_degree(rhs->start, *rhs) > 1);
+ for (RoseInVertex dest : image) {
+ add_edge(v, dest, RoseInEdgeProps(rhs, 0U), vg);
+ }
+ }
+ verts_by_image[image].push_back(v);
+ }
+ }
+
+ assert(hasCorrectlyNumberedVertices(*rhs));
+ assert(hasCorrectlyNumberedEdges(*rhs));
+ assert(isCorrectlyTopped(*rhs));
+ assert(hasCorrectlyNumberedVertices(*lhs));
+ assert(hasCorrectlyNumberedEdges(*lhs));
+ assert(isCorrectlyTopped(*lhs));
+
+ return true;
+}
+
+#define MAX_NETFLOW_CUT_WIDTH 40 /* magic number is magic */
+#define MAX_LEN_2_LITERALS_PER_CUT 3
+
+static
+bool checkValidNetflowLits(NGHolder &h, const vector<u64a> &scores,
+ const map<NFAEdge, set<ue2_literal>> &cut_lits,
+ u32 min_allowed_length) {
+ DEBUG_PRINTF("cut width %zu; min allowed %u\n", cut_lits.size(),
+ min_allowed_length);
+ if (cut_lits.size() > MAX_NETFLOW_CUT_WIDTH) {
+ return false;
+ }
+
+ u32 len_2_count = 0;
+
+ for (const auto &cut : cut_lits) {
+ if (scores[h[cut.first].index] >= NO_LITERAL_AT_EDGE_SCORE) {
+ DEBUG_PRINTF("cut uses a forbidden edge\n");
+ return false;
+ }
+
+ if (min_len(cut.second) < min_allowed_length) {
+ DEBUG_PRINTF("cut uses a bad literal\n");
+ return false;
+ }
+
+ for (const auto &lit : cut.second) {
+ if (lit.length() == 2) {
+ len_2_count++;
+ }
+ }
+ }
+
+ if (len_2_count > MAX_LEN_2_LITERALS_PER_CUT) {
+ return false;
+ }
+
+ return true;
+}
+
+static
+void splitEdgesByCut(NGHolder &h, RoseInGraph &vg,
+ const vector<RoseInEdge> &to_cut,
+ const vector<NFAEdge> &cut,
+ const map<NFAEdge, set<ue2_literal>> &cut_lits) {
+ DEBUG_PRINTF("splitting %s (%zu vertices)\n", to_string(h.kind).c_str(),
+ num_vertices(h));
+
+ /* create literal vertices and connect preds */
+ unordered_set<RoseInVertex> done_sources;
+ map<RoseInVertex, vector<pair<RoseInVertex, NFAVertex>>> verts_by_source;
+ for (const RoseInEdge &ve : to_cut) {
+ assert(&h == &*vg[ve].graph);
+ RoseInVertex src = source(ve, vg);
+ if (!done_sources.insert(src).second) {
+ continue; /* already processed */
+ }
+
+ /* iterate over cut for determinism */
+ for (const auto &e : cut) {
+ NFAVertex prev_v = source(e, h);
+ NFAVertex pivot = target(e, h);
+
+ DEBUG_PRINTF("splitting on pivot %zu\n", h[pivot].index);
+ unordered_map<NFAVertex, NFAVertex> temp_map;
+ shared_ptr<NGHolder> new_lhs = make_shared<NGHolder>();
+ splitLHS(h, pivot, new_lhs.get(), &temp_map);
+
+ /* want to cut off paths to pivot from things other than the pivot -
+ * makes a more svelte graphy */
+ clear_in_edges(temp_map[pivot], *new_lhs);
+ NFAEdge pivot_edge = add_edge(temp_map[prev_v], temp_map[pivot],
+ *new_lhs);
+ if (is_triggered(h) && prev_v == h.start) {
+ (*new_lhs)[pivot_edge].tops.insert(DEFAULT_TOP);
+ }
+
+ pruneUseless(*new_lhs, false);
+ renumber_vertices(*new_lhs);
+ renumber_edges(*new_lhs);
+
+ DEBUG_PRINTF(" into lhs %s (%zu vertices)\n",
+ to_string(new_lhs->kind).c_str(),
+ num_vertices(*new_lhs));
+
+ assert(hasCorrectlyNumberedVertices(*new_lhs));
+ assert(hasCorrectlyNumberedEdges(*new_lhs));
+ assert(isCorrectlyTopped(*new_lhs));
+
+ const set<ue2_literal> &lits = cut_lits.at(e);
+ for (const auto &lit : lits) {
+ if (!can_match(*new_lhs, lit, is_triggered(h))) {
+ continue;
+ }
+
+ RoseInVertex v
+ = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
+
+ /* if this is a prefix/infix an edge directly to accept should
+ * represent a false path as we have poisoned vertices covered
+ * by the literals. */
+ if (generates_callbacks(h)) {
+ if (edge(pivot, h.accept, h).second) {
+ DEBUG_PRINTF("adding acceptEod\n");
+ /* literal has a direct connection to accept */
+ const flat_set<ReportID> &reports = h[pivot].reports;
+ auto tt = add_vertex(
+ RoseInVertexProps::makeAccept(reports), vg);
+ add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
+ }
+
+ if (edge(pivot, h.acceptEod, h).second) {
+ assert(generates_callbacks(h));
+ DEBUG_PRINTF("adding acceptEod\n");
+ /* literal has a direct connection to accept */
+ const flat_set<ReportID> &reports = h[pivot].reports;
+ auto tt = add_vertex(
+ RoseInVertexProps::makeAcceptEod(reports), vg);
+ add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
+ }
+ }
+
+ add_edge(src, v, RoseInEdgeProps(new_lhs, 0), vg);
+ verts_by_source[src].push_back({v, pivot});
+ }
+ }
+ }
+
+ /* wire the literal vertices up to successors */
+ map<vector<NFAVertex>, shared_ptr<NGHolder> > done_rhs;
+ for (const RoseInEdge &ve : to_cut) {
+ RoseInVertex src = source(ve, vg);
+ RoseInVertex dest = target(ve, vg);
+
+ /* iterate over cut for determinism */
+ for (const auto &elem : verts_by_source[src]) {
+ NFAVertex pivot = elem.second;
+ RoseInVertex v = elem.first;
+
+ vector<NFAVertex> adj;
+ insert(&adj, adj.end(), adjacent_vertices(pivot, h));
+ /* we can ignore presence of accept, accepteod in adj as it is best
+ effort */
+
+ if (!contains(done_rhs, adj)) {
+ unordered_map<NFAVertex, NFAVertex> temp_map;
+ shared_ptr<NGHolder> new_rhs = make_shared<NGHolder>();
+ splitRHS(h, adj, new_rhs.get(), &temp_map);
+ remove_edge(new_rhs->start, new_rhs->accept, *new_rhs);
+ remove_edge(new_rhs->start, new_rhs->acceptEod, *new_rhs);
+ renumber_edges(*new_rhs);
+ DEBUG_PRINTF(" into rhs %s (%zu vertices)\n",
+ to_string(new_rhs->kind).c_str(),
+ num_vertices(*new_rhs));
+ done_rhs.emplace(adj, new_rhs);
+ assert(isCorrectlyTopped(*new_rhs));
+ }
+
+ assert(done_rhs[adj].get());
+ shared_ptr<NGHolder> new_rhs = done_rhs[adj];
+
+ assert(hasCorrectlyNumberedVertices(*new_rhs));
+ assert(hasCorrectlyNumberedEdges(*new_rhs));
+ assert(isCorrectlyTopped(*new_rhs));
+
+ if (vg[dest].type == RIV_LITERAL
+ && !can_match(*new_rhs, vg[dest].s, true)) {
+ continue;
+ }
+
+ if (out_degree(new_rhs->start, *new_rhs) != 1) {
+ add_edge(v, dest, RoseInEdgeProps(new_rhs, 0), vg);
+ }
+ }
+
+ remove_edge(ve, vg);
+ }
+}
+
+static
+bool doNetflowCut(NGHolder &h,
+ const vector<NFAVertexDepth> *depths,
+ RoseInGraph &vg,
+ const vector<RoseInEdge> &ee, bool for_prefix,
+ const Grey &grey, u32 min_allowed_length = 0U) {
+ ENSURE_AT_LEAST(&min_allowed_length, grey.minRoseNetflowLiteralLength);
+
+ DEBUG_PRINTF("doing netflow cut\n");
+ /* TODO: we should really get literals/scores from the full graph as this
+ * allows us to overlap with previous cuts. */
+ assert(!ee.empty());
+ assert(&h == &*vg[ee.front()].graph);
+ assert(!for_prefix || depths);
+
+ if (num_edges(h) > grey.maxRoseNetflowEdges) {
+ /* We have a limit on this because scoring edges and running netflow
+ * gets very slow for big graphs. */
+ DEBUG_PRINTF("too many edges, skipping netflow cut\n");
+ return false;
+ }
+
+ assert(hasCorrectlyNumberedVertices(h));
+ assert(hasCorrectlyNumberedEdges(h));
+
+ auto known_bad = poisonEdges(h, depths, vg, ee, for_prefix, grey);
+
+ /* Step 1: Get scores for all edges */
+ vector<u64a> scores = scoreEdges(h, known_bad); /* scores by edge_index */
+
+ /* Step 2: Find cutset based on scores */
+ vector<NFAEdge> cut = findMinCut(h, scores);
+
+ /* Step 3: Get literals corresponding to cut edges */
+ map<NFAEdge, set<ue2_literal>> cut_lits;
+ for (const auto &e : cut) {
+ set<ue2_literal> lits = getLiteralSet(h, e);
+ sanitizeAndCompressAndScore(lits);
+
+ cut_lits[e] = lits;
+ }
+
+ /* if literals are underlength bail or if it involves a forbidden edge*/
+ if (!checkValidNetflowLits(h, scores, cut_lits, min_allowed_length)) {
+ return false;
+ }
+ DEBUG_PRINTF("splitting\n");
+
+ /* Step 4: Split graph based on cuts */
+ splitEdgesByCut(h, vg, ee, cut, cut_lits);
+
+ return true;
+}
+
+static
+bool deanchorIfNeeded(NGHolder &g) {
+ DEBUG_PRINTF("hi\n");
+ if (proper_out_degree(g.startDs, g)) {
+ return false;
+ }
+
+ /* look for a non-special dot with a loop following start */
+ set<NFAVertex> succ_g;
+ insert(&succ_g, adjacent_vertices(g.start, g));
+ succ_g.erase(g.startDs);
+
+ for (auto v : adjacent_vertices_range(g.start, g)) {
+ DEBUG_PRINTF("inspecting cand %zu || = %zu\n", g[v].index,
+ g[v].char_reach.count());
+
+ if (v == g.startDs || !g[v].char_reach.all()) {
+ continue;
+ }
+
+ set<NFAVertex> succ_v;
+ insert(&succ_v, adjacent_vertices(v, g));
+
+ if (succ_v == succ_g) {
+ DEBUG_PRINTF("found ^.*\n");
+ for (auto succ : adjacent_vertices_range(g.start, g)) {
+ if (succ == g.startDs) {
+ continue;
+ }
+ add_edge(g.startDs, succ, g);
+ }
+ clear_vertex(v, g);
+ remove_vertex(v, g);
+ renumber_vertices(g);
+ return true;
+ }
+
+ if (succ_g.size() == 1 && hasSelfLoop(v, g)) {
+ DEBUG_PRINTF("found ^.+\n");
+ add_edge(g.startDs, v, g);
+ remove_edge(v, v, g);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static
+RoseInGraph populateTrivialGraph(const NGHolder &h) {
+ RoseInGraph g;
+ shared_ptr<NGHolder> root_g = cloneHolder(h);
+ bool orig_anch = isAnchored(*root_g);
+ orig_anch |= deanchorIfNeeded(*root_g);
+
+ DEBUG_PRINTF("orig_anch %d\n", (int)orig_anch);
+
+ auto start = add_vertex(RoseInVertexProps::makeStart(orig_anch), g);
+ auto accept = add_vertex(RoseInVertexProps::makeAccept(set<ReportID>()), g);
+
+ add_edge(start, accept, RoseInEdgeProps(root_g, 0), g);
+
+ return g;
+}
+
+static
+void avoidOutfixes(RoseInGraph &vg, bool last_chance,
+ const CompileContext &cc) {
+ STAGE_DEBUG_PRINTF("AVOIDING OUTFIX\n");
+ assert(num_vertices(vg) == 2);
+ assert(num_edges(vg) == 1);
+
+ RoseInEdge e = *edges(vg).first;
+
+ NGHolder &h = *vg[e].graph;
+ assert(isCorrectlyTopped(h));
+
+ renumber_vertices(h);
+ renumber_edges(h);
+
+ unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, {e}, cc);
+
+ if (split && splitRoseEdge(h, vg, {e}, *split)) {
+ DEBUG_PRINTF("split on simple literal\n");
+ return;
+ }
+
+ if (last_chance) {
+ /* look for a prefix split as it allows us to accept very weak anchored
+ * literals. */
+ auto depths = calcDepths(h);
+
+ split = findBestPrefixSplit(h, depths, vg, {e}, last_chance, cc);
+
+ if (split && splitRoseEdge(h, vg, {e}, *split)) {
+ DEBUG_PRINTF("split on simple literal\n");
+ return;
+ }
+ }
+
+ doNetflowCut(h, nullptr, vg, {e}, false, cc.grey);
+}
+
+static
+void removeRedundantPrefixes(RoseInGraph &g) {
+ STAGE_DEBUG_PRINTF("REMOVING REDUNDANT PREFIXES\n");
+
+ for (const RoseInEdge &e : edges_range(g)) {
+ RoseInVertex s = source(e, g);
+ RoseInVertex t = target(e, g);
+
+ if (g[s].type != RIV_START || g[t].type != RIV_LITERAL) {
+ continue;
+ }
+
+ if (!g[e].graph) {
+ continue;
+ }
+
+ assert(!g[t].delay);
+ const ue2_literal &lit = g[t].s;
+
+ if (!literalIsWholeGraph(*g[e].graph, lit)) {
+ DEBUG_PRINTF("not whole graph\n");
+ continue;
+ }
+
+ if (!isFloating(*g[e].graph)) {
+ DEBUG_PRINTF("not floating\n");
+ continue;
+ }
+ g[e].graph.reset();
+ }
+}
+
+static
+u32 maxDelay(const CompileContext &cc) {
+ if (!cc.streaming) {
+ return MO_INVALID_IDX;
+ }
+ return cc.grey.maxHistoryAvailable;
+}
+
+static
+void removeRedundantLiteralsFromPrefixes(RoseInGraph &g,
+ const CompileContext &cc) {
+ STAGE_DEBUG_PRINTF("REMOVING LITERALS FROM PREFIXES\n");
+
+ vector<RoseInEdge> to_anchor;
+ for (const RoseInEdge &e : edges_range(g)) {
+ RoseInVertex s = source(e, g);
+ RoseInVertex t = target(e, g);
+
+ if (g[s].type != RIV_START && g[s].type != RIV_ANCHORED_START) {
+ continue;
+ }
+
+ if (g[t].type != RIV_LITERAL) {
+ continue;
+ }
+
+ if (!g[e].graph) {
+ continue;
+ }
+
+ if (g[e].graph_lag) {
+ /* already removed redundant parts of literals */
+ continue;
+ }
+
+ if (g[e].dfa) {
+ /* if we removed any more states, we would need to rebuild the
+ * the dfa which can be time consuming. */
+ continue;
+ }
+
+ assert(!g[t].delay);
+ const ue2_literal &lit = g[t].s;
+
+ DEBUG_PRINTF("removing states for literal: %s\n",
+ dumpString(lit).c_str());
+
+ unique_ptr<NGHolder> h = cloneHolder(*g[e].graph);
+ const u32 max_delay = maxDelay(cc);
+
+ u32 delay = removeTrailingLiteralStates(*h, lit, max_delay,
+ false /* can't overhang start */);
+
+ DEBUG_PRINTF("got delay %u (max allowed %u)\n", delay, max_delay);
+
+ if (edge(h->startDs, h->accept, *h).second) {
+ /* we should have delay == lit.length(), but in really complex
+ * cases we may fail to identify that we can remove the whole
+ * graph. Regardless, the fact that sds is wired to accept means the
+ * graph serves no purpose. */
+ DEBUG_PRINTF("whole graph\n");
+ g[e].graph.reset();
+ continue;
+ }
+
+ if (delay == lit.length() && edge(h->start, h->accept, *h).second
+ && num_vertices(*h) == N_SPECIALS) {
+ to_anchor.push_back(e);
+ continue;
+ }
+
+ /* if we got here we should still have an interesting graph */
+ assert(delay == max_delay || num_vertices(*h) > N_SPECIALS);
+
+ if (delay && delay != MO_INVALID_IDX) {
+ DEBUG_PRINTF("setting delay %u on lhs %p\n", delay, h.get());
+
+ g[e].graph = move(h);
+ g[e].graph_lag = delay;
+ }
+ }
+
+ if (!to_anchor.empty()) {
+ RoseInVertex anch = add_vertex(RoseInVertexProps::makeStart(true), g);
+
+ for (RoseInEdge e : to_anchor) {
+ DEBUG_PRINTF("rehoming to anchor\n");
+ RoseInVertex v = target(e, g);
+ add_edge(anch, v, g);
+ remove_edge(e, g);
+ }
+ }
+}
+
+static
+bool isStarCliche(const NGHolder &g) {
+ DEBUG_PRINTF("checking graph with %zu vertices\n", num_vertices(g));
+
+ bool nonspecials_seen = false;
+
+ for (auto v : vertices_range(g)) {
+ if (is_special(v, g)) {
+ continue;
+ }
+
+ if (nonspecials_seen) {
+ return false;
+ }
+ nonspecials_seen = true;
+
+ if (!g[v].char_reach.all()) {
+ return false;
+ }
+
+ if (!hasSelfLoop(v, g)) {
+ return false;
+ }
+ if (!edge(v, g.accept, g).second) {
+ return false;
+ }
+ }
+
+ if (!nonspecials_seen) {
+ return false;
+ }
+
+ if (!edge(g.start, g.accept, g).second) {
+ return false;
+ }
+
+ return true;
+}
+
+static
+void removeRedundantLiteralsFromInfix(const NGHolder &h, RoseInGraph &ig,
+ const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ /* TODO: This could be better by not creating a separate graph for each
+ * successor literal. This would require using distinct report ids and also
+ * taking into account overlap of successor literals. */
+
+ set<ue2_literal> preds;
+ set<ue2_literal> succs;
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex u = source(e, ig);
+ assert(ig[u].type == RIV_LITERAL);
+ assert(!ig[u].delay);
+ preds.insert(ig[u].s);
+
+ RoseInVertex v = target(e, ig);
+ assert(ig[v].type == RIV_LITERAL);
+ assert(!ig[v].delay);
+ succs.insert(ig[v].s);
+
+ if (ig[e].graph_lag) {
+ /* already removed redundant parts of literals */
+ return;
+ }
+
+ assert(!ig[e].dfa);
+ }
+
+ map<ue2_literal, pair<shared_ptr<NGHolder>, u32> > graphs; /* + delay */
+
+ for (const ue2_literal &right : succs) {
+ size_t max_overlap = 0;
+ for (const ue2_literal &left : preds) {
+ size_t overlap = maxOverlap(left, right, 0);
+ ENSURE_AT_LEAST(&max_overlap, overlap);
+ }
+
+ u32 max_allowed_delay = right.length() - max_overlap;
+
+ if (cc.streaming) {
+ LIMIT_TO_AT_MOST(&max_allowed_delay, cc.grey.maxHistoryAvailable);
+ }
+
+ if (!max_allowed_delay) {
+ continue;
+ }
+
+ shared_ptr<NGHolder> h_new = cloneHolder(h);
+
+ u32 delay = removeTrailingLiteralStates(*h_new, right,
+ max_allowed_delay);
+
+ if (delay == MO_INVALID_IDX) {
+ /* successor literal could not match infix -> ignore false path */
+ assert(0);
+ continue;
+ }
+
+ if (!delay) {
+ /* unable to trim graph --> no point swapping to new holder */
+ continue;
+ }
+
+ assert(isCorrectlyTopped(*h_new));
+ graphs[right] = make_pair(h_new, delay);
+ }
+
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex v = target(e, ig);
+ const ue2_literal &succ = ig[v].s;
+ if (!contains(graphs, succ)) {
+ continue;
+ }
+
+ ig[e].graph = graphs[succ].first;
+ ig[e].graph_lag = graphs[succ].second;
+
+ if (isStarCliche(*ig[e].graph)) {
+ DEBUG_PRINTF("is a X star!\n");
+ ig[e].graph.reset();
+ ig[e].graph_lag = 0;
+ }
+ }
+}
+
+static
+void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
+ const CompileContext &cc) {
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> infixes;
+
+ for (const RoseInEdge &e : edges_range(g)) {
+ RoseInVertex s = source(e, g);
+ RoseInVertex t = target(e, g);
+
+ if (g[s].type != RIV_LITERAL || g[t].type != RIV_LITERAL) {
+ continue;
+ }
+
+ if (!g[e].graph) {
+ continue;
+ }
+
+ assert(!g[t].delay);
+ if (g[e].dfa) {
+ /* if we removed any more states, we would need to rebuild the
+ * the dfa which can be time consuming. */
+ continue;
+ }
+
+ NGHolder *h = g[e].graph.get();
+ infixes[h].push_back(e);
+ }
+
+ for (const auto &m : infixes) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
+ removeRedundantLiteralsFromInfix(*h, g, edges, cc);
+ }
+}
+
+static
+void removeRedundantLiterals(RoseInGraph &g, const CompileContext &cc) {
+ removeRedundantLiteralsFromPrefixes(g, cc);
+ removeRedundantLiteralsFromInfixes(g, cc);
+}
+
+static
+RoseInVertex getStart(RoseInGraph &vg) {
+ for (RoseInVertex v : vertices_range(vg)) {
+ if (vg[v].type == RIV_START || vg[v].type == RIV_ANCHORED_START) {
+ return v;
+ }
+ }
+ assert(0);
+ return RoseInGraph::null_vertex();
+}
+
+/**
+ * Finds the initial accept vertex created to which suffix/outfixes are
+ * attached.
+ */
+static
+RoseInVertex getPrimaryAccept(RoseInGraph &vg) {
+ for (RoseInVertex v : vertices_range(vg)) {
+ if (vg[v].type == RIV_ACCEPT && vg[v].reports.empty()) {
+ return v;
+ }
+ }
+ assert(0);
+ return RoseInGraph::null_vertex();
+}
+
+static
+bool willBeTransient(const depth &max_depth, const CompileContext &cc) {
+ if (!cc.streaming) {
+ return max_depth <= depth(ROSE_BLOCK_TRANSIENT_MAX_WIDTH);
+ } else {
+ return max_depth <= depth(cc.grey.maxHistoryAvailable + 1);
+ }
+}
+
+static
+bool willBeAnchoredTable(const depth &max_depth, const Grey &grey) {
+ return max_depth <= depth(grey.maxAnchoredRegion);
+}
+
+static
+unique_ptr<NGHolder> make_chain(u32 count) {
+ assert(count);
+
+ auto rv = std::make_unique<NGHolder>(NFA_INFIX);
+
+ NGHolder &h = *rv;
+
+ NFAVertex u = h.start;
+ for (u32 i = 0; i < count; i++) {
+ NFAVertex v = add_vertex(h);
+ h[v].char_reach = CharReach::dot();
+ add_edge(u, v, h);
+ u = v;
+ }
+ h[u].reports.insert(0);
+ add_edge(u, h.accept, h);
+
+ setTops(h);
+
+ return rv;
+}
+
+#define SHORT_TRIGGER_LEN 16
+
+static
+bool makeTransientFromLongLiteral(NGHolder &h, RoseInGraph &vg,
+ const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ /* check max width and literal lengths to see if possible */
+ size_t min_lit = (size_t)~0ULL;
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex v = target(e, vg);
+ LIMIT_TO_AT_MOST(&min_lit, vg[v].s.length());
+ }
+
+ if (min_lit <= SHORT_TRIGGER_LEN || min_lit >= UINT_MAX) {
+ return false;
+ }
+
+ depth max_width = findMaxWidth(h);
+
+ u32 delta = min_lit - SHORT_TRIGGER_LEN;
+
+ if (!willBeTransient(max_width - depth(delta), cc)
+ && !willBeAnchoredTable(max_width - depth(delta), cc.grey)) {
+ return false;
+ }
+
+ DEBUG_PRINTF("candidate for splitting long literal (len %zu)\n", min_lit);
+ DEBUG_PRINTF("delta = %u\n", delta);
+
+ /* try split */
+ map<RoseInVertex, shared_ptr<NGHolder> > graphs;
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex v = target(e, vg);
+
+ shared_ptr<NGHolder> h_new = cloneHolder(h);
+
+ u32 delay = removeTrailingLiteralStates(*h_new, vg[v].s, delta);
+
+ DEBUG_PRINTF("delay %u\n", delay);
+
+ if (delay != delta) {
+ DEBUG_PRINTF("unable to trim literal\n");
+ return false;
+ }
+
+ if (in_degree(v, vg) != 1) {
+ DEBUG_PRINTF("complicated\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("new mw = %u\n", (u32)findMaxWidth(*h_new));
+ assert(willBeTransient(findMaxWidth(*h_new), cc)
+ || willBeAnchoredTable(findMaxWidth(*h_new), cc.grey));
+
+ assert(isCorrectlyTopped(*h_new));
+ graphs[v] = h_new;
+ }
+
+ /* add .{repeats} from prefixes to long literals */
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex s = source(e, vg);
+ RoseInVertex t = target(e, vg);
+
+ remove_edge(e, vg);
+ const ue2_literal &orig_lit = vg[t].s;
+
+ ue2_literal lit(orig_lit.begin(), orig_lit.end() - delta);
+
+ ue2_literal lit2(orig_lit.end() - delta, orig_lit.end());
+
+ assert(lit.length() + delta == orig_lit.length());
+
+ vg[t].s = lit2;
+
+ RoseInVertex v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
+ add_edge(s, v, RoseInEdgeProps(graphs[t], 0), vg);
+ add_edge(v, t, RoseInEdgeProps(make_chain(delta), 0), vg);
+ }
+
+ DEBUG_PRINTF("success\n");
+ /* TODO: alter split point to avoid pathological splits */
+ return true;
+}
+
+static
+void restoreTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
+ u32 delay, const vector<NFAVertex> &preds) {
+ assert(delay <= lit.length());
+ assert(isCorrectlyTopped(g));
+ DEBUG_PRINTF("adding on '%s' %u\n", dumpString(lit).c_str(), delay);
+
+ NFAVertex prev = g.accept;
+ auto it = lit.rbegin();
+ while (delay--) {
+ NFAVertex curr = add_vertex(g);
+ assert(it != lit.rend());
+ g[curr].char_reach = *it;
+ add_edge(curr, prev, g);
+ ++it;
+ prev = curr;
+ }
+
+ for (auto v : preds) {
+ NFAEdge e = add_edge_if_not_present(v, prev, g);
+ if (v == g.start && is_triggered(g)) {
+ g[e].tops.insert(DEFAULT_TOP);
+ }
+ }
+
+ // Every predecessor of accept must have a report.
+ set_report(g, 0);
+
+ renumber_vertices(g);
+ renumber_edges(g);
+ assert(allMatchStatesHaveReports(g));
+ assert(isCorrectlyTopped(g));
+}
+
+static
+void restoreTrailingLiteralStates(NGHolder &g,
+ const vector<pair<ue2_literal, u32>> &lits) {
+ vector<NFAVertex> preds;
+ insert(&preds, preds.end(), inv_adjacent_vertices(g.accept, g));
+ clear_in_edges(g.accept, g);
+
+ for (auto v : preds) {
+ g[v].reports.clear(); /* clear report from old accepts */
+ }
+
+ for (const auto &p : lits) {
+ const ue2_literal &lit = p.first;
+ u32 delay = p.second;
+
+ restoreTrailingLiteralStates(g, lit, delay, preds);
+ }
+}
+
+static
+bool improvePrefix(NGHolder &h, RoseInGraph &vg, const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ DEBUG_PRINTF("trying to improve prefix %p, %zu verts\n", &h,
+ num_vertices(h));
+ assert(isCorrectlyTopped(h));
+
+ renumber_vertices(h);
+ renumber_edges(h);
+
+ auto depths = calcDepths(h);
+
+ /* If the reason the prefix is not transient is due to a very long literal
+ * following, we can make it transient by restricting ourselves to using
+ * just the head of the literal. */
+ if (makeTransientFromLongLiteral(h, vg, ee, cc)) {
+ return true;
+ }
+
+ auto split = findBestPrefixSplit(h, depths, vg, ee, false, cc);
+
+ if (split && (split->creates_transient || split->creates_anchored)
+ && splitRoseEdge(h, vg, ee, *split)) {
+ DEBUG_PRINTF("split on simple literal\n");
+ return true;
+ }
+
+ /* large back edges may prevent us identifing anchored or transient cases
+ * properly - use a simple walk instead */
+
+ if (doNetflowCut(h, &depths, vg, ee, true, cc.grey)) {
+ return true;
+ }
+
+ if (split && splitRoseEdge(h, vg, ee, *split)) {
+ /* use the simple split even though it doesn't create a transient
+ * prefix */
+ DEBUG_PRINTF("split on simple literal\n");
+ return true;
+ }
+
+ /* look for netflow cuts which don't produce good prefixes */
+ if (doNetflowCut(h, &depths, vg, ee, false, cc.grey)) {
+ return true;
+ }
+
+ if (ee.size() > 1) {
+ DEBUG_PRINTF("split the prefix apart based on succ literals\n");
+ unordered_map<shared_ptr<NGHolder>, vector<pair<RoseInEdge, u32> >,
NGHolderHasher, NGHolderEqual> trimmed;
-
- for (const auto &e : ee) {
- shared_ptr<NGHolder> hh = cloneHolder(h);
- auto succ_lit = vg[target(e, vg)].s;
- assert(isCorrectlyTopped(*hh));
- u32 delay = removeTrailingLiteralStates(*hh, succ_lit,
- succ_lit.length(),
- false /* can't overhang start */);
- if (!delay) {
- DEBUG_PRINTF("could not remove any literal, skip over\n");
- continue;
- }
-
- assert(isCorrectlyTopped(*hh));
- trimmed[hh].emplace_back(e, delay);
- }
-
- if (trimmed.size() == 1) {
- return false;
- }
-
- /* shift the contents to a vector so we can modify the graphs without
- * violating the map's invariants. */
- vector<pair<shared_ptr<NGHolder>, vector<pair<RoseInEdge, u32> > > >
- trimmed_vec(trimmed.begin(), trimmed.end());
- trimmed.clear();
- for (auto &elem : trimmed_vec) {
- shared_ptr<NGHolder> &hp = elem.first;
- vector<pair<ue2_literal, u32>> succ_lits;
-
- for (const auto &edge_delay : elem.second) {
- const RoseInEdge &e = edge_delay.first;
- u32 delay = edge_delay.second;
- auto lit = vg[target(e, vg)].s;
-
- vg[e].graph = hp;
- assert(delay <= lit.length());
- succ_lits.emplace_back(lit, delay);
- }
- restoreTrailingLiteralStates(*hp, succ_lits);
- }
- return true;
- }
-
- return false;
-}
-
-#define MAX_FIND_BETTER_PREFIX_GEN 4
-#define MAX_FIND_BETTER_PREFIX_COUNT 100
-
-static
-void findBetterPrefixes(RoseInGraph &vg, const CompileContext &cc) {
- STAGE_DEBUG_PRINTF("FIND BETTER PREFIXES\n");
- RoseInVertex start = getStart(vg);
-
- insertion_ordered_map<NGHolder *, vector<RoseInEdge>> prefixes;
- bool changed;
- u32 gen = 0;
- do {
- DEBUG_PRINTF("gen %u\n", gen);
- changed = false;
- prefixes.clear();
-
- /* find prefixes */
- for (const RoseInEdge &e : out_edges_range(start, vg)) {
- /* outfixes shouldn't have made it this far */
- assert(vg[target(e, vg)].type == RIV_LITERAL);
- if (vg[e].graph) {
- NGHolder *h = vg[e].graph.get();
- prefixes[h].push_back(e);
- }
- }
-
- if (prefixes.size() > MAX_FIND_BETTER_PREFIX_COUNT) {
- break;
- }
-
- /* look for bad prefixes and try to split */
- for (const auto &m : prefixes) {
- NGHolder *h = m.first;
- const auto &edges = m.second;
- depth max_width = findMaxWidth(*h);
- if (willBeTransient(max_width, cc)
- || willBeAnchoredTable(max_width, cc.grey)) {
- continue;
- }
-
- changed = improvePrefix(*h, vg, edges, cc);
- }
- } while (changed && gen++ < MAX_FIND_BETTER_PREFIX_GEN);
-}
-
-#define STRONG_LITERAL_LENGTH 20
-#define MAX_EXTRACT_STRONG_LITERAL_GRAPHS 10
-
-static
-bool extractStrongLiteral(NGHolder &h, RoseInGraph &vg,
- const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- DEBUG_PRINTF("looking for string literal\n");
- unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, ee, cc);
-
- if (split && min_len(split->lit) >= STRONG_LITERAL_LENGTH) {
- DEBUG_PRINTF("splitting simple literal\n");
- return splitRoseEdge(h, vg, ee, *split);
- }
-
- return false;
-}
-
-static
-void extractStrongLiterals(RoseInGraph &vg, const CompileContext &cc) {
- if (!cc.grey.violetExtractStrongLiterals) {
- return;
- }
-
- STAGE_DEBUG_PRINTF("EXTRACT STRONG LITERALS\n");
-
- unordered_set<NGHolder *> stuck;
- insertion_ordered_map<NGHolder *, vector<RoseInEdge>> edges_by_graph;
- bool changed;
-
- do {
- changed = false;
-
- edges_by_graph.clear();
- for (const RoseInEdge &ve : edges_range(vg)) {
- if (vg[source(ve, vg)].type != RIV_LITERAL) {
- continue;
- }
-
- if (vg[ve].graph) {
- NGHolder *h = vg[ve].graph.get();
- edges_by_graph[h].push_back(ve);
- }
- }
-
- if (edges_by_graph.size() > MAX_EXTRACT_STRONG_LITERAL_GRAPHS) {
- DEBUG_PRINTF("too many graphs, stopping\n");
- return;
- }
-
- for (const auto &m : edges_by_graph) {
- NGHolder *g = m.first;
- const auto &edges = m.second;
- if (contains(stuck, g)) {
- DEBUG_PRINTF("already known to be bad\n");
- continue;
- }
- bool rv = extractStrongLiteral(*g, vg, edges, cc);
- if (rv) {
- changed = true;
- } else {
- stuck.insert(g);
- }
- }
- } while (changed);
-}
-
-#define INFIX_STRONG_GUARD_LEN 8
-#define INFIX_MIN_SPLIT_LITERAL_LEN 12
-
-static
-bool improveInfix(NGHolder &h, RoseInGraph &vg, const vector<RoseInEdge> &ee,
- const CompileContext &cc) {
- unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, ee, cc);
-
- if (split && min_len(split->lit) >= INFIX_MIN_SPLIT_LITERAL_LEN
- && splitRoseEdge(h, vg, ee, *split)) {
- DEBUG_PRINTF("splitting simple literal\n");
- return true;
- }
-
- DEBUG_PRINTF("trying for a netflow cut\n");
- /* look for netflow cuts which don't produce good prefixes */
- bool rv = doNetflowCut(h, nullptr, vg, ee, false, cc.grey, 8);
-
- DEBUG_PRINTF("did netfow cut? = %d\n", (int)rv);
-
- return rv;
-}
-
-/**
- * Infixes which are weakly guarded can, in effect, act like prefixes as they
- * will often be live. We should try to split these infixes further if they
- * contain strong literals so that we are at least running smaller weak infixes
- * which can hopeful be accelerated/miracled.
- */
-static
-void improveWeakInfixes(RoseInGraph &vg, const CompileContext &cc) {
- if (!cc.grey.violetAvoidWeakInfixes) {
- return;
- }
- STAGE_DEBUG_PRINTF("IMPROVE WEAK INFIXES\n");
-
- RoseInVertex start = getStart(vg);
-
- unordered_set<NGHolder *> weak;
-
- for (RoseInVertex vv : adjacent_vertices_range(start, vg)) {
- /* outfixes shouldn't have made it this far */
- assert(vg[vv].type == RIV_LITERAL);
- if (vg[vv].s.length() >= INFIX_STRONG_GUARD_LEN) {
- continue;
- }
-
- for (const RoseInEdge &e : out_edges_range(vv, vg)) {
- if (vg[target(e, vg)].type != RIV_LITERAL || !vg[e].graph) {
- continue;
- }
-
- NGHolder *h = vg[e].graph.get();
- DEBUG_PRINTF("'%s' guards %p\n", dumpString(vg[vv].s).c_str(), h);
- weak.insert(h);
- }
- }
-
- insertion_ordered_map<NGHolder *, vector<RoseInEdge>> weak_edges;
- for (const RoseInEdge &ve : edges_range(vg)) {
- NGHolder *h = vg[ve].graph.get();
- if (contains(weak, h)) {
- weak_edges[h].push_back(ve);
- }
- }
-
- for (const auto &m : weak_edges) {
- NGHolder *h = m.first;
- const auto &edges = m.second;
- improveInfix(*h, vg, edges, cc);
- }
-}
-
-static
-void splitEdgesForSuffix(const NGHolder &base_graph, RoseInGraph &vg,
- const vector<RoseInEdge> &ee, const VertLitInfo &split,
- bool eod, const flat_set<ReportID> &reports) {
- const vector<NFAVertex> &splitters = split.vv;
- assert(!splitters.empty());
-
- shared_ptr<NGHolder> lhs = make_shared<NGHolder>();
- unordered_map<NFAVertex, NFAVertex> v_map;
- cloneHolder(*lhs, base_graph, &v_map);
- lhs->kind = NFA_INFIX;
- clear_in_edges(lhs->accept, *lhs);
- clear_in_edges(lhs->acceptEod, *lhs);
- add_edge(lhs->accept, lhs->acceptEod, *lhs);
- clearReports(*lhs);
- for (NFAVertex v : splitters) {
- NFAEdge e = add_edge(v_map[v], lhs->accept, *lhs);
- if (v == base_graph.start) {
- (*lhs)[e].tops.insert(DEFAULT_TOP);
- }
- (*lhs)[v_map[v]].reports.insert(0);
-
- }
- pruneUseless(*lhs);
- assert(isCorrectlyTopped(*lhs));
-
- /* create literal vertices and connect preds */
- for (const auto &lit : split.lit) {
- if (!can_match(*lhs, lit, is_triggered(*lhs))) {
- continue;
- }
-
- DEBUG_PRINTF("best is '%s'\n", escapeString(lit).c_str());
- RoseInVertex v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
-
- RoseInVertex tt;
- if (eod) {
- DEBUG_PRINTF("doing eod\n");
- tt = add_vertex(RoseInVertexProps::makeAcceptEod(reports), vg);
- } else {
- DEBUG_PRINTF("doing non-eod\n");
- tt = add_vertex(RoseInVertexProps::makeAccept(reports), vg);
- }
- add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
-
- for (const RoseInEdge &e : ee) {
- RoseInVertex u = source(e, vg);
- assert(!edge(u, v, vg).second);
- add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
- }
- }
-}
-
-#define MIN_SUFFIX_LEN 6
-
-static
-bool replaceSuffixWithInfix(const NGHolder &h, RoseInGraph &vg,
- const vector<RoseInEdge> &suffix_edges,
- const CompileContext &cc) {
- DEBUG_PRINTF("inspecting suffix : %p on %zu edges\n", &h,
- suffix_edges.size());
- /*
- * We would, in general, rather not have output exposed engines because
- * once they are triggered, they must be run while infixes only have to run
- * if the successor literal is seen. Matches from output exposed engines
- * also have to be placed in a priority queue and interleaved with matches
- * from other sources.
- *
- * Note:
- * - if the LHS is extremely unlikely we may be better off leaving
- * a suffix unguarded.
- *
- * - limited width suffixes may be less bad as they won't be continuously
- * active, we may want to have (a) stronger controls on if we want to pick
- * a trailing literal in these cases and/or (b) look also for literals
- * near accept as well as right on accept
- *
- * TODO: improve heuristics, splitting logic.
- */
-
- /* we may do multiple splits corresponding to different report behaviour */
- set<NFAVertex> seen;
- map<pair<bool, flat_set<ReportID> >, VertLitInfo> by_reports; /* eod, rep */
-
- for (NFAVertex v : inv_adjacent_vertices_range(h.accept, h)) {
- set<ue2_literal> ss = getLiteralSet(h, v, false);
- if (ss.empty()) {
- DEBUG_PRINTF("candidate is too shitty\n");
- return false;
- }
-
- VertLitInfo &vli = by_reports[make_pair(false, h[v].reports)];
- insert(&vli.lit, ss);
- vli.vv.push_back(v);
- seen.insert(v);
- }
-
- seen.insert(h.accept);
- for (NFAVertex v : inv_adjacent_vertices_range(h.acceptEod, h)) {
- if (contains(seen, v)) {
- continue;
- }
-
- set<ue2_literal> ss = getLiteralSet(h, v, false);
- if (ss.empty()) {
- DEBUG_PRINTF("candidate is too shitty\n");
- return false;
- }
-
- VertLitInfo &vli = by_reports[make_pair(true, h[v].reports)];
- insert(&vli.lit, ss);
- vli.vv.push_back(v);
- }
-
- assert(!by_reports.empty());
-
- /* TODO: how strong a min len do we want here ? */
- u32 min_len = cc.grey.minRoseLiteralLength;
- ENSURE_AT_LEAST(&min_len, MIN_SUFFIX_LEN);
-
- for (auto &vli : by_reports | map_values) {
- u64a score = sanitizeAndCompressAndScore(vli.lit);
-
- if (vli.lit.empty()
- || !validateRoseLiteralSetQuality(vli.lit, score, false, min_len,
- false, false)) {
- return false;
- }
- }
-
- for (const auto &info : by_reports) {
- DEBUG_PRINTF("splitting on simple literals\n");
- splitEdgesForSuffix(h, vg, suffix_edges, info.second,
- info.first.first /* eod */,
- info.first.second /* reports */);
- }
-
- for (const RoseInEdge &e : suffix_edges) {
- remove_edge(e, vg);
- }
- return true;
-}
-
-static
-void avoidSuffixes(RoseInGraph &vg, const CompileContext &cc) {
- if (!cc.grey.violetAvoidSuffixes) {
- return;
- }
-
- STAGE_DEBUG_PRINTF("AVOID SUFFIXES\n");
-
- RoseInVertex accept = getPrimaryAccept(vg);
-
- insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> suffixes;
-
- /* find suffixes */
- for (const RoseInEdge &e : in_edges_range(accept, vg)) {
- /* outfixes shouldn't have made it this far */
- assert(vg[source(e, vg)].type == RIV_LITERAL);
- assert(vg[e].graph); /* non suffix paths should be wired to other
- accepts */
- const NGHolder *h = vg[e].graph.get();
- suffixes[h].push_back(e);
- }
-
- /* look at suffixes and try to split */
- for (const auto &m : suffixes) {
- const NGHolder *h = m.first;
- const auto &edges = m.second;
- replaceSuffixWithInfix(*h, vg, edges, cc);
- }
-}
-
-static
-bool leadingDotStartLiteral(const NGHolder &h, VertLitInfo *out) {
- if (out_degree(h.start, h) != 3) {
- return false;
- }
-
- NFAVertex v = NGHolder::null_vertex();
- NFAVertex ds = NGHolder::null_vertex();
-
- for (NFAVertex a : adjacent_vertices_range(h.start, h)) {
- if (a == h.startDs) {
- continue;
- }
- if (h[a].char_reach.all()) {
- ds = a;
- if (out_degree(ds, h) != 2 || !edge(ds, ds, h).second) {
- return false;
- }
- } else {
- v = a;
- }
- }
-
- if (!v || !ds || !edge(ds, v, h).second) {
- return false;
- }
-
- if (h[v].char_reach.count() != 1 && !h[v].char_reach.isCaselessChar()) {
- return false;
- }
-
- ue2_literal lit;
- lit.push_back(h[v].char_reach.find_first(),
- h[v].char_reach.isCaselessChar());
- while (out_degree(v, h) == 1) {
- NFAVertex vv = *adjacent_vertices(v, h).first;
- if (h[vv].char_reach.count() != 1
- && !h[vv].char_reach.isCaselessChar()) {
- break;
- }
-
- v = vv;
-
- lit.push_back(h[v].char_reach.find_first(),
- h[v].char_reach.isCaselessChar());
- }
-
- if (is_match_vertex(v, h) && h.kind != NFA_SUFFIX) {
- /* we have rediscovered the post-infix literal */
- return false;
- }
-
- if (bad_mixed_sensitivity(lit)) {
- make_nocase(&lit);
- }
-
- DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str());
- out->vv = {v};
- out->lit = {lit};
- return true;
-}
-
-static
-bool lookForDoubleCut(const NGHolder &h, const vector<RoseInEdge> &ee,
- RoseInGraph &vg, const Grey &grey) {
- VertLitInfo info;
- if (!leadingDotStartLiteral(h, &info)
- || min_len(info.lit) < grey.violetDoubleCutLiteralLen) {
- return false;
- }
- DEBUG_PRINTF("performing split\n");
- return splitRoseEdge(h, vg, ee, {info});
-}
-
-static
-void lookForDoubleCut(RoseInGraph &vg, const CompileContext &cc) {
- if (!cc.grey.violetDoubleCut) {
- return;
- }
-
- insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
- for (const RoseInEdge &ve : edges_range(vg)) {
- if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
- const NGHolder *h = vg[ve].graph.get();
- right_edges[h].push_back(ve);
- }
- }
-
- for (const auto &m : right_edges) {
- const NGHolder *h = m.first;
- const auto &edges = m.second;
- lookForDoubleCut(*h, edges, vg, cc.grey);
- }
-}
-
-static
-pair<NFAVertex, ue2_literal> findLiteralBefore(const NGHolder &h, NFAVertex v) {
- ue2_literal lit;
- if (h[v].char_reach.count() != 1 && !h[v].char_reach.isCaselessChar()) {
- return {v, std::move(lit) };
- }
- lit.push_back(h[v].char_reach.find_first(),
- h[v].char_reach.isCaselessChar());
-
- while (in_degree(v, h) == 1) {
- NFAVertex vv = *inv_adjacent_vertices(v, h).first;
- if (h[vv].char_reach.count() != 1
- && !h[vv].char_reach.isCaselessChar()) {
- break;
- }
-
- lit.push_back(h[vv].char_reach.find_first(),
- h[vv].char_reach.isCaselessChar());
- v = vv;
- }
-
- return {v, std::move(lit) };
-}
-
-static
-bool lookForDotStarPred(NFAVertex v, const NGHolder &h,
- NFAVertex *u, NFAVertex *ds) {
- *u = NGHolder::null_vertex();
- *ds = NGHolder::null_vertex();
- for (NFAVertex a : inv_adjacent_vertices_range(v, h)) {
- if (h[a].char_reach.all()) {
- if (!edge(a, a, h).second) {
- return false;
- }
-
- if (*ds) {
- return false;
- }
-
- *ds = a;
- } else {
- if (*u) {
- return false;
- }
- *u = a;
- }
- }
-
- if (!*u || !*ds) {
- return false;
- }
-
- return true;
-}
-
-static
-bool trailingDotStarLiteral(const NGHolder &h, VertLitInfo *out) {
- /* Note: there is no delay yet - so the final literal is the already
- * discovered successor literal - we are in fact interested in the literal
- * before it. */
-
- if (in_degree(h.accept, h) != 1) {
- return false;
- }
-
- if (in_degree(h.acceptEod, h) != 1) {
- assert(0);
- return false;
- }
-
- NFAVertex v
- = findLiteralBefore(h, *inv_adjacent_vertices(h.accept, h).first).first;
-
- NFAVertex u;
- NFAVertex ds;
-
- if (!lookForDotStarPred(v, h, &u, &ds)) {
- return false;
- }
-
- v = u;
- auto rv = findLiteralBefore(h, v);
-
- if (!lookForDotStarPred(v, h, &u, &ds)) {
- return false;
- }
-
- ue2_literal lit = reverse_literal(rv.second);
- DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str());
-
- if (bad_mixed_sensitivity(lit)) {
- make_nocase(&lit);
- }
-
- out->vv = {v};
- out->lit = {lit};
- return true;
-}
-
-static
-bool lookForTrailingLiteralDotStar(const NGHolder &h,
- const vector<RoseInEdge> &ee,
- RoseInGraph &vg, const Grey &grey) {
- VertLitInfo info;
- if (!trailingDotStarLiteral(h, &info)
- || min_len(info.lit) < grey.violetDoubleCutLiteralLen) {
- return false;
- }
- DEBUG_PRINTF("performing split\n");
- return splitRoseEdge(h, vg, ee, info);
-}
-
-/* In streaming mode, active engines have to be caught up at stream boundaries
- * and have to be stored in stream state, so we prefer to decompose patterns
- * in to literals with no state between them if possible. */
-static
-void decomposeLiteralChains(RoseInGraph &vg, const CompileContext &cc) {
- if (!cc.grey.violetLiteralChains) {
- return;
- }
-
- insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
- bool changed;
- do {
- changed = false;
-
- right_edges.clear();
- for (const RoseInEdge &ve : edges_range(vg)) {
- if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
- const NGHolder *h = vg[ve].graph.get();
- right_edges[h].push_back(ve);
- }
- }
-
- for (const auto &m : right_edges) {
- const NGHolder *h = m.first;
- const vector<RoseInEdge> &ee = m.second;
- bool rv = lookForDoubleCut(*h, ee, vg, cc.grey);
- if (!rv && h->kind != NFA_SUFFIX) {
- rv = lookForTrailingLiteralDotStar(*h, ee, vg, cc.grey);
- }
- changed |= rv;
- }
- } while (changed);
-}
-
-static
-bool lookForCleanSplit(const NGHolder &h, const vector<RoseInEdge> &ee,
- RoseInGraph &vg, const CompileContext &cc) {
- unique_ptr<VertLitInfo> split = findBestCleanSplit(h, cc);
-
- if (split) {
- return splitRoseEdge(h, vg, {ee}, *split);
- }
-
- return false;
-}
-
-#define MAX_DESIRED_CLEAN_SPLIT_DEPTH 4
-
-static
-void lookForCleanEarlySplits(RoseInGraph &vg, const CompileContext &cc) {
- u32 gen = 0;
-
- insertion_ordered_set<RoseInVertex> prev({getStart(vg)});
- insertion_ordered_set<RoseInVertex> curr;
-
- while (gen < MAX_DESIRED_CLEAN_SPLIT_DEPTH) {
- curr.clear();
- for (RoseInVertex u : prev) {
- for (auto v : adjacent_vertices_range(u, vg)) {
- curr.insert(v);
- }
- }
-
- insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> rightfixes;
- for (RoseInVertex v : curr) {
- for (const RoseInEdge &e : out_edges_range(v, vg)) {
- if (vg[e].graph) {
- NGHolder *h = vg[e].graph.get();
- rightfixes[h].push_back(e);
- }
- }
- }
-
- for (const auto &m : rightfixes) {
- const NGHolder *h = m.first;
- const auto &edges = m.second;
- lookForCleanSplit(*h, edges, vg, cc);
- }
-
- prev = std::move(curr);
- gen++;
- }
-}
-
-static
-void rehomeEodSuffixes(RoseInGraph &vg) {
- // Find edges to accept with EOD-anchored graphs that we can move over to
- // acceptEod.
- vector<RoseInEdge> acc_edges;
- for (const auto &e : edges_range(vg)) {
- if (vg[target(e, vg)].type != RIV_ACCEPT) {
- continue;
- }
- if (vg[e].haig || !vg[e].graph) {
- continue;
- }
-
- const NGHolder &h = *vg[e].graph;
-
- if (in_degree(h.accept, h)) {
- DEBUG_PRINTF("graph isn't eod anchored\n");
- continue;
- }
-
- acc_edges.push_back(e);
- }
-
- for (const RoseInEdge &e : acc_edges) {
- // Move this edge from accept to acceptEod
- RoseInVertex w = add_vertex(RoseInVertexProps::makeAcceptEod(), vg);
- add_edge(source(e, vg), w, vg[e], vg);
- remove_edge(e, vg);
- }
-
- /* old accept vertices will be tidied up by final pruneUseless() call */
-}
-
-static
-bool tryForEarlyDfa(const NGHolder &h, const CompileContext &cc) {
- switch (h.kind) {
- case NFA_OUTFIX: /* 'prefix' of eod */
- case NFA_PREFIX:
- return cc.grey.earlyMcClellanPrefix;
- case NFA_INFIX:
- return cc.grey.earlyMcClellanInfix;
- case NFA_SUFFIX:
- return cc.grey.earlyMcClellanSuffix;
- default:
- DEBUG_PRINTF("kind %u\n", (u32)h.kind);
- assert(0);
- return false;
- }
-}
-
-static
-vector<vector<CharReach>> getDfaTriggers(RoseInGraph &vg,
- const vector<RoseInEdge> &edges,
- bool *single_trigger) {
- vector<vector<CharReach>> triggers;
- u32 min_offset = ~0U;
- u32 max_offset = 0;
- for (const auto &e : edges) {
- RoseInVertex s = source(e, vg);
- if (vg[s].type == RIV_LITERAL) {
- triggers.push_back(as_cr_seq(vg[s].s));
- }
- ENSURE_AT_LEAST(&max_offset, vg[s].max_offset);
- LIMIT_TO_AT_MOST(&min_offset, vg[s].min_offset);
- }
-
- *single_trigger = min_offset == max_offset;
- DEBUG_PRINTF("trigger offset (%u, %u)\n", min_offset, max_offset);
-
- return triggers;
-}
-
-static
-bool doEarlyDfa(RoseBuild &rose, RoseInGraph &vg, NGHolder &h,
- const vector<RoseInEdge> &edges, bool final_chance,
- const ReportManager &rm, const CompileContext &cc) {
- DEBUG_PRINTF("trying for dfa\n");
-
- bool single_trigger;
- for (const auto &e : edges) {
- if (vg[target(e, vg)].type == RIV_ACCEPT_EOD) {
- /* TODO: support eod prefixes */
- return false;
- }
- }
-
- auto triggers = getDfaTriggers(vg, edges, &single_trigger);
-
- /* TODO: literal delay things */
- if (!generates_callbacks(h)) {
- set_report(h, rose.getNewNfaReport());
- }
-
- shared_ptr<raw_dfa> dfa = buildMcClellan(h, &rm, single_trigger, triggers,
- cc.grey, final_chance);
-
- if (!dfa) {
- return false;
- }
-
- DEBUG_PRINTF("dfa ok\n");
- for (const auto &e : edges) {
- vg[e].dfa = dfa;
- }
-
- return true;
-}
-
-#define MAX_EDGES_FOR_IMPLEMENTABILITY 50
-
-static
-bool splitForImplementability(RoseInGraph &vg, NGHolder &h,
- const vector<RoseInEdge> &edges,
- const CompileContext &cc) {
- vector<pair<ue2_literal, u32>> succ_lits;
- DEBUG_PRINTF("trying to split %s with %zu vertices on %zu edges\n",
- to_string(h.kind).c_str(), num_vertices(h), edges.size());
-
- if (edges.size() > MAX_EDGES_FOR_IMPLEMENTABILITY) {
- return false;
- }
-
- if (!generates_callbacks(h)) {
- for (const auto &e : edges) {
- const auto &lit = vg[target(e, vg)].s;
- u32 delay = vg[e].graph_lag;
- vg[e].graph_lag = 0;
-
- assert(delay <= lit.length());
- succ_lits.emplace_back(lit, delay);
- }
- restoreTrailingLiteralStates(h, succ_lits);
- }
-
- unique_ptr<VertLitInfo> split;
- bool last_chance = true;
- if (h.kind == NFA_PREFIX) {
- auto depths = calcDepths(h);
-
- split = findBestPrefixSplit(h, depths, vg, edges, last_chance, cc);
- } else {
- split = findBestLastChanceSplit(h, vg, edges, cc);
- }
-
- if (split && splitRoseEdge(h, vg, edges, *split)) {
- DEBUG_PRINTF("split on simple literal\n");
- return true;
- }
-
- DEBUG_PRINTF("trying to netflow\n");
- bool rv = doNetflowCut(h, nullptr, vg, edges, false, cc.grey);
- DEBUG_PRINTF("done\n");
-
- return rv;
-}
-
-#define MAX_IMPLEMENTABLE_SPLITS 50
-
-bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
- bool final_chance, const ReportManager &rm,
- const CompileContext &cc) {
- DEBUG_PRINTF("checking for impl %d\n", final_chance);
- bool changed = false;
- bool need_to_recalc = false;
- u32 added_count = 0;
- unordered_set<shared_ptr<NGHolder>> good; /* known to be implementable */
- do {
- changed = false;
- DEBUG_PRINTF("added %u\n", added_count);
- insertion_ordered_map<shared_ptr<NGHolder>,
- vector<RoseInEdge>> edges_by_graph;
- for (const RoseInEdge &ve : edges_range(vg)) {
- if (vg[ve].graph && !vg[ve].dfa) {
- auto &h = vg[ve].graph;
- edges_by_graph[h].push_back(ve);
- }
- }
- for (auto &m : edges_by_graph) {
- auto &h = m.first;
- if (contains(good, h)) {
- continue;
- }
- reduceGraphEquivalences(*h, cc);
- if (isImplementableNFA(*h, &rm, cc)) {
- good.insert(h);
- continue;
- }
-
- const auto &edges = m.second;
-
- if (tryForEarlyDfa(*h, cc) &&
- doEarlyDfa(rose, vg, *h, edges, final_chance, rm, cc)) {
- continue;
- }
-
- DEBUG_PRINTF("eek\n");
- if (!allow_changes) {
- return false;
- }
-
- if (splitForImplementability(vg, *h, edges, cc)) {
- added_count++;
- if (added_count > MAX_IMPLEMENTABLE_SPLITS) {
- DEBUG_PRINTF("added_count hit limit\n");
- return false;
- }
- changed = true;
- continue;
- }
-
- return false;
- }
-
- assert(added_count <= MAX_IMPLEMENTABLE_SPLITS);
-
- if (changed) {
- removeRedundantLiterals(vg, cc);
- pruneUseless(vg);
- need_to_recalc = true;
- }
- } while (changed);
-
- if (need_to_recalc) {
- renumber_vertices(vg);
- calcVertexOffsets(vg);
- }
-
- DEBUG_PRINTF("ok!\n");
- return true;
-}
-
-static
-RoseInGraph doInitialVioletTransform(const NGHolder &h, bool last_chance,
- const CompileContext &cc) {
- assert(!can_never_match(h));
-
- RoseInGraph vg = populateTrivialGraph(h);
-
- if (!cc.grey.allowViolet) {
- return vg;
- }
-
- /* Avoid running the Violet analysis at all on graphs with no vertices with
- * small reach, since we will not be able to extract any literals. */
- if (!hasNarrowReachVertex(h)) {
- DEBUG_PRINTF("fail, no vertices with small reach\n");
- return vg;
- }
-
- DEBUG_PRINTF("hello world\n");
-
- /* Step 1: avoid outfixes as we always have to run them. */
- avoidOutfixes(vg, last_chance, cc);
-
- if (num_vertices(vg) <= 2) {
- return vg; /* unable to transform pattern */
- }
-
- removeRedundantPrefixes(vg);
- dumpPreRoseGraph(vg, cc.grey, "pre_prefix_rose.dot");
-
- /* Step 2: avoid non-transient prefixes (esp in streaming mode) */
- findBetterPrefixes(vg, cc);
-
- dumpPreRoseGraph(vg, cc.grey, "post_prefix_rose.dot");
-
- extractStrongLiterals(vg, cc);
- dumpPreRoseGraph(vg, cc.grey, "post_extract_rose.dot");
- improveWeakInfixes(vg, cc);
- dumpPreRoseGraph(vg, cc.grey, "post_infix_rose.dot");
-
- /* Step 3: avoid output exposed engines if there is a strong trailing
- literal) */
- avoidSuffixes(vg, cc);
-
- /* Step 4: look for infixes/suffixes with leading .*literals
- * This can reduce the amount of work a heavily picked literal has to do and
- * reduce the amount of state used as .* is handled internally to rose. */
- lookForDoubleCut(vg, cc);
-
- if (cc.streaming) {
- lookForCleanEarlySplits(vg, cc);
- decomposeLiteralChains(vg, cc);
- }
-
- rehomeEodSuffixes(vg);
- removeRedundantLiterals(vg, cc);
-
- pruneUseless(vg);
- dumpPreRoseGraph(vg, cc.grey);
- renumber_vertices(vg);
- calcVertexOffsets(vg);
-
- return vg;
-}
-
-bool doViolet(RoseBuild &rose, const NGHolder &h, bool prefilter,
- bool last_chance, const ReportManager &rm,
- const CompileContext &cc) {
- auto vg = doInitialVioletTransform(h, last_chance, cc);
- if (num_vertices(vg) <= 2) {
- return false;
- }
-
- /* Step 5: avoid unimplementable, or overly large engines if possible */
- if (!ensureImplementable(rose, vg, last_chance, last_chance, rm, cc)) {
- return false;
- }
- dumpPreRoseGraph(vg, cc.grey, "post_ensure_rose.dot");
-
- /* Step 6: send to rose */
- bool rv = rose.addRose(vg, prefilter);
- DEBUG_PRINTF("violet: %s\n", rv ? "success" : "fail");
- return rv;
-}
-
-bool checkViolet(const ReportManager &rm, const NGHolder &h, bool prefilter,
- const CompileContext &cc) {
- auto vg = doInitialVioletTransform(h, true, cc);
- if (num_vertices(vg) <= 2) {
- return false;
- }
-
- bool rv = roseCheckRose(vg, prefilter, rm, cc);
- DEBUG_PRINTF("violet: %s\n", rv ? "success" : "fail");
- return rv;
-}
-
-}
+
+ for (const auto &e : ee) {
+ shared_ptr<NGHolder> hh = cloneHolder(h);
+ auto succ_lit = vg[target(e, vg)].s;
+ assert(isCorrectlyTopped(*hh));
+ u32 delay = removeTrailingLiteralStates(*hh, succ_lit,
+ succ_lit.length(),
+ false /* can't overhang start */);
+ if (!delay) {
+ DEBUG_PRINTF("could not remove any literal, skip over\n");
+ continue;
+ }
+
+ assert(isCorrectlyTopped(*hh));
+ trimmed[hh].emplace_back(e, delay);
+ }
+
+ if (trimmed.size() == 1) {
+ return false;
+ }
+
+ /* shift the contents to a vector so we can modify the graphs without
+ * violating the map's invariants. */
+ vector<pair<shared_ptr<NGHolder>, vector<pair<RoseInEdge, u32> > > >
+ trimmed_vec(trimmed.begin(), trimmed.end());
+ trimmed.clear();
+ for (auto &elem : trimmed_vec) {
+ shared_ptr<NGHolder> &hp = elem.first;
+ vector<pair<ue2_literal, u32>> succ_lits;
+
+ for (const auto &edge_delay : elem.second) {
+ const RoseInEdge &e = edge_delay.first;
+ u32 delay = edge_delay.second;
+ auto lit = vg[target(e, vg)].s;
+
+ vg[e].graph = hp;
+ assert(delay <= lit.length());
+ succ_lits.emplace_back(lit, delay);
+ }
+ restoreTrailingLiteralStates(*hp, succ_lits);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+#define MAX_FIND_BETTER_PREFIX_GEN 4
+#define MAX_FIND_BETTER_PREFIX_COUNT 100
+
+static
+void findBetterPrefixes(RoseInGraph &vg, const CompileContext &cc) {
+ STAGE_DEBUG_PRINTF("FIND BETTER PREFIXES\n");
+ RoseInVertex start = getStart(vg);
+
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> prefixes;
+ bool changed;
+ u32 gen = 0;
+ do {
+ DEBUG_PRINTF("gen %u\n", gen);
+ changed = false;
+ prefixes.clear();
+
+ /* find prefixes */
+ for (const RoseInEdge &e : out_edges_range(start, vg)) {
+ /* outfixes shouldn't have made it this far */
+ assert(vg[target(e, vg)].type == RIV_LITERAL);
+ if (vg[e].graph) {
+ NGHolder *h = vg[e].graph.get();
+ prefixes[h].push_back(e);
+ }
+ }
+
+ if (prefixes.size() > MAX_FIND_BETTER_PREFIX_COUNT) {
+ break;
+ }
+
+ /* look for bad prefixes and try to split */
+ for (const auto &m : prefixes) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
+ depth max_width = findMaxWidth(*h);
+ if (willBeTransient(max_width, cc)
+ || willBeAnchoredTable(max_width, cc.grey)) {
+ continue;
+ }
+
+ changed = improvePrefix(*h, vg, edges, cc);
+ }
+ } while (changed && gen++ < MAX_FIND_BETTER_PREFIX_GEN);
+}
+
+#define STRONG_LITERAL_LENGTH 20
+#define MAX_EXTRACT_STRONG_LITERAL_GRAPHS 10
+
+static
+bool extractStrongLiteral(NGHolder &h, RoseInGraph &vg,
+ const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ DEBUG_PRINTF("looking for string literal\n");
+ unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, ee, cc);
+
+ if (split && min_len(split->lit) >= STRONG_LITERAL_LENGTH) {
+ DEBUG_PRINTF("splitting simple literal\n");
+ return splitRoseEdge(h, vg, ee, *split);
+ }
+
+ return false;
+}
+
+static
+void extractStrongLiterals(RoseInGraph &vg, const CompileContext &cc) {
+ if (!cc.grey.violetExtractStrongLiterals) {
+ return;
+ }
+
+ STAGE_DEBUG_PRINTF("EXTRACT STRONG LITERALS\n");
+
+ unordered_set<NGHolder *> stuck;
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> edges_by_graph;
+ bool changed;
+
+ do {
+ changed = false;
+
+ edges_by_graph.clear();
+ for (const RoseInEdge &ve : edges_range(vg)) {
+ if (vg[source(ve, vg)].type != RIV_LITERAL) {
+ continue;
+ }
+
+ if (vg[ve].graph) {
+ NGHolder *h = vg[ve].graph.get();
+ edges_by_graph[h].push_back(ve);
+ }
+ }
+
+ if (edges_by_graph.size() > MAX_EXTRACT_STRONG_LITERAL_GRAPHS) {
+ DEBUG_PRINTF("too many graphs, stopping\n");
+ return;
+ }
+
+ for (const auto &m : edges_by_graph) {
+ NGHolder *g = m.first;
+ const auto &edges = m.second;
+ if (contains(stuck, g)) {
+ DEBUG_PRINTF("already known to be bad\n");
+ continue;
+ }
+ bool rv = extractStrongLiteral(*g, vg, edges, cc);
+ if (rv) {
+ changed = true;
+ } else {
+ stuck.insert(g);
+ }
+ }
+ } while (changed);
+}
+
+#define INFIX_STRONG_GUARD_LEN 8
+#define INFIX_MIN_SPLIT_LITERAL_LEN 12
+
+static
+bool improveInfix(NGHolder &h, RoseInGraph &vg, const vector<RoseInEdge> &ee,
+ const CompileContext &cc) {
+ unique_ptr<VertLitInfo> split = findBestNormalSplit(h, vg, ee, cc);
+
+ if (split && min_len(split->lit) >= INFIX_MIN_SPLIT_LITERAL_LEN
+ && splitRoseEdge(h, vg, ee, *split)) {
+ DEBUG_PRINTF("splitting simple literal\n");
+ return true;
+ }
+
+ DEBUG_PRINTF("trying for a netflow cut\n");
+ /* look for netflow cuts which don't produce good prefixes */
+ bool rv = doNetflowCut(h, nullptr, vg, ee, false, cc.grey, 8);
+
+ DEBUG_PRINTF("did netfow cut? = %d\n", (int)rv);
+
+ return rv;
+}
+
+/**
+ * Infixes which are weakly guarded can, in effect, act like prefixes as they
+ * will often be live. We should try to split these infixes further if they
+ * contain strong literals so that we are at least running smaller weak infixes
+ * which can hopeful be accelerated/miracled.
+ */
+static
+void improveWeakInfixes(RoseInGraph &vg, const CompileContext &cc) {
+ if (!cc.grey.violetAvoidWeakInfixes) {
+ return;
+ }
+ STAGE_DEBUG_PRINTF("IMPROVE WEAK INFIXES\n");
+
+ RoseInVertex start = getStart(vg);
+
+ unordered_set<NGHolder *> weak;
+
+ for (RoseInVertex vv : adjacent_vertices_range(start, vg)) {
+ /* outfixes shouldn't have made it this far */
+ assert(vg[vv].type == RIV_LITERAL);
+ if (vg[vv].s.length() >= INFIX_STRONG_GUARD_LEN) {
+ continue;
+ }
+
+ for (const RoseInEdge &e : out_edges_range(vv, vg)) {
+ if (vg[target(e, vg)].type != RIV_LITERAL || !vg[e].graph) {
+ continue;
+ }
+
+ NGHolder *h = vg[e].graph.get();
+ DEBUG_PRINTF("'%s' guards %p\n", dumpString(vg[vv].s).c_str(), h);
+ weak.insert(h);
+ }
+ }
+
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> weak_edges;
+ for (const RoseInEdge &ve : edges_range(vg)) {
+ NGHolder *h = vg[ve].graph.get();
+ if (contains(weak, h)) {
+ weak_edges[h].push_back(ve);
+ }
+ }
+
+ for (const auto &m : weak_edges) {
+ NGHolder *h = m.first;
+ const auto &edges = m.second;
+ improveInfix(*h, vg, edges, cc);
+ }
+}
+
+static
+void splitEdgesForSuffix(const NGHolder &base_graph, RoseInGraph &vg,
+ const vector<RoseInEdge> &ee, const VertLitInfo &split,
+ bool eod, const flat_set<ReportID> &reports) {
+ const vector<NFAVertex> &splitters = split.vv;
+ assert(!splitters.empty());
+
+ shared_ptr<NGHolder> lhs = make_shared<NGHolder>();
+ unordered_map<NFAVertex, NFAVertex> v_map;
+ cloneHolder(*lhs, base_graph, &v_map);
+ lhs->kind = NFA_INFIX;
+ clear_in_edges(lhs->accept, *lhs);
+ clear_in_edges(lhs->acceptEod, *lhs);
+ add_edge(lhs->accept, lhs->acceptEod, *lhs);
+ clearReports(*lhs);
+ for (NFAVertex v : splitters) {
+ NFAEdge e = add_edge(v_map[v], lhs->accept, *lhs);
+ if (v == base_graph.start) {
+ (*lhs)[e].tops.insert(DEFAULT_TOP);
+ }
+ (*lhs)[v_map[v]].reports.insert(0);
+
+ }
+ pruneUseless(*lhs);
+ assert(isCorrectlyTopped(*lhs));
+
+ /* create literal vertices and connect preds */
+ for (const auto &lit : split.lit) {
+ if (!can_match(*lhs, lit, is_triggered(*lhs))) {
+ continue;
+ }
+
+ DEBUG_PRINTF("best is '%s'\n", escapeString(lit).c_str());
+ RoseInVertex v = add_vertex(RoseInVertexProps::makeLiteral(lit), vg);
+
+ RoseInVertex tt;
+ if (eod) {
+ DEBUG_PRINTF("doing eod\n");
+ tt = add_vertex(RoseInVertexProps::makeAcceptEod(reports), vg);
+ } else {
+ DEBUG_PRINTF("doing non-eod\n");
+ tt = add_vertex(RoseInVertexProps::makeAccept(reports), vg);
+ }
+ add_edge(v, tt, RoseInEdgeProps(0U, 0U), vg);
+
+ for (const RoseInEdge &e : ee) {
+ RoseInVertex u = source(e, vg);
+ assert(!edge(u, v, vg).second);
+ add_edge(u, v, RoseInEdgeProps(lhs, 0U), vg);
+ }
+ }
+}
+
+#define MIN_SUFFIX_LEN 6
+
+static
+bool replaceSuffixWithInfix(const NGHolder &h, RoseInGraph &vg,
+ const vector<RoseInEdge> &suffix_edges,
+ const CompileContext &cc) {
+ DEBUG_PRINTF("inspecting suffix : %p on %zu edges\n", &h,
+ suffix_edges.size());
+ /*
+ * We would, in general, rather not have output exposed engines because
+ * once they are triggered, they must be run while infixes only have to run
+ * if the successor literal is seen. Matches from output exposed engines
+ * also have to be placed in a priority queue and interleaved with matches
+ * from other sources.
+ *
+ * Note:
+ * - if the LHS is extremely unlikely we may be better off leaving
+ * a suffix unguarded.
+ *
+ * - limited width suffixes may be less bad as they won't be continuously
+ * active, we may want to have (a) stronger controls on if we want to pick
+ * a trailing literal in these cases and/or (b) look also for literals
+ * near accept as well as right on accept
+ *
+ * TODO: improve heuristics, splitting logic.
+ */
+
+ /* we may do multiple splits corresponding to different report behaviour */
+ set<NFAVertex> seen;
+ map<pair<bool, flat_set<ReportID> >, VertLitInfo> by_reports; /* eod, rep */
+
+ for (NFAVertex v : inv_adjacent_vertices_range(h.accept, h)) {
+ set<ue2_literal> ss = getLiteralSet(h, v, false);
+ if (ss.empty()) {
+ DEBUG_PRINTF("candidate is too shitty\n");
+ return false;
+ }
+
+ VertLitInfo &vli = by_reports[make_pair(false, h[v].reports)];
+ insert(&vli.lit, ss);
+ vli.vv.push_back(v);
+ seen.insert(v);
+ }
+
+ seen.insert(h.accept);
+ for (NFAVertex v : inv_adjacent_vertices_range(h.acceptEod, h)) {
+ if (contains(seen, v)) {
+ continue;
+ }
+
+ set<ue2_literal> ss = getLiteralSet(h, v, false);
+ if (ss.empty()) {
+ DEBUG_PRINTF("candidate is too shitty\n");
+ return false;
+ }
+
+ VertLitInfo &vli = by_reports[make_pair(true, h[v].reports)];
+ insert(&vli.lit, ss);
+ vli.vv.push_back(v);
+ }
+
+ assert(!by_reports.empty());
+
+ /* TODO: how strong a min len do we want here ? */
+ u32 min_len = cc.grey.minRoseLiteralLength;
+ ENSURE_AT_LEAST(&min_len, MIN_SUFFIX_LEN);
+
+ for (auto &vli : by_reports | map_values) {
+ u64a score = sanitizeAndCompressAndScore(vli.lit);
+
+ if (vli.lit.empty()
+ || !validateRoseLiteralSetQuality(vli.lit, score, false, min_len,
+ false, false)) {
+ return false;
+ }
+ }
+
+ for (const auto &info : by_reports) {
+ DEBUG_PRINTF("splitting on simple literals\n");
+ splitEdgesForSuffix(h, vg, suffix_edges, info.second,
+ info.first.first /* eod */,
+ info.first.second /* reports */);
+ }
+
+ for (const RoseInEdge &e : suffix_edges) {
+ remove_edge(e, vg);
+ }
+ return true;
+}
+
+static
+void avoidSuffixes(RoseInGraph &vg, const CompileContext &cc) {
+ if (!cc.grey.violetAvoidSuffixes) {
+ return;
+ }
+
+ STAGE_DEBUG_PRINTF("AVOID SUFFIXES\n");
+
+ RoseInVertex accept = getPrimaryAccept(vg);
+
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> suffixes;
+
+ /* find suffixes */
+ for (const RoseInEdge &e : in_edges_range(accept, vg)) {
+ /* outfixes shouldn't have made it this far */
+ assert(vg[source(e, vg)].type == RIV_LITERAL);
+ assert(vg[e].graph); /* non suffix paths should be wired to other
+ accepts */
+ const NGHolder *h = vg[e].graph.get();
+ suffixes[h].push_back(e);
+ }
+
+ /* look at suffixes and try to split */
+ for (const auto &m : suffixes) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ replaceSuffixWithInfix(*h, vg, edges, cc);
+ }
+}
+
+static
+bool leadingDotStartLiteral(const NGHolder &h, VertLitInfo *out) {
+ if (out_degree(h.start, h) != 3) {
+ return false;
+ }
+
+ NFAVertex v = NGHolder::null_vertex();
+ NFAVertex ds = NGHolder::null_vertex();
+
+ for (NFAVertex a : adjacent_vertices_range(h.start, h)) {
+ if (a == h.startDs) {
+ continue;
+ }
+ if (h[a].char_reach.all()) {
+ ds = a;
+ if (out_degree(ds, h) != 2 || !edge(ds, ds, h).second) {
+ return false;
+ }
+ } else {
+ v = a;
+ }
+ }
+
+ if (!v || !ds || !edge(ds, v, h).second) {
+ return false;
+ }
+
+ if (h[v].char_reach.count() != 1 && !h[v].char_reach.isCaselessChar()) {
+ return false;
+ }
+
+ ue2_literal lit;
+ lit.push_back(h[v].char_reach.find_first(),
+ h[v].char_reach.isCaselessChar());
+ while (out_degree(v, h) == 1) {
+ NFAVertex vv = *adjacent_vertices(v, h).first;
+ if (h[vv].char_reach.count() != 1
+ && !h[vv].char_reach.isCaselessChar()) {
+ break;
+ }
+
+ v = vv;
+
+ lit.push_back(h[v].char_reach.find_first(),
+ h[v].char_reach.isCaselessChar());
+ }
+
+ if (is_match_vertex(v, h) && h.kind != NFA_SUFFIX) {
+ /* we have rediscovered the post-infix literal */
+ return false;
+ }
+
+ if (bad_mixed_sensitivity(lit)) {
+ make_nocase(&lit);
+ }
+
+ DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str());
+ out->vv = {v};
+ out->lit = {lit};
+ return true;
+}
+
+static
+bool lookForDoubleCut(const NGHolder &h, const vector<RoseInEdge> &ee,
+ RoseInGraph &vg, const Grey &grey) {
+ VertLitInfo info;
+ if (!leadingDotStartLiteral(h, &info)
+ || min_len(info.lit) < grey.violetDoubleCutLiteralLen) {
+ return false;
+ }
+ DEBUG_PRINTF("performing split\n");
+ return splitRoseEdge(h, vg, ee, {info});
+}
+
+static
+void lookForDoubleCut(RoseInGraph &vg, const CompileContext &cc) {
+ if (!cc.grey.violetDoubleCut) {
+ return;
+ }
+
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
+ for (const RoseInEdge &ve : edges_range(vg)) {
+ if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
+ const NGHolder *h = vg[ve].graph.get();
+ right_edges[h].push_back(ve);
+ }
+ }
+
+ for (const auto &m : right_edges) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ lookForDoubleCut(*h, edges, vg, cc.grey);
+ }
+}
+
+static
+pair<NFAVertex, ue2_literal> findLiteralBefore(const NGHolder &h, NFAVertex v) {
+ ue2_literal lit;
+ if (h[v].char_reach.count() != 1 && !h[v].char_reach.isCaselessChar()) {
+ return {v, std::move(lit) };
+ }
+ lit.push_back(h[v].char_reach.find_first(),
+ h[v].char_reach.isCaselessChar());
+
+ while (in_degree(v, h) == 1) {
+ NFAVertex vv = *inv_adjacent_vertices(v, h).first;
+ if (h[vv].char_reach.count() != 1
+ && !h[vv].char_reach.isCaselessChar()) {
+ break;
+ }
+
+ lit.push_back(h[vv].char_reach.find_first(),
+ h[vv].char_reach.isCaselessChar());
+ v = vv;
+ }
+
+ return {v, std::move(lit) };
+}
+
+static
+bool lookForDotStarPred(NFAVertex v, const NGHolder &h,
+ NFAVertex *u, NFAVertex *ds) {
+ *u = NGHolder::null_vertex();
+ *ds = NGHolder::null_vertex();
+ for (NFAVertex a : inv_adjacent_vertices_range(v, h)) {
+ if (h[a].char_reach.all()) {
+ if (!edge(a, a, h).second) {
+ return false;
+ }
+
+ if (*ds) {
+ return false;
+ }
+
+ *ds = a;
+ } else {
+ if (*u) {
+ return false;
+ }
+ *u = a;
+ }
+ }
+
+ if (!*u || !*ds) {
+ return false;
+ }
+
+ return true;
+}
+
+static
+bool trailingDotStarLiteral(const NGHolder &h, VertLitInfo *out) {
+ /* Note: there is no delay yet - so the final literal is the already
+ * discovered successor literal - we are in fact interested in the literal
+ * before it. */
+
+ if (in_degree(h.accept, h) != 1) {
+ return false;
+ }
+
+ if (in_degree(h.acceptEod, h) != 1) {
+ assert(0);
+ return false;
+ }
+
+ NFAVertex v
+ = findLiteralBefore(h, *inv_adjacent_vertices(h.accept, h).first).first;
+
+ NFAVertex u;
+ NFAVertex ds;
+
+ if (!lookForDotStarPred(v, h, &u, &ds)) {
+ return false;
+ }
+
+ v = u;
+ auto rv = findLiteralBefore(h, v);
+
+ if (!lookForDotStarPred(v, h, &u, &ds)) {
+ return false;
+ }
+
+ ue2_literal lit = reverse_literal(rv.second);
+ DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str());
+
+ if (bad_mixed_sensitivity(lit)) {
+ make_nocase(&lit);
+ }
+
+ out->vv = {v};
+ out->lit = {lit};
+ return true;
+}
+
+static
+bool lookForTrailingLiteralDotStar(const NGHolder &h,
+ const vector<RoseInEdge> &ee,
+ RoseInGraph &vg, const Grey &grey) {
+ VertLitInfo info;
+ if (!trailingDotStarLiteral(h, &info)
+ || min_len(info.lit) < grey.violetDoubleCutLiteralLen) {
+ return false;
+ }
+ DEBUG_PRINTF("performing split\n");
+ return splitRoseEdge(h, vg, ee, info);
+}
+
+/* In streaming mode, active engines have to be caught up at stream boundaries
+ * and have to be stored in stream state, so we prefer to decompose patterns
+ * in to literals with no state between them if possible. */
+static
+void decomposeLiteralChains(RoseInGraph &vg, const CompileContext &cc) {
+ if (!cc.grey.violetLiteralChains) {
+ return;
+ }
+
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
+ bool changed;
+ do {
+ changed = false;
+
+ right_edges.clear();
+ for (const RoseInEdge &ve : edges_range(vg)) {
+ if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
+ const NGHolder *h = vg[ve].graph.get();
+ right_edges[h].push_back(ve);
+ }
+ }
+
+ for (const auto &m : right_edges) {
+ const NGHolder *h = m.first;
+ const vector<RoseInEdge> &ee = m.second;
+ bool rv = lookForDoubleCut(*h, ee, vg, cc.grey);
+ if (!rv && h->kind != NFA_SUFFIX) {
+ rv = lookForTrailingLiteralDotStar(*h, ee, vg, cc.grey);
+ }
+ changed |= rv;
+ }
+ } while (changed);
+}
+
+static
+bool lookForCleanSplit(const NGHolder &h, const vector<RoseInEdge> &ee,
+ RoseInGraph &vg, const CompileContext &cc) {
+ unique_ptr<VertLitInfo> split = findBestCleanSplit(h, cc);
+
+ if (split) {
+ return splitRoseEdge(h, vg, {ee}, *split);
+ }
+
+ return false;
+}
+
+#define MAX_DESIRED_CLEAN_SPLIT_DEPTH 4
+
+static
+void lookForCleanEarlySplits(RoseInGraph &vg, const CompileContext &cc) {
+ u32 gen = 0;
+
+ insertion_ordered_set<RoseInVertex> prev({getStart(vg)});
+ insertion_ordered_set<RoseInVertex> curr;
+
+ while (gen < MAX_DESIRED_CLEAN_SPLIT_DEPTH) {
+ curr.clear();
+ for (RoseInVertex u : prev) {
+ for (auto v : adjacent_vertices_range(u, vg)) {
+ curr.insert(v);
+ }
+ }
+
+ insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> rightfixes;
+ for (RoseInVertex v : curr) {
+ for (const RoseInEdge &e : out_edges_range(v, vg)) {
+ if (vg[e].graph) {
+ NGHolder *h = vg[e].graph.get();
+ rightfixes[h].push_back(e);
+ }
+ }
+ }
+
+ for (const auto &m : rightfixes) {
+ const NGHolder *h = m.first;
+ const auto &edges = m.second;
+ lookForCleanSplit(*h, edges, vg, cc);
+ }
+
+ prev = std::move(curr);
+ gen++;
+ }
+}
+
+static
+void rehomeEodSuffixes(RoseInGraph &vg) {
+ // Find edges to accept with EOD-anchored graphs that we can move over to
+ // acceptEod.
+ vector<RoseInEdge> acc_edges;
+ for (const auto &e : edges_range(vg)) {
+ if (vg[target(e, vg)].type != RIV_ACCEPT) {
+ continue;
+ }
+ if (vg[e].haig || !vg[e].graph) {
+ continue;
+ }
+
+ const NGHolder &h = *vg[e].graph;
+
+ if (in_degree(h.accept, h)) {
+ DEBUG_PRINTF("graph isn't eod anchored\n");
+ continue;
+ }
+
+ acc_edges.push_back(e);
+ }
+
+ for (const RoseInEdge &e : acc_edges) {
+ // Move this edge from accept to acceptEod
+ RoseInVertex w = add_vertex(RoseInVertexProps::makeAcceptEod(), vg);
+ add_edge(source(e, vg), w, vg[e], vg);
+ remove_edge(e, vg);
+ }
+
+ /* old accept vertices will be tidied up by final pruneUseless() call */
+}
+
+static
+bool tryForEarlyDfa(const NGHolder &h, const CompileContext &cc) {
+ switch (h.kind) {
+ case NFA_OUTFIX: /* 'prefix' of eod */
+ case NFA_PREFIX:
+ return cc.grey.earlyMcClellanPrefix;
+ case NFA_INFIX:
+ return cc.grey.earlyMcClellanInfix;
+ case NFA_SUFFIX:
+ return cc.grey.earlyMcClellanSuffix;
+ default:
+ DEBUG_PRINTF("kind %u\n", (u32)h.kind);
+ assert(0);
+ return false;
+ }
+}
+
+static
+vector<vector<CharReach>> getDfaTriggers(RoseInGraph &vg,
+ const vector<RoseInEdge> &edges,
+ bool *single_trigger) {
+ vector<vector<CharReach>> triggers;
+ u32 min_offset = ~0U;
+ u32 max_offset = 0;
+ for (const auto &e : edges) {
+ RoseInVertex s = source(e, vg);
+ if (vg[s].type == RIV_LITERAL) {
+ triggers.push_back(as_cr_seq(vg[s].s));
+ }
+ ENSURE_AT_LEAST(&max_offset, vg[s].max_offset);
+ LIMIT_TO_AT_MOST(&min_offset, vg[s].min_offset);
+ }
+
+ *single_trigger = min_offset == max_offset;
+ DEBUG_PRINTF("trigger offset (%u, %u)\n", min_offset, max_offset);
+
+ return triggers;
+}
+
+static
+bool doEarlyDfa(RoseBuild &rose, RoseInGraph &vg, NGHolder &h,
+ const vector<RoseInEdge> &edges, bool final_chance,
+ const ReportManager &rm, const CompileContext &cc) {
+ DEBUG_PRINTF("trying for dfa\n");
+
+ bool single_trigger;
+ for (const auto &e : edges) {
+ if (vg[target(e, vg)].type == RIV_ACCEPT_EOD) {
+ /* TODO: support eod prefixes */
+ return false;
+ }
+ }
+
+ auto triggers = getDfaTriggers(vg, edges, &single_trigger);
+
+ /* TODO: literal delay things */
+ if (!generates_callbacks(h)) {
+ set_report(h, rose.getNewNfaReport());
+ }
+
+ shared_ptr<raw_dfa> dfa = buildMcClellan(h, &rm, single_trigger, triggers,
+ cc.grey, final_chance);
+
+ if (!dfa) {
+ return false;
+ }
+
+ DEBUG_PRINTF("dfa ok\n");
+ for (const auto &e : edges) {
+ vg[e].dfa = dfa;
+ }
+
+ return true;
+}
+
+#define MAX_EDGES_FOR_IMPLEMENTABILITY 50
+
+static
+bool splitForImplementability(RoseInGraph &vg, NGHolder &h,
+ const vector<RoseInEdge> &edges,
+ const CompileContext &cc) {
+ vector<pair<ue2_literal, u32>> succ_lits;
+ DEBUG_PRINTF("trying to split %s with %zu vertices on %zu edges\n",
+ to_string(h.kind).c_str(), num_vertices(h), edges.size());
+
+ if (edges.size() > MAX_EDGES_FOR_IMPLEMENTABILITY) {
+ return false;
+ }
+
+ if (!generates_callbacks(h)) {
+ for (const auto &e : edges) {
+ const auto &lit = vg[target(e, vg)].s;
+ u32 delay = vg[e].graph_lag;
+ vg[e].graph_lag = 0;
+
+ assert(delay <= lit.length());
+ succ_lits.emplace_back(lit, delay);
+ }
+ restoreTrailingLiteralStates(h, succ_lits);
+ }
+
+ unique_ptr<VertLitInfo> split;
+ bool last_chance = true;
+ if (h.kind == NFA_PREFIX) {
+ auto depths = calcDepths(h);
+
+ split = findBestPrefixSplit(h, depths, vg, edges, last_chance, cc);
+ } else {
+ split = findBestLastChanceSplit(h, vg, edges, cc);
+ }
+
+ if (split && splitRoseEdge(h, vg, edges, *split)) {
+ DEBUG_PRINTF("split on simple literal\n");
+ return true;
+ }
+
+ DEBUG_PRINTF("trying to netflow\n");
+ bool rv = doNetflowCut(h, nullptr, vg, edges, false, cc.grey);
+ DEBUG_PRINTF("done\n");
+
+ return rv;
+}
+
+#define MAX_IMPLEMENTABLE_SPLITS 50
+
+bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
+ bool final_chance, const ReportManager &rm,
+ const CompileContext &cc) {
+ DEBUG_PRINTF("checking for impl %d\n", final_chance);
+ bool changed = false;
+ bool need_to_recalc = false;
+ u32 added_count = 0;
+ unordered_set<shared_ptr<NGHolder>> good; /* known to be implementable */
+ do {
+ changed = false;
+ DEBUG_PRINTF("added %u\n", added_count);
+ insertion_ordered_map<shared_ptr<NGHolder>,
+ vector<RoseInEdge>> edges_by_graph;
+ for (const RoseInEdge &ve : edges_range(vg)) {
+ if (vg[ve].graph && !vg[ve].dfa) {
+ auto &h = vg[ve].graph;
+ edges_by_graph[h].push_back(ve);
+ }
+ }
+ for (auto &m : edges_by_graph) {
+ auto &h = m.first;
+ if (contains(good, h)) {
+ continue;
+ }
+ reduceGraphEquivalences(*h, cc);
+ if (isImplementableNFA(*h, &rm, cc)) {
+ good.insert(h);
+ continue;
+ }
+
+ const auto &edges = m.second;
+
+ if (tryForEarlyDfa(*h, cc) &&
+ doEarlyDfa(rose, vg, *h, edges, final_chance, rm, cc)) {
+ continue;
+ }
+
+ DEBUG_PRINTF("eek\n");
+ if (!allow_changes) {
+ return false;
+ }
+
+ if (splitForImplementability(vg, *h, edges, cc)) {
+ added_count++;
+ if (added_count > MAX_IMPLEMENTABLE_SPLITS) {
+ DEBUG_PRINTF("added_count hit limit\n");
+ return false;
+ }
+ changed = true;
+ continue;
+ }
+
+ return false;
+ }
+
+ assert(added_count <= MAX_IMPLEMENTABLE_SPLITS);
+
+ if (changed) {
+ removeRedundantLiterals(vg, cc);
+ pruneUseless(vg);
+ need_to_recalc = true;
+ }
+ } while (changed);
+
+ if (need_to_recalc) {
+ renumber_vertices(vg);
+ calcVertexOffsets(vg);
+ }
+
+ DEBUG_PRINTF("ok!\n");
+ return true;
+}
+
+static
+RoseInGraph doInitialVioletTransform(const NGHolder &h, bool last_chance,
+ const CompileContext &cc) {
+ assert(!can_never_match(h));
+
+ RoseInGraph vg = populateTrivialGraph(h);
+
+ if (!cc.grey.allowViolet) {
+ return vg;
+ }
+
+ /* Avoid running the Violet analysis at all on graphs with no vertices with
+ * small reach, since we will not be able to extract any literals. */
+ if (!hasNarrowReachVertex(h)) {
+ DEBUG_PRINTF("fail, no vertices with small reach\n");
+ return vg;
+ }
+
+ DEBUG_PRINTF("hello world\n");
+
+ /* Step 1: avoid outfixes as we always have to run them. */
+ avoidOutfixes(vg, last_chance, cc);
+
+ if (num_vertices(vg) <= 2) {
+ return vg; /* unable to transform pattern */
+ }
+
+ removeRedundantPrefixes(vg);
+ dumpPreRoseGraph(vg, cc.grey, "pre_prefix_rose.dot");
+
+ /* Step 2: avoid non-transient prefixes (esp in streaming mode) */
+ findBetterPrefixes(vg, cc);
+
+ dumpPreRoseGraph(vg, cc.grey, "post_prefix_rose.dot");
+
+ extractStrongLiterals(vg, cc);
+ dumpPreRoseGraph(vg, cc.grey, "post_extract_rose.dot");
+ improveWeakInfixes(vg, cc);
+ dumpPreRoseGraph(vg, cc.grey, "post_infix_rose.dot");
+
+ /* Step 3: avoid output exposed engines if there is a strong trailing
+ literal) */
+ avoidSuffixes(vg, cc);
+
+ /* Step 4: look for infixes/suffixes with leading .*literals
+ * This can reduce the amount of work a heavily picked literal has to do and
+ * reduce the amount of state used as .* is handled internally to rose. */
+ lookForDoubleCut(vg, cc);
+
+ if (cc.streaming) {
+ lookForCleanEarlySplits(vg, cc);
+ decomposeLiteralChains(vg, cc);
+ }
+
+ rehomeEodSuffixes(vg);
+ removeRedundantLiterals(vg, cc);
+
+ pruneUseless(vg);
+ dumpPreRoseGraph(vg, cc.grey);
+ renumber_vertices(vg);
+ calcVertexOffsets(vg);
+
+ return vg;
+}
+
+bool doViolet(RoseBuild &rose, const NGHolder &h, bool prefilter,
+ bool last_chance, const ReportManager &rm,
+ const CompileContext &cc) {
+ auto vg = doInitialVioletTransform(h, last_chance, cc);
+ if (num_vertices(vg) <= 2) {
+ return false;
+ }
+
+ /* Step 5: avoid unimplementable, or overly large engines if possible */
+ if (!ensureImplementable(rose, vg, last_chance, last_chance, rm, cc)) {
+ return false;
+ }
+ dumpPreRoseGraph(vg, cc.grey, "post_ensure_rose.dot");
+
+ /* Step 6: send to rose */
+ bool rv = rose.addRose(vg, prefilter);
+ DEBUG_PRINTF("violet: %s\n", rv ? "success" : "fail");
+ return rv;
+}
+
+bool checkViolet(const ReportManager &rm, const NGHolder &h, bool prefilter,
+ const CompileContext &cc) {
+ auto vg = doInitialVioletTransform(h, true, cc);
+ if (num_vertices(vg) <= 2) {
+ return false;
+ }
+
+ bool rv = roseCheckRose(vg, prefilter, rm, cc);
+ DEBUG_PRINTF("violet: %s\n", rv ? "success" : "fail");
+ return rv;
+}
+
+}
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_violet.h b/contrib/libs/hyperscan/src/nfagraph/ng_violet.h
index 5158c43a08f..3fe57dbfaa1 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_violet.h
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_violet.h
@@ -1,65 +1,65 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Violet method of rose construction from NGHolder.
- */
-
-#ifndef NG_VIOLET_H
-#define NG_VIOLET_H
-
-#include "ue2common.h"
-
-namespace ue2 {
-
-class NGHolder;
-class RoseBuild;
-
-struct CompileContext;
-class ReportManager;
-struct RoseInGraph;
-
-/** \brief Attempt to consume the entire pattern in graph \a h with Rose.
- * Returns true if successful. */
-bool doViolet(RoseBuild &rose, const NGHolder &h, bool prefilter,
- bool last_chance, const ReportManager &rm,
- const CompileContext &cc);
-
-bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
- bool final_chance, const ReportManager &rm,
- const CompileContext &cc);
-
-/** \brief True if the pattern in \a h is consumable by Rose/Violet. This
- * function may be conservative (return false even if supported) for
- * efficiency. */
-bool checkViolet(const ReportManager &rm, const NGHolder &h, bool prefilter,
- const CompileContext &cc);
-
-} // namespace ue2
-
-#endif
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Violet method of rose construction from NGHolder.
+ */
+
+#ifndef NG_VIOLET_H
+#define NG_VIOLET_H
+
+#include "ue2common.h"
+
+namespace ue2 {
+
+class NGHolder;
+class RoseBuild;
+
+struct CompileContext;
+class ReportManager;
+struct RoseInGraph;
+
+/** \brief Attempt to consume the entire pattern in graph \a h with Rose.
+ * Returns true if successful. */
+bool doViolet(RoseBuild &rose, const NGHolder &h, bool prefilter,
+ bool last_chance, const ReportManager &rm,
+ const CompileContext &cc);
+
+bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
+ bool final_chance, const ReportManager &rm,
+ const CompileContext &cc);
+
+/** \brief True if the pattern in \a h is consumable by Rose/Violet. This
+ * function may be conservative (return false even if supported) for
+ * efficiency. */
+bool checkViolet(const ReportManager &rm, const NGHolder &h, bool prefilter,
+ const CompileContext &cc);
+
+} // namespace ue2
+
+#endif
diff --git a/contrib/libs/hyperscan/src/nfagraph/ng_width.cpp b/contrib/libs/hyperscan/src/nfagraph/ng_width.cpp
index f33d5d5689d..219241ca550 100644
--- a/contrib/libs/hyperscan/src/nfagraph/ng_width.cpp
+++ b/contrib/libs/hyperscan/src/nfagraph/ng_width.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@
#include "ue2common.h"
#include "util/depth.h"
#include "util/graph.h"
-#include "util/graph_small_color_map.h"
+#include "util/graph_small_color_map.h"
#include <deque>
#include <vector>
@@ -59,18 +59,18 @@ namespace {
struct SpecialEdgeFilter {
SpecialEdgeFilter() {}
explicit SpecialEdgeFilter(const NGHolder &h_in) : h(&h_in) {}
- SpecialEdgeFilter(const NGHolder &h_in, u32 top_in)
+ SpecialEdgeFilter(const NGHolder &h_in, u32 top_in)
: h(&h_in), single_top(true), top(top_in) {}
bool operator()(const NFAEdge &e) const {
- NFAVertex u = source(e, *h);
- NFAVertex v = target(e, *h);
- if ((is_any_start(u, *h) && is_any_start(v, *h)) ||
- (is_any_accept(u, *h) && is_any_accept(v, *h))) {
+ NFAVertex u = source(e, *h);
+ NFAVertex v = target(e, *h);
+ if ((is_any_start(u, *h) && is_any_start(v, *h)) ||
+ (is_any_accept(u, *h) && is_any_accept(v, *h))) {
return false;
}
if (single_top) {
- if (u == h->start && !contains((*h)[e].tops, top)) {
+ if (u == h->start && !contains((*h)[e].tops, top)) {
return false;
}
if (u == h->startDs) {
@@ -95,7 +95,7 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
return depth::unreachable();
}
- boost::filtered_graph<NGHolder, SpecialEdgeFilter> g(h, filter);
+ boost::filtered_graph<NGHolder, SpecialEdgeFilter> g(h, filter);
assert(hasCorrectlyNumberedVertices(h));
const size_t num = num_vertices(h);
@@ -107,10 +107,10 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
// Since we are interested in the single-source shortest paths on a graph
// with the same weight on every edge, using BFS will be faster than
// Dijkstra here.
- breadth_first_search(g, src,
+ breadth_first_search(g, src,
visitor(make_bfs_visitor(record_distances(
make_iterator_property_map(distance.begin(), index_map),
- boost::on_tree_edge()))));
+ boost::on_tree_edge()))));
DEBUG_PRINTF("d[accept]=%s, d[acceptEod]=%s\n",
distance.at(NODE_ACCEPT).str().c_str(),
@@ -130,7 +130,7 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
static
depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
NFAVertex src) {
- if (isLeafNode(src, h)) {
+ if (isLeafNode(src, h)) {
return depth::unreachable();
}
@@ -139,31 +139,31 @@ depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
return depth::infinity();
}
- boost::filtered_graph<NGHolder, SpecialEdgeFilter> g(h, filter);
+ boost::filtered_graph<NGHolder, SpecialEdgeFilter> g(h, filter);
assert(hasCorrectlyNumberedVertices(h));
const size_t num = num_vertices(h);
vector<int> distance(num);
- auto colors = make_small_color_map(h);
+ auto colors = make_small_color_map(h);
auto index_map = get(&NFAGraphVertexProps::index, g);
// DAG shortest paths with negative edge weights.
- dag_shortest_paths(g, src,
+ dag_shortest_paths(g, src,
distance_map(make_iterator_property_map(distance.begin(), index_map))
.weight_map(boost::make_constant_property<NFAEdge>(-1))
- .color_map(colors));
+ .color_map(colors));
depth acceptDepth, acceptEodDepth;
- if (get(colors, h.accept) == small_color::white) {
+ if (get(colors, h.accept) == small_color::white) {
acceptDepth = depth::unreachable();
} else {
- acceptDepth = depth(-1 * distance.at(NODE_ACCEPT));
+ acceptDepth = depth(-1 * distance.at(NODE_ACCEPT));
}
- if (get(colors, h.acceptEod) == small_color::white) {
+ if (get(colors, h.acceptEod) == small_color::white) {
acceptEodDepth = depth::unreachable();
} else {
- acceptEodDepth = depth(-1 * distance.at(NODE_ACCEPT_EOD));
+ acceptEodDepth = depth(-1 * distance.at(NODE_ACCEPT_EOD));
}
depth d;
diff --git a/contrib/libs/hyperscan/src/parser/ComponentCondReference.h b/contrib/libs/hyperscan/src/parser/ComponentCondReference.h
index 91c560ad894..c0ee9ac3ac2 100644
--- a/contrib/libs/hyperscan/src/parser/ComponentCondReference.h
+++ b/contrib/libs/hyperscan/src/parser/ComponentCondReference.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -46,9 +46,9 @@ class ComponentCondReference : public ComponentSequence {
friend class ReferenceVisitor;
friend class PrintVisitor;
public:
- explicit ComponentCondReference(unsigned ref);
- explicit ComponentCondReference(const std::string &name);
- explicit ComponentCondReference(std::unique_ptr<Component> c);
+ explicit ComponentCondReference(unsigned ref);
+ explicit ComponentCondReference(const std::string &name);
+ explicit ComponentCondReference(std::unique_ptr<Component> c);
~ComponentCondReference() override;
ComponentCondReference *clone() const override;
diff --git a/contrib/libs/hyperscan/src/parser/ComponentRepeat.cpp b/contrib/libs/hyperscan/src/parser/ComponentRepeat.cpp
index 47bc7725299..09f59d05ec8 100644
--- a/contrib/libs/hyperscan/src/parser/ComponentRepeat.cpp
+++ b/contrib/libs/hyperscan/src/parser/ComponentRepeat.cpp
@@ -87,7 +87,7 @@ ComponentRepeat::ComponentRepeat(const ComponentRepeat &other)
type(other.type), sub_comp(unique_ptr<Component>(other.sub_comp->clone())),
m_min(other.m_min), m_max(other.m_max),
m_firsts(other.m_firsts), m_lasts(other.m_lasts),
- posFirst(other.posFirst), posLast(other.posLast) {}
+ posFirst(other.posFirst), posLast(other.posLast) {}
bool ComponentRepeat::empty() const {
return m_min == 0 || sub_comp->empty();
@@ -174,24 +174,24 @@ void ComponentRepeat::notePositions(GlushkovBuildState &bs) {
}
recordPosBounds(posFirst, bs.getBuilder().numVertices());
-
- // Each optional repeat has an epsilon at the end of its firsts list.
- for (u32 i = m_min; i < m_firsts.size(); i++) {
- m_firsts[i].push_back(GlushkovBuildState::POS_EPSILON);
- }
-
+
+ // Each optional repeat has an epsilon at the end of its firsts list.
+ for (u32 i = m_min; i < m_firsts.size(); i++) {
+ m_firsts[i].push_back(GlushkovBuildState::POS_EPSILON);
+ }
+
}
vector<PositionInfo> ComponentRepeat::first() const {
- if (!m_max) {
- return {};
- }
-
- assert(!m_firsts.empty()); // notePositions should already have run
- const vector<PositionInfo> &firsts = m_firsts.front();
- DEBUG_PRINTF("firsts = %s\n",
- dumpPositions(begin(firsts), end(firsts)).c_str());
- return firsts;
+ if (!m_max) {
+ return {};
+ }
+
+ assert(!m_firsts.empty()); // notePositions should already have run
+ const vector<PositionInfo> &firsts = m_firsts.front();
+ DEBUG_PRINTF("firsts = %s\n",
+ dumpPositions(begin(firsts), end(firsts)).c_str());
+ return firsts;
}
void ComponentRepeat::buildFollowSet(GlushkovBuildState &bs,
@@ -218,7 +218,7 @@ void ComponentRepeat::buildFollowSet(GlushkovBuildState &bs,
}
}
- wireRepeats(bs);
+ wireRepeats(bs);
DEBUG_PRINTF("leave\n");
}
@@ -234,7 +234,7 @@ void ComponentRepeat::optimise(bool connected_to_sds) {
}
bool ComponentRepeat::vacuous_everywhere() const {
- return !m_min || sub_comp->vacuous_everywhere();
+ return !m_min || sub_comp->vacuous_everywhere();
}
bool ComponentRepeat::checkEmbeddedStartAnchor(bool at_start) const {
@@ -288,24 +288,24 @@ vector<PositionInfo> ComponentRepeat::last() const {
assert(!m_firsts.empty()); // notePositions should already have run
assert(!m_lasts.empty());
- const auto &l = m_min ? m_lasts[m_min - 1] : m_lasts[0];
- lasts.insert(lasts.end(), l.begin(), l.end());
-
+ const auto &l = m_min ? m_lasts[m_min - 1] : m_lasts[0];
+ lasts.insert(lasts.end(), l.begin(), l.end());
+
if (!m_min || m_min != m_lasts.size()) {
lasts.insert(lasts.end(), m_lasts.back().begin(), m_lasts.back().end());
}
-
- DEBUG_PRINTF("lasts = %s\n",
- dumpPositions(lasts.begin(), lasts.end()).c_str());
+
+ DEBUG_PRINTF("lasts = %s\n",
+ dumpPositions(lasts.begin(), lasts.end()).c_str());
return lasts;
}
-void ComponentRepeat::wireRepeats(GlushkovBuildState &bs) {
+void ComponentRepeat::wireRepeats(GlushkovBuildState &bs) {
/* note: m_lasts[0] already valid */
u32 copies = m_firsts.size();
const bool isEmpty = sub_comp->empty();
- const vector<PositionInfo> &optLasts =
- m_min ? m_lasts[m_min - 1] : m_lasts[0];
+ const vector<PositionInfo> &optLasts =
+ m_min ? m_lasts[m_min - 1] : m_lasts[0];
if (!copies) {
goto inf_check;
@@ -324,7 +324,7 @@ void ComponentRepeat::wireRepeats(GlushkovBuildState &bs) {
DEBUG_PRINTF("wiring up %d optional repeats\n", copies - m_min);
for (u32 rep = MAX(m_min, 1); rep < copies; rep++) {
vector<PositionInfo> lasts = m_lasts[rep - 1];
- if (rep != m_min) {
+ if (rep != m_min) {
lasts.insert(lasts.end(), optLasts.begin(), optLasts.end());
sort(lasts.begin(), lasts.end());
lasts.erase(unique(lasts.begin(), lasts.end()), lasts.end());
diff --git a/contrib/libs/hyperscan/src/parser/ComponentRepeat.h b/contrib/libs/hyperscan/src/parser/ComponentRepeat.h
index 8565f1bb261..8905bfcf5ef 100644
--- a/contrib/libs/hyperscan/src/parser/ComponentRepeat.h
+++ b/contrib/libs/hyperscan/src/parser/ComponentRepeat.h
@@ -42,31 +42,31 @@
namespace ue2 {
-/**
- * \brief Encapsulates a repeat of a subexpression ('*', '+', '?', '{M,N}',
+/**
+ * \brief Encapsulates a repeat of a subexpression ('*', '+', '?', '{M,N}',
* etc).
*
- * ASCII Art Time:
+ * ASCII Art Time:
*
* Our standard representation of standard repeats. Other constructions (fan-in
* vs fan-out) would also be possible and equivalent for our purposes.
*
* {n,m}
*
- * S->M->M->M->O->O->O->T
- * | ^ ^ ^
- * | | | |
- * \-----------/
+ * S->M->M->M->O->O->O->T
+ * | ^ ^ ^
+ * | | | |
+ * \-----------/
*
* {0,m}
*
- * /-----------\
- * | |
- * | V
- * S->O->O->O->T
- * | ^ ^ ^
- * | | | |
- * \--------/
+ * /-----------\
+ * | |
+ * | V
+ * S->O->O->O->T
+ * | ^ ^ ^
+ * | | | |
+ * \--------/
*
*/
class ComponentRepeat : public Component {
@@ -121,7 +121,7 @@ public:
protected:
void postSubNotePositionHook();
- void wireRepeats(GlushkovBuildState &bs);
+ void wireRepeats(GlushkovBuildState &bs);
std::unique_ptr<Component> sub_comp;
u32 m_min;
diff --git a/contrib/libs/hyperscan/src/parser/Parser.h b/contrib/libs/hyperscan/src/parser/Parser.h
index 69844eed7e5..a034a18fc12 100644
--- a/contrib/libs/hyperscan/src/parser/Parser.h
+++ b/contrib/libs/hyperscan/src/parser/Parser.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -69,7 +69,7 @@ struct ParseMode {
*
* This call will throw a ParseError on failure.
*/
-std::unique_ptr<Component> parse(const char *ptr, ParseMode &mode);
+std::unique_ptr<Component> parse(const char *ptr, ParseMode &mode);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/parser/Parser.rl6 b/contrib/libs/hyperscan/src/parser/Parser.rl6
index 0b529f995cb..8643aebfc6f 100644
--- a/contrib/libs/hyperscan/src/parser/Parser.rl6
+++ b/contrib/libs/hyperscan/src/parser/Parser.rl6
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@
/* Parser.cpp is a built source, may not be in same dir as parser files */
#include "parser/check_refs.h"
-#include "parser/control_verbs.h"
+#include "parser/control_verbs.h"
#include "parser/ComponentAlternation.h"
#include "parser/ComponentAssertion.h"
#include "parser/ComponentAtomicGroup.h"
@@ -53,7 +53,7 @@
#include "parser/Parser.h"
#include "ue2common.h"
#include "util/compare.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/make_unique.h"
#include "util/unicode_def.h"
#include "util/verify_types.h"
@@ -116,7 +116,7 @@ unsigned parseAsDecimal(unsigned oct) {
static constexpr u32 MAX_NUMBER = INT_MAX;
static
-void pushDec(u32 *acc, char raw_digit) {
+void pushDec(u32 *acc, char raw_digit) {
assert(raw_digit >= '0' && raw_digit <= '9');
u32 digit_val = raw_digit - '0';
@@ -130,7 +130,7 @@ void pushDec(u32 *acc, char raw_digit) {
}
static
-void pushOct(u32 *acc, char raw_digit) {
+void pushOct(u32 *acc, char raw_digit) {
assert(raw_digit >= '0' && raw_digit <= '7');
u32 digit_val = raw_digit - '0';
@@ -169,7 +169,7 @@ ComponentSequence *enterSequence(ComponentSequence *parent,
}
static
-void addLiteral(ComponentSequence *currentSeq, char c, const ParseMode &mode) {
+void addLiteral(ComponentSequence *currentSeq, char c, const ParseMode &mode) {
if (mode.utf8 && mode.caseless) {
/* leverage ComponentClass to generate the vertices */
auto cc = getComponentClass(mode);
@@ -196,7 +196,7 @@ void addEscaped(ComponentSequence *currentSeq, unichar accum,
if (accum > 255) {
throw LocatedParseError(err_msg);
}
- addLiteral(currentSeq, (char)accum, mode);
+ addLiteral(currentSeq, (char)accum, mode);
}
}
@@ -216,7 +216,7 @@ void addEscapedHex(ComponentSequence *currentSeq, unichar accum,
#define SLASH_C_ERROR "\\c must be followed by an ASCII character"
static
-u8 decodeCtrl(char raw) {
+u8 decodeCtrl(char raw) {
if (raw & 0x80) {
throw LocatedParseError(SLASH_C_ERROR);
}
@@ -224,8 +224,8 @@ u8 decodeCtrl(char raw) {
}
static
-unichar readUtf8CodePoint2c(const char *s) {
- auto *ts = (const u8 *)s;
+unichar readUtf8CodePoint2c(const char *s) {
+ auto *ts = (const u8 *)s;
assert(ts[0] >= 0xc0 && ts[0] < 0xe0);
assert(ts[1] >= 0x80 && ts[1] < 0xc0);
unichar val = ts[0] & 0x1f;
@@ -237,8 +237,8 @@ unichar readUtf8CodePoint2c(const char *s) {
}
static
-unichar readUtf8CodePoint3c(const char *s) {
- auto *ts = (const u8 *)s;
+unichar readUtf8CodePoint3c(const char *s) {
+ auto *ts = (const u8 *)s;
assert(ts[0] >= 0xe0 && ts[0] < 0xf0);
assert(ts[1] >= 0x80 && ts[1] < 0xc0);
assert(ts[2] >= 0x80 && ts[2] < 0xc0);
@@ -253,8 +253,8 @@ unichar readUtf8CodePoint3c(const char *s) {
}
static
-unichar readUtf8CodePoint4c(const char *s) {
- auto *ts = (const u8 *)s;
+unichar readUtf8CodePoint4c(const char *s) {
+ auto *ts = (const u8 *)s;
assert(ts[0] >= 0xf0 && ts[0] < 0xf8);
assert(ts[1] >= 0x80 && ts[1] < 0xc0);
assert(ts[2] >= 0x80 && ts[2] < 0xc0);
@@ -276,8 +276,8 @@ unichar readUtf8CodePoint4c(const char *s) {
action throwUnsupportedEscape {
ostringstream str;
- str << "'\\" << *(ts + 1) << "' at index " << ts - ptr
- << " not supported in a character class.";
+ str << "'\\" << *(ts + 1) << "' at index " << ts - ptr
+ << " not supported in a character class.";
throw ParseError(str.str());
}
action unsupportedProperty {
@@ -549,25 +549,25 @@ unichar readUtf8CodePoint4c(const char *s) {
#############################################################
readVerb := |*
'UTF8)' => {
- throw LocatedParseError("(*UTF8) must be at start of "
- "expression, encountered");
+ throw LocatedParseError("(*UTF8) must be at start of "
+ "expression, encountered");
+ };
+ 'UTF)' => {
+ throw LocatedParseError("(*UTF) must be at start of "
+ "expression, encountered");
};
- 'UTF)' => {
- throw LocatedParseError("(*UTF) must be at start of "
- "expression, encountered");
- };
'UCP)' => {
- throw LocatedParseError("(*UCP) must be at start of "
- "expression, encountered");
+ throw LocatedParseError("(*UCP) must be at start of "
+ "expression, encountered");
};
- # Use the control verb mini-parser to report an error for this
- # unsupported/unknown verb.
- [^)]+ ')' => {
- ParseMode temp_mode;
- assert(ts - 2 >= ptr); // parser needs the '(*' at the start too.
- read_control_verbs(ts - 2, te, (ts - 2 - ptr), temp_mode);
- assert(0); // Should have thrown a parse error.
- throw LocatedParseError("Unknown control verb");
+ # Use the control verb mini-parser to report an error for this
+ # unsupported/unknown verb.
+ [^)]+ ')' => {
+ ParseMode temp_mode;
+ assert(ts - 2 >= ptr); // parser needs the '(*' at the start too.
+ read_control_verbs(ts - 2, te, (ts - 2 - ptr), temp_mode);
+ assert(0); // Should have thrown a parse error.
+ throw LocatedParseError("Unknown control verb");
};
any => {
throw LocatedParseError("Unknown control verb");
@@ -976,13 +976,13 @@ unichar readUtf8CodePoint4c(const char *s) {
};
'\\o{' [0-7]+ '}' => {
- string oct(ts + 3, te - ts - 4);
- unsigned long val;
- try {
- val = stoul(oct, nullptr, 8);
- } catch (const std::out_of_range &) {
- val = MAX_UNICODE + 1;
- }
+ string oct(ts + 3, te - ts - 4);
+ unsigned long val;
+ try {
+ val = stoul(oct, nullptr, 8);
+ } catch (const std::out_of_range &) {
+ val = MAX_UNICODE + 1;
+ }
if ((!mode.utf8 && val > 255) || val > MAX_UNICODE) {
throw LocatedParseError("Value in \\o{...} sequence is too large");
}
@@ -1006,13 +1006,13 @@ unichar readUtf8CodePoint4c(const char *s) {
};
# Unicode Hex
'\\x{' xdigit+ '}' => {
- string hex(ts + 3, te - ts - 4);
- unsigned long val;
- try {
- val = stoul(hex, nullptr, 16);
- } catch (const std::out_of_range &) {
- val = MAX_UNICODE + 1;
- }
+ string hex(ts + 3, te - ts - 4);
+ unsigned long val;
+ try {
+ val = stoul(hex, nullptr, 16);
+ } catch (const std::out_of_range &) {
+ val = MAX_UNICODE + 1;
+ }
if (val > MAX_UNICODE) {
throw LocatedParseError("Value in \\x{...} sequence is too large");
}
@@ -1101,7 +1101,7 @@ unichar readUtf8CodePoint4c(const char *s) {
# Literal character
(any - ']') => {
- currentCls->add((u8)*ts);
+ currentCls->add((u8)*ts);
};
']' => {
@@ -1155,40 +1155,40 @@ unichar readUtf8CodePoint4c(const char *s) {
'\\E' => {
fgoto main;
};
-
- #unicode chars
- utf8_2c when is_utf8 => {
- assert(mode.utf8);
- /* leverage ComponentClass to generate the vertices */
- auto cc = getComponentClass(mode);
- cc->add(readUtf8CodePoint2c(ts));
- cc->finalize();
- currentSeq->addComponent(move(cc));
- };
-
- utf8_3c when is_utf8 => {
- assert(mode.utf8);
- /* leverage ComponentClass to generate the vertices */
- auto cc = getComponentClass(mode);
- cc->add(readUtf8CodePoint3c(ts));
- cc->finalize();
- currentSeq->addComponent(move(cc));
- };
-
- utf8_4c when is_utf8 => {
- assert(mode.utf8);
- /* leverage ComponentClass to generate the vertices */
- auto cc = getComponentClass(mode);
- cc->add(readUtf8CodePoint4c(ts));
- cc->finalize();
- currentSeq->addComponent(move(cc));
- };
-
- hi_byte when is_utf8 => {
- assert(mode.utf8);
- throwInvalidUtf8();
- };
-
+
+ #unicode chars
+ utf8_2c when is_utf8 => {
+ assert(mode.utf8);
+ /* leverage ComponentClass to generate the vertices */
+ auto cc = getComponentClass(mode);
+ cc->add(readUtf8CodePoint2c(ts));
+ cc->finalize();
+ currentSeq->addComponent(move(cc));
+ };
+
+ utf8_3c when is_utf8 => {
+ assert(mode.utf8);
+ /* leverage ComponentClass to generate the vertices */
+ auto cc = getComponentClass(mode);
+ cc->add(readUtf8CodePoint3c(ts));
+ cc->finalize();
+ currentSeq->addComponent(move(cc));
+ };
+
+ utf8_4c when is_utf8 => {
+ assert(mode.utf8);
+ /* leverage ComponentClass to generate the vertices */
+ auto cc = getComponentClass(mode);
+ cc->add(readUtf8CodePoint4c(ts));
+ cc->finalize();
+ currentSeq->addComponent(move(cc));
+ };
+
+ hi_byte when is_utf8 => {
+ assert(mode.utf8);
+ throwInvalidUtf8();
+ };
+
# Literal character
any => {
addLiteral(currentSeq, *ts, mode);
@@ -1203,31 +1203,31 @@ unichar readUtf8CodePoint4c(const char *s) {
'\\E' => {
fret;
};
-
- #unicode chars
- utf8_2c when is_utf8 => {
- assert(mode.utf8);
- currentCls->add(readUtf8CodePoint2c(ts));
- inCharClassEarly = false;
- };
-
- utf8_3c when is_utf8 => {
- assert(mode.utf8);
- currentCls->add(readUtf8CodePoint3c(ts));
- inCharClassEarly = false;
- };
-
- utf8_4c when is_utf8 => {
- assert(mode.utf8);
- currentCls->add(readUtf8CodePoint4c(ts));
- inCharClassEarly = false;
- };
-
- hi_byte when is_utf8 => {
- assert(mode.utf8);
- throwInvalidUtf8();
- };
-
+
+ #unicode chars
+ utf8_2c when is_utf8 => {
+ assert(mode.utf8);
+ currentCls->add(readUtf8CodePoint2c(ts));
+ inCharClassEarly = false;
+ };
+
+ utf8_3c when is_utf8 => {
+ assert(mode.utf8);
+ currentCls->add(readUtf8CodePoint3c(ts));
+ inCharClassEarly = false;
+ };
+
+ utf8_4c when is_utf8 => {
+ assert(mode.utf8);
+ currentCls->add(readUtf8CodePoint4c(ts));
+ inCharClassEarly = false;
+ };
+
+ hi_byte when is_utf8 => {
+ assert(mode.utf8);
+ throwInvalidUtf8();
+ };
+
# Literal character
any => {
currentCls->add(*ts);
@@ -1294,8 +1294,8 @@ unichar readUtf8CodePoint4c(const char *s) {
'\\Q' => {
fgoto readQuotedLiteral;
};
- # An \E that is not preceded by a \Q is ignored
- '\\E' => { /* noop */ };
+ # An \E that is not preceded by a \Q is ignored
+ '\\E' => { /* noop */ };
# Match any character
'\.' => {
currentSeq->addComponent(generateComponent(CLASS_ANY, false, mode));
@@ -1514,12 +1514,12 @@ unichar readUtf8CodePoint4c(const char *s) {
// Otherwise, we interpret the first three digits as an
// octal escape, and the remaining characters stand for
// themselves as literals.
- const char *s = ts;
+ const char *s = ts;
unsigned int accum = 0;
unsigned int oct_digits = 0;
- assert(*s == '\\'); // token starts at backslash
- for (++s; s < te && oct_digits < 3; ++oct_digits, ++s) {
- u8 digit = *s - '0';
+ assert(*s == '\\'); // token starts at backslash
+ for (++s; s < te && oct_digits < 3; ++oct_digits, ++s) {
+ u8 digit = *s - '0';
if (digit < 8) {
accum = digit + accum * 8;
} else {
@@ -1532,8 +1532,8 @@ unichar readUtf8CodePoint4c(const char *s) {
}
// And then the rest of the digits, if any, are literal.
- for (; s < te; ++s) {
- addLiteral(currentSeq, *s, mode);
+ for (; s < te; ++s) {
+ addLiteral(currentSeq, *s, mode);
}
}
};
@@ -1559,13 +1559,13 @@ unichar readUtf8CodePoint4c(const char *s) {
throw LocatedParseError("Invalid reference after \\g");
};
'\\o{' [0-7]+ '}' => {
- string oct(ts + 3, te - ts - 4);
- unsigned long val;
- try {
- val = stoul(oct, nullptr, 8);
- } catch (const std::out_of_range &) {
- val = MAX_UNICODE + 1;
- }
+ string oct(ts + 3, te - ts - 4);
+ unsigned long val;
+ try {
+ val = stoul(oct, nullptr, 8);
+ } catch (const std::out_of_range &) {
+ val = MAX_UNICODE + 1;
+ }
if ((!mode.utf8 && val > 255) || val > MAX_UNICODE) {
throw LocatedParseError("Value in \\o{...} sequence is too large");
}
@@ -1581,13 +1581,13 @@ unichar readUtf8CodePoint4c(const char *s) {
};
# Unicode Hex
'\\x{' xdigit+ '}' => {
- string hex(ts + 3, te - ts - 4);
- unsigned long val;
- try {
- val = stoul(hex, nullptr, 16);
- } catch (const std::out_of_range &) {
- val = MAX_UNICODE + 1;
- }
+ string hex(ts + 3, te - ts - 4);
+ unsigned long val;
+ try {
+ val = stoul(hex, nullptr, 16);
+ } catch (const std::out_of_range &) {
+ val = MAX_UNICODE + 1;
+ }
if (val > MAX_UNICODE) {
throw LocatedParseError("Value in \\x{...} sequence is too large");
}
@@ -1610,8 +1610,8 @@ unichar readUtf8CodePoint4c(const char *s) {
# A bunch of unsupported (for now) escapes
escapedUnsupported => {
ostringstream str;
- str << "'\\" << *(ts + 1) << "' at index " << ts - ptr
- << " not supported.";
+ str << "'\\" << *(ts + 1) << "' at index " << ts - ptr
+ << " not supported.";
throw ParseError(str.str());
};
@@ -1912,22 +1912,22 @@ unichar readUtf8CodePoint4c(const char *s) {
%% write data nofinal;
/** \brief Main parser call, returns root Component or nullptr. */
-unique_ptr<Component> parse(const char *ptr, ParseMode &globalMode) {
- assert(ptr);
-
- const char *p = ptr;
- const char *pe = ptr + strlen(ptr);
-
- // First, read the control verbs, set any global mode flags and move the
- // ptr forward.
- p = read_control_verbs(p, pe, 0, globalMode);
-
- const char *eof = pe;
+unique_ptr<Component> parse(const char *ptr, ParseMode &globalMode) {
+ assert(ptr);
+
+ const char *p = ptr;
+ const char *pe = ptr + strlen(ptr);
+
+ // First, read the control verbs, set any global mode flags and move the
+ // ptr forward.
+ p = read_control_verbs(p, pe, 0, globalMode);
+
+ const char *eof = pe;
int cs;
UNUSED int act;
int top;
vector<int> stack;
- const char *ts, *te;
+ const char *ts, *te;
unichar accumulator = 0;
unichar octAccumulator = 0; /* required as we are also accumulating for
* back ref when looking for octals */
@@ -1950,7 +1950,7 @@ unique_ptr<Component> parse(const char *ptr, ParseMode &globalMode) {
unsigned groupIndex = 1;
// Set storing group names that are currently in use.
- flat_set<string> groupNames;
+ flat_set<string> groupNames;
// Root sequence.
unique_ptr<ComponentSequence> rootSeq = ue2::make_unique<ComponentSequence>();
@@ -1973,7 +1973,7 @@ unique_ptr<Component> parse(const char *ptr, ParseMode &globalMode) {
bool inCharClassEarly = false;
// Location at which the current character class began.
- const char *currentClsBegin = p;
+ const char *currentClsBegin = p;
// We throw exceptions on various parsing failures beyond this point: we
// use a try/catch block here to clean up our allocated memory before we
diff --git a/contrib/libs/hyperscan/src/parser/buildstate.cpp b/contrib/libs/hyperscan/src/parser/buildstate.cpp
index a5b0d2f2eb8..75cfbb7b2d3 100644
--- a/contrib/libs/hyperscan/src/parser/buildstate.cpp
+++ b/contrib/libs/hyperscan/src/parser/buildstate.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,10 +39,10 @@
#include "nfagraph/ng_builder.h"
#include "util/charreach.h"
#include "util/container.h"
-#include "util/flat_containers.h"
-#include "util/hash.h"
+#include "util/flat_containers.h"
+#include "util/hash.h"
#include "util/make_unique.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <algorithm>
#include <iterator>
@@ -451,7 +451,7 @@ unique_ptr<GlushkovBuildState> makeGlushkovBuildState(NFABuilder &b,
* Scans through a list of positions and retains only the highest priority
* version of a given (position, flags) entry. */
void cleanupPositions(vector<PositionInfo> &a) {
- ue2_unordered_set<pair<Position, int>> seen;
+ ue2_unordered_set<pair<Position, int>> seen;
vector<PositionInfo> out;
out.reserve(a.size()); // output should be close to input in size.
diff --git a/contrib/libs/hyperscan/src/parser/buildstate.h b/contrib/libs/hyperscan/src/parser/buildstate.h
index 71109262d1b..5ddaf9b2386 100644
--- a/contrib/libs/hyperscan/src/parser/buildstate.h
+++ b/contrib/libs/hyperscan/src/parser/buildstate.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
#include "ue2common.h"
#include "position.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include <memory>
#include <vector>
@@ -49,7 +49,7 @@ class PositionInfo;
*
* Abstract base class; use \ref makeGlushkovBuildState to get one of these you
* can use. */
-class GlushkovBuildState : noncopyable {
+class GlushkovBuildState : noncopyable {
public:
/** \brief Represents an uninitialized state. */
static const Position POS_UNINITIALIZED;
diff --git a/contrib/libs/hyperscan/src/parser/check_refs.cpp b/contrib/libs/hyperscan/src/parser/check_refs.cpp
index fb32ec29748..60b5b6ba77e 100644
--- a/contrib/libs/hyperscan/src/parser/check_refs.cpp
+++ b/contrib/libs/hyperscan/src/parser/check_refs.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,7 +36,7 @@
#include "ConstComponentVisitor.h"
#include "parse_error.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include <sstream>
@@ -73,8 +73,8 @@ public:
throw ParseError(str.str());
}
- using DefaultConstComponentVisitor::pre;
-
+ using DefaultConstComponentVisitor::pre;
+
void pre(const ComponentBackReference &c) override {
if (c.ref_id) {
if (c.ref_id >= num_ids) {
@@ -114,7 +114,7 @@ public:
ReferenceVisitor::~ReferenceVisitor() {}
void checkReferences(const Component &root, unsigned int groupIndices,
- const flat_set<std::string> &groupNames) {
+ const flat_set<std::string> &groupNames) {
ReferenceVisitor vis(groupIndices, groupNames);
root.accept(vis);
}
diff --git a/contrib/libs/hyperscan/src/parser/check_refs.h b/contrib/libs/hyperscan/src/parser/check_refs.h
index 5e1678702a5..26912fb8e44 100644
--- a/contrib/libs/hyperscan/src/parser/check_refs.h
+++ b/contrib/libs/hyperscan/src/parser/check_refs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,17 +26,17 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Component tree analysis that checks that references (such as
* back-refs, conditionals) have valid referents.
*/
-#ifndef PARSER_CHECK_REFS_H
-#define PARSER_CHECK_REFS_H
+#ifndef PARSER_CHECK_REFS_H
+#define PARSER_CHECK_REFS_H
+
+#include "util/flat_containers.h"
-#include "util/flat_containers.h"
-
#include <string>
namespace ue2 {
@@ -45,8 +45,8 @@ class Component;
class ComponentSequence;
void checkReferences(const Component &root, unsigned int groupIndices,
- const flat_set<std::string> &groupNames);
+ const flat_set<std::string> &groupNames);
} // namespace ue2
-#endif // PARSER_CHECK_REFS_H
+#endif // PARSER_CHECK_REFS_H
diff --git a/contrib/libs/hyperscan/src/parser/control_verbs.h b/contrib/libs/hyperscan/src/parser/control_verbs.h
index 60935023869..58934ec2ced 100644
--- a/contrib/libs/hyperscan/src/parser/control_verbs.h
+++ b/contrib/libs/hyperscan/src/parser/control_verbs.h
@@ -1,48 +1,48 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Parser for control verbs that can occur at the beginning of a pattern.
- */
-
-#ifndef CONTROL_VERBS_H
-#define CONTROL_VERBS_H
-
-#include "ue2common.h"
-
-namespace ue2 {
-
-struct ParseMode;
-
-const char *read_control_verbs(const char *ptr, const char *end, size_t start,
- ParseMode &mode);
-
-} // namespace ue2
-
-#endif // CONTROL_VERBS_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Parser for control verbs that can occur at the beginning of a pattern.
+ */
+
+#ifndef CONTROL_VERBS_H
+#define CONTROL_VERBS_H
+
+#include "ue2common.h"
+
+namespace ue2 {
+
+struct ParseMode;
+
+const char *read_control_verbs(const char *ptr, const char *end, size_t start,
+ ParseMode &mode);
+
+} // namespace ue2
+
+#endif // CONTROL_VERBS_H
diff --git a/contrib/libs/hyperscan/src/parser/control_verbs.rl6 b/contrib/libs/hyperscan/src/parser/control_verbs.rl6
index 46a0bfd000e..1d3e33a9aac 100644
--- a/contrib/libs/hyperscan/src/parser/control_verbs.rl6
+++ b/contrib/libs/hyperscan/src/parser/control_verbs.rl6
@@ -1,121 +1,121 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Parser for control verbs that can occur at the beginning of a pattern.
- */
-
-#include "parser/control_verbs.h"
-
-#include "parser/Parser.h"
-#include "parser/parse_error.h"
-
-#include <cstring>
-#include <sstream>
-
-using namespace std;
-
-namespace ue2 {
-
-const char *read_control_verbs(const char *ptr, const char *end, size_t start,
- ParseMode &mode) {
- const char *p = ptr;
- const char *pe = end;
- const char *eof = pe;
- const char *ts, *te;
- int cs;
- UNUSED int act;
-
- %%{
- machine ControlVerbs;
-
- # Verbs that we recognise but do not support.
- unhandledVerbs = '(*' (
- 'LIMIT_MATCH=' [0-9]+ |
- 'LIMIT_RECURSION=' [0-9]+ |
- 'NO_AUTO_POSSESS' |
- 'NO_START_OPT' |
- 'UTF16' |
- 'UTF32' |
- 'CR' |
- 'LF' |
- 'CRLF' |
- 'ANYCRLF' |
- 'ANY' |
- 'BSR_ANYCRLF' |
- 'BSR_UNICODE'
- ) . ')';
-
- main := |*
- '(*UTF8)' | '(*UTF)' => {
- mode.utf8 = true;
- };
-
- '(*UCP)' => {
- mode.ucp = true;
- };
-
- unhandledVerbs => {
- ostringstream str;
- str << "Unsupported control verb " << string(ts, te - ts);
- throw LocatedParseError(str.str());
- };
-
- '(*' [^)]+ ')' => {
- ostringstream str;
- str << "Unknown control verb " << string(ts, te - ts);
- throw LocatedParseError(str.str());
- };
-
- # Anything else means we're done.
- any => {
- fhold;
- fbreak;
- };
- *|;
-
- write data;
- write init;
- }%%
-
- try {
- %% write exec;
- } catch (LocatedParseError &error) {
- if (ts >= ptr && ts <= pe) {
- error.locate(ts - ptr + start);
- } else {
- error.locate(0);
- }
- throw;
- }
-
- return p;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Parser for control verbs that can occur at the beginning of a pattern.
+ */
+
+#include "parser/control_verbs.h"
+
+#include "parser/Parser.h"
+#include "parser/parse_error.h"
+
+#include <cstring>
+#include <sstream>
+
+using namespace std;
+
+namespace ue2 {
+
+const char *read_control_verbs(const char *ptr, const char *end, size_t start,
+ ParseMode &mode) {
+ const char *p = ptr;
+ const char *pe = end;
+ const char *eof = pe;
+ const char *ts, *te;
+ int cs;
+ UNUSED int act;
+
+ %%{
+ machine ControlVerbs;
+
+ # Verbs that we recognise but do not support.
+ unhandledVerbs = '(*' (
+ 'LIMIT_MATCH=' [0-9]+ |
+ 'LIMIT_RECURSION=' [0-9]+ |
+ 'NO_AUTO_POSSESS' |
+ 'NO_START_OPT' |
+ 'UTF16' |
+ 'UTF32' |
+ 'CR' |
+ 'LF' |
+ 'CRLF' |
+ 'ANYCRLF' |
+ 'ANY' |
+ 'BSR_ANYCRLF' |
+ 'BSR_UNICODE'
+ ) . ')';
+
+ main := |*
+ '(*UTF8)' | '(*UTF)' => {
+ mode.utf8 = true;
+ };
+
+ '(*UCP)' => {
+ mode.ucp = true;
+ };
+
+ unhandledVerbs => {
+ ostringstream str;
+ str << "Unsupported control verb " << string(ts, te - ts);
+ throw LocatedParseError(str.str());
+ };
+
+ '(*' [^)]+ ')' => {
+ ostringstream str;
+ str << "Unknown control verb " << string(ts, te - ts);
+ throw LocatedParseError(str.str());
+ };
+
+ # Anything else means we're done.
+ any => {
+ fhold;
+ fbreak;
+ };
+ *|;
+
+ write data;
+ write init;
+ }%%
+
+ try {
+ %% write exec;
+ } catch (LocatedParseError &error) {
+ if (ts >= ptr && ts <= pe) {
+ error.locate(ts - ptr + start);
+ } else {
+ error.locate(0);
+ }
+ throw;
+ }
+
+ return p;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/parser/parse_error.cpp b/contrib/libs/hyperscan/src/parser/parse_error.cpp
index 7852c400155..e7f60b2645c 100644
--- a/contrib/libs/hyperscan/src/parser/parse_error.cpp
+++ b/contrib/libs/hyperscan/src/parser/parse_error.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -44,13 +44,13 @@ ParseError::~ParseError() {}
LocatedParseError::~LocatedParseError() {}
void LocatedParseError::locate(size_t offset) {
- if (finalized) {
- return;
- }
+ if (finalized) {
+ return;
+ }
std::ostringstream str;
str << reason << " at index " << offset << ".";
reason = str.str();
- finalized = true;
+ finalized = true;
}
}
diff --git a/contrib/libs/hyperscan/src/parser/parse_error.h b/contrib/libs/hyperscan/src/parser/parse_error.h
index af6ba78c0a0..4556ed5e048 100644
--- a/contrib/libs/hyperscan/src/parser/parse_error.h
+++ b/contrib/libs/hyperscan/src/parser/parse_error.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,8 +30,8 @@
* \brief Parse/Compile exceptions.
*/
-#ifndef PARSE_ERROR_H
-#define PARSE_ERROR_H
+#ifndef PARSE_ERROR_H
+#define PARSE_ERROR_H
#include "util/compile_error.h"
@@ -44,24 +44,24 @@ class ParseError : public CompileError {
public:
// Note: 'why' should describe why the error occurred and end with a
// full stop, but no line break.
- explicit ParseError(std::string why) : CompileError(std::move(why)) {}
+ explicit ParseError(std::string why) : CompileError(std::move(why)) {}
~ParseError() override;
};
class LocatedParseError : public ParseError {
public:
- explicit LocatedParseError(std::string why) : ParseError(".") {
- reason = std::move(why); // don't use ParseError ctor
+ explicit LocatedParseError(std::string why) : ParseError(".") {
+ reason = std::move(why); // don't use ParseError ctor
}
~LocatedParseError() override;
void locate(size_t offset);
-private:
- bool finalized = false; //!< true when locate() has been called.
+private:
+ bool finalized = false; //!< true when locate() has been called.
};
} // namespace ue2
-#endif /* PARSE_ERROR_H */
+#endif /* PARSE_ERROR_H */
diff --git a/contrib/libs/hyperscan/src/parser/prefilter.cpp b/contrib/libs/hyperscan/src/parser/prefilter.cpp
index 96292aed73d..f69362e4e33 100644
--- a/contrib/libs/hyperscan/src/parser/prefilter.cpp
+++ b/contrib/libs/hyperscan/src/parser/prefilter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -80,9 +80,9 @@ public:
return numPositions <= MAX_REFERENT_POSITIONS;
}
- using DefaultConstComponentVisitor::pre;
- using DefaultConstComponentVisitor::post;
-
+ using DefaultConstComponentVisitor::pre;
+ using DefaultConstComponentVisitor::post;
+
void pre(const AsciiComponentClass &) override {
numPositions++;
}
@@ -167,8 +167,8 @@ public:
explicit FindSequenceVisitor(unsigned ref_id) : id(ref_id) {}
explicit FindSequenceVisitor(const std::string &s) : name(s) {}
- using DefaultConstComponentVisitor::pre;
-
+ using DefaultConstComponentVisitor::pre;
+
void pre(const ComponentSequence &c) override {
if (!name.empty()) {
if (c.getCaptureName() == name) {
@@ -208,8 +208,8 @@ public:
PrefilterVisitor(Component *c, const ParseMode &m) : root(c), mode(m) {}
~PrefilterVisitor() override;
- using DefaultComponentVisitor::visit;
-
+ using DefaultComponentVisitor::visit;
+
/** \brief Calls the visitor (recursively) on a new replacement component
* we've just created. Takes care of freeing it if the sequence is itself
* replaced. */
@@ -295,16 +295,16 @@ public:
Component *visit(ComponentWordBoundary *c) override {
assert(c);
-
- // TODO: Right now, we do not have correct code for resolving these
- // when prefiltering is on, UCP is on, and UTF-8 is *off*. For now, we
- // just replace with an empty sequence (as that will return a superset
- // of matches).
- if (mode.ucp && !mode.utf8) {
- return new ComponentSequence();
- }
-
- // All other cases can be prefiltered.
+
+ // TODO: Right now, we do not have correct code for resolving these
+ // when prefiltering is on, UCP is on, and UTF-8 is *off*. For now, we
+ // just replace with an empty sequence (as that will return a superset
+ // of matches).
+ if (mode.ucp && !mode.utf8) {
+ return new ComponentSequence();
+ }
+
+ // All other cases can be prefiltered.
c->setPrefilter(true);
return c;
}
diff --git a/contrib/libs/hyperscan/src/parser/shortcut_literal.cpp b/contrib/libs/hyperscan/src/parser/shortcut_literal.cpp
index 3f7150c2f19..a5d67f30d84 100644
--- a/contrib/libs/hyperscan/src/parser/shortcut_literal.cpp
+++ b/contrib/libs/hyperscan/src/parser/shortcut_literal.cpp
@@ -159,26 +159,26 @@ public:
ConstructLiteralVisitor::~ConstructLiteralVisitor() {}
/** \brief True if the literal expression \a expr could be added to Rose. */
-bool shortcutLiteral(NG &ng, const ParsedExpression &pe) {
- assert(pe.component);
+bool shortcutLiteral(NG &ng, const ParsedExpression &pe) {
+ assert(pe.component);
- if (!ng.cc.grey.allowLiteral) {
+ if (!ng.cc.grey.allowLiteral) {
return false;
}
- const auto &expr = pe.expr;
-
+ const auto &expr = pe.expr;
+
// XXX: don't shortcut literals with extended params (yet)
- if (expr.min_offset || expr.max_offset != MAX_OFFSET || expr.min_length ||
- expr.edit_distance || expr.hamm_distance) {
+ if (expr.min_offset || expr.max_offset != MAX_OFFSET || expr.min_length ||
+ expr.edit_distance || expr.hamm_distance) {
DEBUG_PRINTF("extended params not allowed\n");
return false;
}
ConstructLiteralVisitor vis;
try {
- assert(pe.component);
- pe.component->accept(vis);
+ assert(pe.component);
+ pe.component->accept(vis);
assert(vis.repeat_stack.empty());
} catch (const ConstructLiteralVisitor::NotLiteral&) {
DEBUG_PRINTF("not a literal\n");
@@ -198,7 +198,7 @@ bool shortcutLiteral(NG &ng, const ParsedExpression &pe) {
}
DEBUG_PRINTF("constructed literal %s\n", dumpString(lit).c_str());
- return ng.addLiteral(lit, expr.index, expr.report, expr.highlander,
+ return ng.addLiteral(lit, expr.index, expr.report, expr.highlander,
expr.som, expr.quiet);
}
diff --git a/contrib/libs/hyperscan/src/parser/ucp_table.cpp b/contrib/libs/hyperscan/src/parser/ucp_table.cpp
index dc7474a3745..fc1330fe7f2 100644
--- a/contrib/libs/hyperscan/src/parser/ucp_table.cpp
+++ b/contrib/libs/hyperscan/src/parser/ucp_table.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -83,13 +83,13 @@ void make_caseless(CodePointSet *cps) {
CodePointSet base = *cps;
- auto uc_begin = begin(ucp_caseless_def);
- auto uc_end = end(ucp_caseless_def);
- DEBUG_PRINTF("uc len %zd\n", distance(uc_begin, uc_end));
+ auto uc_begin = begin(ucp_caseless_def);
+ auto uc_end = end(ucp_caseless_def);
+ DEBUG_PRINTF("uc len %zd\n", distance(uc_begin, uc_end));
- for (const auto &elem : base) {
- unichar b = lower(elem);
- unichar e = upper(elem) + 1;
+ for (const auto &elem : base) {
+ unichar b = lower(elem);
+ unichar e = upper(elem) + 1;
for (; b < e; b++) {
DEBUG_PRINTF("decasing %x\n", b);
@@ -100,7 +100,7 @@ void make_caseless(CodePointSet *cps) {
DEBUG_PRINTF("EOL\n");
return;
}
- while (uc_begin != uc_end && uc_begin->base == b) {
+ while (uc_begin != uc_end && uc_begin->base == b) {
DEBUG_PRINTF("at {%x,%x}\n", uc_begin->base, uc_begin->caseless);
cps->set(uc_begin->caseless);
++uc_begin;
@@ -116,12 +116,12 @@ void make_caseless(CodePointSet *cps) {
bool flip_case(unichar *c) {
assert(c);
- const unicase test = { *c, 0 };
+ const unicase test = { *c, 0 };
- const auto uc_begin = begin(ucp_caseless_def);
- const auto uc_end = end(ucp_caseless_def);
- const auto f = lower_bound(uc_begin, uc_end, test);
- if (f != uc_end && f->base == *c) {
+ const auto uc_begin = begin(ucp_caseless_def);
+ const auto uc_end = end(ucp_caseless_def);
+ const auto f = lower_bound(uc_begin, uc_end, test);
+ if (f != uc_end && f->base == *c) {
DEBUG_PRINTF("flipped c=%x to %x\n", *c, f->caseless);
*c = f->caseless;
return true;
diff --git a/contrib/libs/hyperscan/src/parser/unsupported.cpp b/contrib/libs/hyperscan/src/parser/unsupported.cpp
index 7e515c90283..c4b18b6a300 100644
--- a/contrib/libs/hyperscan/src/parser/unsupported.cpp
+++ b/contrib/libs/hyperscan/src/parser/unsupported.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,7 +45,7 @@ namespace ue2 {
class UnsupportedVisitor : public DefaultConstComponentVisitor {
public:
~UnsupportedVisitor() override;
- using DefaultConstComponentVisitor::pre;
+ using DefaultConstComponentVisitor::pre;
void pre(const ComponentAssertion &) override {
throw ParseError("Zero-width assertions are not supported.");
}
diff --git a/contrib/libs/hyperscan/src/report.h b/contrib/libs/hyperscan/src/report.h
index 653f908126d..b35f4c052d2 100644
--- a/contrib/libs/hyperscan/src/report.h
+++ b/contrib/libs/hyperscan/src/report.h
@@ -1,157 +1,157 @@
-/*
+/*
* Copyright (c) 2016-2019, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Runtime functions to do with reports, inlined into callers.
- */
-
-#ifndef REPORT_H
-#define REPORT_H
-
-#include "hs_internal.h"
-#include "hs_runtime.h"
-#include "scratch.h"
-#include "ue2common.h"
-#include "nfa/callback.h"
-#include "nfa/nfa_internal.h"
-#include "rose/runtime.h"
-#include "som/som_runtime.h"
-#include "util/exhaust.h"
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Runtime functions to do with reports, inlined into callers.
+ */
+
+#ifndef REPORT_H
+#define REPORT_H
+
+#include "hs_internal.h"
+#include "hs_runtime.h"
+#include "scratch.h"
+#include "ue2common.h"
+#include "nfa/callback.h"
+#include "nfa/nfa_internal.h"
+#include "rose/runtime.h"
+#include "som/som_runtime.h"
+#include "util/exhaust.h"
#include "util/logical.h"
-#include "util/fatbit.h"
-
-enum DedupeResult {
- DEDUPE_CONTINUE, //!< Continue with match, not a dupe.
- DEDUPE_SKIP, //!< Don't report this match, dupe or delayed due to SOM.
- DEDUPE_HALT //!< User instructed us to stop matching.
-};
-
-static really_inline
-enum DedupeResult dedupeCatchup(const struct RoseEngine *rose,
- struct hs_scratch *scratch, u64a offset,
- u64a from_offset, u64a to_offset, u32 dkey,
- s32 offset_adjust, char is_external_report,
- char quash_som, const char do_som) {
- DEBUG_PRINTF("offset=%llu, match=[%llu,%llu], dkey=%u, do_som=%d\n", offset,
- from_offset, to_offset, dkey, do_som);
-
- // We should not have been called if there's no dedupe work to do.
- assert(do_som || dkey != MO_INVALID_IDX);
-
- struct match_deduper *deduper = &scratch->deduper;
- if (offset != deduper->current_report_offset) {
- assert(deduper->current_report_offset == ~0ULL ||
- deduper->current_report_offset < offset);
- if (offset == deduper->current_report_offset + 1) {
- fatbit_clear(deduper->log[offset % 2]);
- } else {
- fatbit_clear(deduper->log[0]);
- fatbit_clear(deduper->log[1]);
- }
-
- if (do_som && flushStoredSomMatches(scratch, offset)) {
- return DEDUPE_HALT;
- }
- deduper->current_report_offset = offset;
- }
-
- if (dkey != MO_INVALID_IDX) {
- const u32 dkeyCount = rose->dkeyCount;
- if (is_external_report || quash_som) {
- DEBUG_PRINTF("checking dkey %u at offset %llu\n", dkey, to_offset);
- assert(offset_adjust == 0 || offset_adjust == -1);
- if (fatbit_set(deduper->log[to_offset % 2], dkeyCount, dkey)) {
- /* we have already raised this report at this offset, squash
- * dupe match. */
- DEBUG_PRINTF("dedupe\n");
- return DEDUPE_SKIP;
- }
- } else if (do_som) {
- /* SOM external event */
- DEBUG_PRINTF("checking dkey %u at offset %llu\n", dkey, to_offset);
- assert(offset_adjust == 0 || offset_adjust == -1);
- u64a *starts = deduper->som_start_log[to_offset % 2];
- if (fatbit_set(deduper->som_log[to_offset % 2], dkeyCount, dkey)) {
- starts[dkey] = MIN(starts[dkey], from_offset);
- } else {
- starts[dkey] = from_offset;
- }
- DEBUG_PRINTF("starts[%u]=%llu\n", dkey, starts[dkey]);
-
- if (offset_adjust) {
- deduper->som_log_dirty |= 1;
- } else {
- deduper->som_log_dirty |= 2;
- }
-
- return DEDUPE_SKIP;
- }
- }
-
- return DEDUPE_CONTINUE;
-}
-
-/** \brief Test whether the given key (\a ekey) is set in the exhaustion vector
- * \a evec. */
-static really_inline
-int isExhausted(const struct RoseEngine *rose, const char *evec, u32 ekey) {
- DEBUG_PRINTF("checking exhaustion %p %u\n", evec, ekey);
- assert(ekey != INVALID_EKEY);
- assert(ekey < rose->ekeyCount);
- return mmbit_isset((const u8 *)evec, rose->ekeyCount, ekey);
-}
-
-/** \brief Returns 1 if all exhaustion keys in the bitvector are on. */
-static really_inline
-int isAllExhausted(const struct RoseEngine *rose, const char *evec) {
- if (!rose->canExhaust) {
- return 0; /* pattern set is inexhaustible */
- }
-
- return mmbit_all((const u8 *)evec, rose->ekeyCount);
-}
-
-/** \brief Mark key \a ekey on in the exhaustion vector. */
-static really_inline
-void markAsMatched(const struct RoseEngine *rose, char *evec, u32 ekey) {
- DEBUG_PRINTF("marking as exhausted key %u\n", ekey);
- assert(ekey != INVALID_EKEY);
- assert(ekey < rose->ekeyCount);
- mmbit_set((u8 *)evec, rose->ekeyCount, ekey);
-}
-
-/** \brief Clear all keys in the exhaustion vector. */
-static really_inline
-void clearEvec(const struct RoseEngine *rose, char *evec) {
- DEBUG_PRINTF("clearing evec %p %u\n", evec, rose->ekeyCount);
- mmbit_clear((u8 *)evec, rose->ekeyCount);
-}
-
+#include "util/fatbit.h"
+
+enum DedupeResult {
+ DEDUPE_CONTINUE, //!< Continue with match, not a dupe.
+ DEDUPE_SKIP, //!< Don't report this match, dupe or delayed due to SOM.
+ DEDUPE_HALT //!< User instructed us to stop matching.
+};
+
+static really_inline
+enum DedupeResult dedupeCatchup(const struct RoseEngine *rose,
+ struct hs_scratch *scratch, u64a offset,
+ u64a from_offset, u64a to_offset, u32 dkey,
+ s32 offset_adjust, char is_external_report,
+ char quash_som, const char do_som) {
+ DEBUG_PRINTF("offset=%llu, match=[%llu,%llu], dkey=%u, do_som=%d\n", offset,
+ from_offset, to_offset, dkey, do_som);
+
+ // We should not have been called if there's no dedupe work to do.
+ assert(do_som || dkey != MO_INVALID_IDX);
+
+ struct match_deduper *deduper = &scratch->deduper;
+ if (offset != deduper->current_report_offset) {
+ assert(deduper->current_report_offset == ~0ULL ||
+ deduper->current_report_offset < offset);
+ if (offset == deduper->current_report_offset + 1) {
+ fatbit_clear(deduper->log[offset % 2]);
+ } else {
+ fatbit_clear(deduper->log[0]);
+ fatbit_clear(deduper->log[1]);
+ }
+
+ if (do_som && flushStoredSomMatches(scratch, offset)) {
+ return DEDUPE_HALT;
+ }
+ deduper->current_report_offset = offset;
+ }
+
+ if (dkey != MO_INVALID_IDX) {
+ const u32 dkeyCount = rose->dkeyCount;
+ if (is_external_report || quash_som) {
+ DEBUG_PRINTF("checking dkey %u at offset %llu\n", dkey, to_offset);
+ assert(offset_adjust == 0 || offset_adjust == -1);
+ if (fatbit_set(deduper->log[to_offset % 2], dkeyCount, dkey)) {
+ /* we have already raised this report at this offset, squash
+ * dupe match. */
+ DEBUG_PRINTF("dedupe\n");
+ return DEDUPE_SKIP;
+ }
+ } else if (do_som) {
+ /* SOM external event */
+ DEBUG_PRINTF("checking dkey %u at offset %llu\n", dkey, to_offset);
+ assert(offset_adjust == 0 || offset_adjust == -1);
+ u64a *starts = deduper->som_start_log[to_offset % 2];
+ if (fatbit_set(deduper->som_log[to_offset % 2], dkeyCount, dkey)) {
+ starts[dkey] = MIN(starts[dkey], from_offset);
+ } else {
+ starts[dkey] = from_offset;
+ }
+ DEBUG_PRINTF("starts[%u]=%llu\n", dkey, starts[dkey]);
+
+ if (offset_adjust) {
+ deduper->som_log_dirty |= 1;
+ } else {
+ deduper->som_log_dirty |= 2;
+ }
+
+ return DEDUPE_SKIP;
+ }
+ }
+
+ return DEDUPE_CONTINUE;
+}
+
+/** \brief Test whether the given key (\a ekey) is set in the exhaustion vector
+ * \a evec. */
+static really_inline
+int isExhausted(const struct RoseEngine *rose, const char *evec, u32 ekey) {
+ DEBUG_PRINTF("checking exhaustion %p %u\n", evec, ekey);
+ assert(ekey != INVALID_EKEY);
+ assert(ekey < rose->ekeyCount);
+ return mmbit_isset((const u8 *)evec, rose->ekeyCount, ekey);
+}
+
+/** \brief Returns 1 if all exhaustion keys in the bitvector are on. */
+static really_inline
+int isAllExhausted(const struct RoseEngine *rose, const char *evec) {
+ if (!rose->canExhaust) {
+ return 0; /* pattern set is inexhaustible */
+ }
+
+ return mmbit_all((const u8 *)evec, rose->ekeyCount);
+}
+
+/** \brief Mark key \a ekey on in the exhaustion vector. */
+static really_inline
+void markAsMatched(const struct RoseEngine *rose, char *evec, u32 ekey) {
+ DEBUG_PRINTF("marking as exhausted key %u\n", ekey);
+ assert(ekey != INVALID_EKEY);
+ assert(ekey < rose->ekeyCount);
+ mmbit_set((u8 *)evec, rose->ekeyCount, ekey);
+}
+
+/** \brief Clear all keys in the exhaustion vector. */
+static really_inline
+void clearEvec(const struct RoseEngine *rose, char *evec) {
+ DEBUG_PRINTF("clearing evec %p %u\n", evec, rose->ekeyCount);
+ mmbit_clear((u8 *)evec, rose->ekeyCount);
+}
+
/** \brief Test whether the given key (\a lkey) is set in the logical vector
* \a lvec. */
static really_inline
@@ -291,102 +291,102 @@ void clearCvec(const struct RoseEngine *rose, char *cvec) {
mmbit_clear((u8 *)cvec, rose->ckeyCount);
}
-/**
- * \brief Deliver the given report to the user callback.
- *
- * Assumes all preconditions (bounds, exhaustion etc) have been checked and
- * that dedupe catchup has been done.
- */
-static really_inline
-int roseDeliverReport(u64a offset, ReportID onmatch, s32 offset_adjust,
- struct hs_scratch *scratch, u32 ekey) {
- assert(scratch);
- assert(scratch->magic == SCRATCH_MAGIC);
-
- struct core_info *ci = &scratch->core_info;
-
- u32 flags = 0;
-#ifndef RELEASE_BUILD
- if (offset_adjust) {
- // alert testing tools that we've got adjusted matches
- flags |= HS_MATCH_FLAG_ADJUSTED;
- }
-#endif
-
- assert(!can_stop_matching(scratch));
- assert(ekey == INVALID_EKEY ||
- !isExhausted(ci->rose, ci->exhaustionVector, ekey));
-
- u64a from_offset = 0;
- u64a to_offset = offset + offset_adjust;
-
- DEBUG_PRINTF(">> reporting match @[%llu,%llu] for sig %u ctxt %p <<\n",
- from_offset, to_offset, onmatch, ci->userContext);
-
- int halt = ci->userCallback(onmatch, from_offset, to_offset, flags,
- ci->userContext);
- if (halt) {
- DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->status |= STATUS_TERMINATED;
- return MO_HALT_MATCHING;
- }
-
- if (ekey != INVALID_EKEY) {
- markAsMatched(ci->rose, ci->exhaustionVector, ekey);
- return MO_CONTINUE_MATCHING;
- } else {
- return ROSE_CONTINUE_MATCHING_NO_EXHAUST;
- }
-}
-
-/**
- * \brief Deliver the given SOM report to the user callback.
- *
- * Assumes all preconditions (bounds, exhaustion etc) have been checked and
- * that dedupe catchup has been done.
- */
-static really_inline
-int roseDeliverSomReport(u64a from_offset, u64a to_offset, ReportID onmatch,
- s32 offset_adjust, struct hs_scratch *scratch,
- u32 ekey) {
- assert(scratch);
- assert(scratch->magic == SCRATCH_MAGIC);
-
- struct core_info *ci = &scratch->core_info;
-
- u32 flags = 0;
-#ifndef RELEASE_BUILD
- if (offset_adjust) {
- // alert testing tools that we've got adjusted matches
- flags |= HS_MATCH_FLAG_ADJUSTED;
- }
-#endif
-
- assert(!can_stop_matching(scratch));
- assert(ekey == INVALID_EKEY ||
- !isExhausted(ci->rose, ci->exhaustionVector, ekey));
-
- to_offset += offset_adjust;
- assert(from_offset == HS_OFFSET_PAST_HORIZON || from_offset <= to_offset);
-
- DEBUG_PRINTF(">> reporting match @[%llu,%llu] for sig %u ctxt %p <<\n",
- from_offset, to_offset, onmatch, ci->userContext);
-
- int halt = ci->userCallback(onmatch, from_offset, to_offset, flags,
- ci->userContext);
-
- if (halt) {
- DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->status |= STATUS_TERMINATED;
- return MO_HALT_MATCHING;
- }
-
- if (ekey != INVALID_EKEY) {
- markAsMatched(ci->rose, ci->exhaustionVector, ekey);
- return MO_CONTINUE_MATCHING;
- } else {
- return ROSE_CONTINUE_MATCHING_NO_EXHAUST;
- }
-}
-
-#endif // REPORT_H
+/**
+ * \brief Deliver the given report to the user callback.
+ *
+ * Assumes all preconditions (bounds, exhaustion etc) have been checked and
+ * that dedupe catchup has been done.
+ */
+static really_inline
+int roseDeliverReport(u64a offset, ReportID onmatch, s32 offset_adjust,
+ struct hs_scratch *scratch, u32 ekey) {
+ assert(scratch);
+ assert(scratch->magic == SCRATCH_MAGIC);
+
+ struct core_info *ci = &scratch->core_info;
+
+ u32 flags = 0;
+#ifndef RELEASE_BUILD
+ if (offset_adjust) {
+ // alert testing tools that we've got adjusted matches
+ flags |= HS_MATCH_FLAG_ADJUSTED;
+ }
+#endif
+
+ assert(!can_stop_matching(scratch));
+ assert(ekey == INVALID_EKEY ||
+ !isExhausted(ci->rose, ci->exhaustionVector, ekey));
+
+ u64a from_offset = 0;
+ u64a to_offset = offset + offset_adjust;
+
+ DEBUG_PRINTF(">> reporting match @[%llu,%llu] for sig %u ctxt %p <<\n",
+ from_offset, to_offset, onmatch, ci->userContext);
+
+ int halt = ci->userCallback(onmatch, from_offset, to_offset, flags,
+ ci->userContext);
+ if (halt) {
+ DEBUG_PRINTF("callback requested to terminate matches\n");
+ ci->status |= STATUS_TERMINATED;
+ return MO_HALT_MATCHING;
+ }
+
+ if (ekey != INVALID_EKEY) {
+ markAsMatched(ci->rose, ci->exhaustionVector, ekey);
+ return MO_CONTINUE_MATCHING;
+ } else {
+ return ROSE_CONTINUE_MATCHING_NO_EXHAUST;
+ }
+}
+
+/**
+ * \brief Deliver the given SOM report to the user callback.
+ *
+ * Assumes all preconditions (bounds, exhaustion etc) have been checked and
+ * that dedupe catchup has been done.
+ */
+static really_inline
+int roseDeliverSomReport(u64a from_offset, u64a to_offset, ReportID onmatch,
+ s32 offset_adjust, struct hs_scratch *scratch,
+ u32 ekey) {
+ assert(scratch);
+ assert(scratch->magic == SCRATCH_MAGIC);
+
+ struct core_info *ci = &scratch->core_info;
+
+ u32 flags = 0;
+#ifndef RELEASE_BUILD
+ if (offset_adjust) {
+ // alert testing tools that we've got adjusted matches
+ flags |= HS_MATCH_FLAG_ADJUSTED;
+ }
+#endif
+
+ assert(!can_stop_matching(scratch));
+ assert(ekey == INVALID_EKEY ||
+ !isExhausted(ci->rose, ci->exhaustionVector, ekey));
+
+ to_offset += offset_adjust;
+ assert(from_offset == HS_OFFSET_PAST_HORIZON || from_offset <= to_offset);
+
+ DEBUG_PRINTF(">> reporting match @[%llu,%llu] for sig %u ctxt %p <<\n",
+ from_offset, to_offset, onmatch, ci->userContext);
+
+ int halt = ci->userCallback(onmatch, from_offset, to_offset, flags,
+ ci->userContext);
+
+ if (halt) {
+ DEBUG_PRINTF("callback requested to terminate matches\n");
+ ci->status |= STATUS_TERMINATED;
+ return MO_HALT_MATCHING;
+ }
+
+ if (ekey != INVALID_EKEY) {
+ markAsMatched(ci->rose, ci->exhaustionVector, ekey);
+ return MO_CONTINUE_MATCHING;
+ } else {
+ return ROSE_CONTINUE_MATCHING_NO_EXHAUST;
+ }
+}
+
+#endif // REPORT_H
diff --git a/contrib/libs/hyperscan/src/rose/block.c b/contrib/libs/hyperscan/src/rose/block.c
index 9148ecb8ff5..b3f424cb73c 100644
--- a/contrib/libs/hyperscan/src/rose/block.c
+++ b/contrib/libs/hyperscan/src/rose/block.c
@@ -29,9 +29,9 @@
#include "catchup.h"
#include "init.h"
#include "match.h"
-#include "program_runtime.h"
-#include "rose.h"
-#include "rose_common.h"
+#include "program_runtime.h"
+#include "rose.h"
+#include "rose_common.h"
#include "nfa/nfa_api.h"
#include "nfa/nfa_internal.h"
#include "nfa/nfa_rev_api.h"
@@ -62,11 +62,11 @@ void runAnchoredTableBlock(const struct RoseEngine *t, const void *atable,
if (nfa->type == MCCLELLAN_NFA_8) {
nfaExecMcClellan8_B(nfa, curr->anchoredMinDistance,
local_buffer, local_alen,
- roseAnchoredCallback, scratch);
+ roseAnchoredCallback, scratch);
} else {
nfaExecMcClellan16_B(nfa, curr->anchoredMinDistance,
local_buffer, local_alen,
- roseAnchoredCallback, scratch);
+ roseAnchoredCallback, scratch);
}
}
@@ -79,12 +79,12 @@ void runAnchoredTableBlock(const struct RoseEngine *t, const void *atable,
}
static really_inline
-void init_state_for_block(const struct RoseEngine *t, char *state) {
+void init_state_for_block(const struct RoseEngine *t, char *state) {
assert(t);
assert(state);
- DEBUG_PRINTF("init for Rose %p with %u state indices\n", t,
- t->rolesWithStateCount);
+ DEBUG_PRINTF("init for Rose %p with %u state indices\n", t,
+ t->rolesWithStateCount);
// Rose is guaranteed 8-aligned state
assert(ISALIGNED_N(state, 8));
@@ -94,7 +94,7 @@ void init_state_for_block(const struct RoseEngine *t, char *state) {
static really_inline
void init_outfixes_for_block(const struct RoseEngine *t,
- struct hs_scratch *scratch, char *state,
+ struct hs_scratch *scratch, char *state,
char is_small_block) {
/* active leaf array has been cleared by the init scatter */
@@ -114,7 +114,7 @@ void init_outfixes_for_block(const struct RoseEngine *t,
fatbit_set(scratch->aqa, qCount, 0);
struct mq *q = scratch->queues;
- initQueue(q, 0, t, scratch);
+ initQueue(q, 0, t, scratch);
q->length = len; /* adjust for rev_accel */
nfaQueueInitState(nfa, q);
pushQueueAt(q, 0, MQE_START, 0);
@@ -134,7 +134,7 @@ void init_outfixes_for_block(const struct RoseEngine *t,
static really_inline
void init_for_block(const struct RoseEngine *t, struct hs_scratch *scratch,
- char *state, char is_small_block) {
+ char *state, char is_small_block) {
init_state_for_block(t, state);
struct RoseContext *tctxt = &scratch->tctxt;
@@ -159,211 +159,211 @@ void init_for_block(const struct RoseEngine *t, struct hs_scratch *scratch,
init_outfixes_for_block(t, scratch, state, is_small_block);
}
-static rose_inline
-void roseBlockEodExec(const struct RoseEngine *t, u64a offset,
- struct hs_scratch *scratch) {
- assert(t->requiresEodCheck);
- assert(t->maxBiAnchoredWidth == ROSE_BOUND_INF
- || offset <= t->maxBiAnchoredWidth);
-
- assert(!can_stop_matching(scratch));
- assert(t->eodProgramOffset);
-
- // Ensure that history is correct before we look for EOD matches.
- roseFlushLastByteHistory(t, scratch, offset);
- scratch->tctxt.lastEndOffset = offset;
-
- DEBUG_PRINTF("running eod program at %u\n", t->eodProgramOffset);
-
- // There should be no pending delayed literals.
- assert(!scratch->tctxt.filledDelayedSlots);
-
- const u64a som = 0;
- const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
-
- // Note: we ignore the result, as this is the last thing to ever happen on
- // a scan.
- roseRunProgram(t, scratch, t->eodProgramOffset, som, offset, flags);
-}
-
-/**
- * \brief Run the anchored matcher, if any. Returns non-zero if matching should
- * halt.
- */
-static rose_inline
-int roseBlockAnchored(const struct RoseEngine *t, struct hs_scratch *scratch) {
- const void *atable = getALiteralMatcher(t);
- if (!atable) {
- DEBUG_PRINTF("no anchored table\n");
- return 0;
- }
-
- const size_t length = scratch->core_info.len;
-
- if (t->amatcherMaxBiAnchoredWidth != ROSE_BOUND_INF &&
- length > t->amatcherMaxBiAnchoredWidth) {
- return 0;
- }
-
- if (length < t->amatcherMinWidth) {
- return 0;
- }
-
- runAnchoredTableBlock(t, atable, scratch);
-
- return can_stop_matching(scratch);
-}
-
-/**
- * \brief Run the floating matcher, if any. Returns non-zero if matching should
- * halt.
- */
-static rose_inline
-int roseBlockFloating(const struct RoseEngine *t, struct hs_scratch *scratch) {
- const struct HWLM *ftable = getFLiteralMatcher(t);
- if (!ftable) {
- return 0;
- }
-
- const size_t length = scratch->core_info.len;
- char *state = scratch->core_info.state;
- struct RoseContext *tctxt = &scratch->tctxt;
-
- DEBUG_PRINTF("ftable fd=%u fmd %u\n", t->floatingDistance,
- t->floatingMinDistance);
- if (t->noFloatingRoots && !roseHasInFlightMatches(t, state, scratch)) {
- DEBUG_PRINTF("skip FLOATING: no inflight matches\n");
- return 0;
- }
-
- if (t->fmatcherMaxBiAnchoredWidth != ROSE_BOUND_INF &&
- length > t->fmatcherMaxBiAnchoredWidth) {
- return 0;
- }
-
- if (length < t->fmatcherMinWidth) {
- return 0;
- }
-
- const u8 *buffer = scratch->core_info.buf;
- size_t flen = length;
- if (t->floatingDistance != ROSE_BOUND_INF) {
- flen = MIN(t->floatingDistance, length);
- }
- if (flen <= t->floatingMinDistance) {
- return 0;
- }
-
- DEBUG_PRINTF("BEGIN FLOATING (over %zu/%zu)\n", flen, length);
- DEBUG_PRINTF("-- %016llx\n", tctxt->groups);
- hwlmExec(ftable, buffer, flen, t->floatingMinDistance, roseFloatingCallback,
- scratch, tctxt->groups & t->floating_group_mask);
-
- return can_stop_matching(scratch);
-}
-
-static rose_inline
-void runEagerPrefixesBlock(const struct RoseEngine *t,
- struct hs_scratch *scratch) {
- if (!t->eagerIterOffset) {
- return;
- }
-
- char *state = scratch->core_info.state;
- u8 *ara = getActiveLeftArray(t, state); /* indexed by offsets into
- * left_table */
- const u32 arCount = t->activeLeftCount;
- const u32 qCount = t->queueCount;
- const struct LeftNfaInfo *left_table = getLeftTable(t);
- const struct mmbit_sparse_iter *it = getByOffset(t, t->eagerIterOffset);
-
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
-
- u32 idx = 0;
- u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
- for (; ri != MMB_INVALID;
- ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
- const struct LeftNfaInfo *left = left_table + ri;
- u32 qi = ri + t->leftfixBeginQueue;
- DEBUG_PRINTF("leftfix %u/%u, maxLag=%u\n", ri, arCount, left->maxLag);
-
- assert(!fatbit_isset(scratch->aqa, qCount, qi));
- assert(left->eager);
- assert(!left->infix);
-
- struct mq *q = scratch->queues + qi;
- const struct NFA *nfa = getNfaByQueue(t, qi);
-
- if (scratch->core_info.len < nfa->minWidth) {
- /* we know that there is not enough data for this to ever match, so
- * we can immediately squash/ */
- mmbit_unset(ara, arCount, ri);
- scratch->tctxt.groups &= left->squash_mask;
- }
-
- s64a loc = MIN(scratch->core_info.len, EAGER_STOP_OFFSET);
-
- fatbit_set(scratch->aqa, qCount, qi);
- initRoseQueue(t, qi, left, scratch);
-
- pushQueueAt(q, 0, MQE_START, 0);
- pushQueueAt(q, 1, MQE_TOP, 0);
- pushQueueAt(q, 2, MQE_END, loc);
- nfaQueueInitState(nfa, q);
-
- char alive = nfaQueueExecToMatch(q->nfa, q, loc);
-
- if (!alive) {
- DEBUG_PRINTF("queue %u dead, squashing\n", qi);
- mmbit_unset(ara, arCount, ri);
- fatbit_unset(scratch->aqa, qCount, qi);
- scratch->tctxt.groups &= left->squash_mask;
- } else if (q->cur == q->end) {
- assert(alive != MO_MATCHES_PENDING);
- if (loc == (s64a)scratch->core_info.len) {
- /* We know that the prefix does not match in the block so we
- * can squash the groups anyway even though it did not die */
- /* TODO: if we knew the minimum lag the leftfix is checked at we
- * could make this check tighter */
- DEBUG_PRINTF("queue %u has no match in block, squashing\n", qi);
- mmbit_unset(ara, arCount, ri);
- fatbit_unset(scratch->aqa, qCount, qi);
- scratch->tctxt.groups &= left->squash_mask;
- } else {
- DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
- q->cur = q->end = 0;
- pushQueueAt(q, 0, MQE_START, loc);
- }
- } else {
- assert(alive == MO_MATCHES_PENDING);
- DEBUG_PRINTF("queue %u unfinished, nfa lives\n", qi);
- q->end--; /* remove end item */
- }
- }
-}
-
-void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
+static rose_inline
+void roseBlockEodExec(const struct RoseEngine *t, u64a offset,
+ struct hs_scratch *scratch) {
+ assert(t->requiresEodCheck);
+ assert(t->maxBiAnchoredWidth == ROSE_BOUND_INF
+ || offset <= t->maxBiAnchoredWidth);
+
+ assert(!can_stop_matching(scratch));
+ assert(t->eodProgramOffset);
+
+ // Ensure that history is correct before we look for EOD matches.
+ roseFlushLastByteHistory(t, scratch, offset);
+ scratch->tctxt.lastEndOffset = offset;
+
+ DEBUG_PRINTF("running eod program at %u\n", t->eodProgramOffset);
+
+ // There should be no pending delayed literals.
+ assert(!scratch->tctxt.filledDelayedSlots);
+
+ const u64a som = 0;
+ const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
+
+ // Note: we ignore the result, as this is the last thing to ever happen on
+ // a scan.
+ roseRunProgram(t, scratch, t->eodProgramOffset, som, offset, flags);
+}
+
+/**
+ * \brief Run the anchored matcher, if any. Returns non-zero if matching should
+ * halt.
+ */
+static rose_inline
+int roseBlockAnchored(const struct RoseEngine *t, struct hs_scratch *scratch) {
+ const void *atable = getALiteralMatcher(t);
+ if (!atable) {
+ DEBUG_PRINTF("no anchored table\n");
+ return 0;
+ }
+
+ const size_t length = scratch->core_info.len;
+
+ if (t->amatcherMaxBiAnchoredWidth != ROSE_BOUND_INF &&
+ length > t->amatcherMaxBiAnchoredWidth) {
+ return 0;
+ }
+
+ if (length < t->amatcherMinWidth) {
+ return 0;
+ }
+
+ runAnchoredTableBlock(t, atable, scratch);
+
+ return can_stop_matching(scratch);
+}
+
+/**
+ * \brief Run the floating matcher, if any. Returns non-zero if matching should
+ * halt.
+ */
+static rose_inline
+int roseBlockFloating(const struct RoseEngine *t, struct hs_scratch *scratch) {
+ const struct HWLM *ftable = getFLiteralMatcher(t);
+ if (!ftable) {
+ return 0;
+ }
+
+ const size_t length = scratch->core_info.len;
+ char *state = scratch->core_info.state;
+ struct RoseContext *tctxt = &scratch->tctxt;
+
+ DEBUG_PRINTF("ftable fd=%u fmd %u\n", t->floatingDistance,
+ t->floatingMinDistance);
+ if (t->noFloatingRoots && !roseHasInFlightMatches(t, state, scratch)) {
+ DEBUG_PRINTF("skip FLOATING: no inflight matches\n");
+ return 0;
+ }
+
+ if (t->fmatcherMaxBiAnchoredWidth != ROSE_BOUND_INF &&
+ length > t->fmatcherMaxBiAnchoredWidth) {
+ return 0;
+ }
+
+ if (length < t->fmatcherMinWidth) {
+ return 0;
+ }
+
+ const u8 *buffer = scratch->core_info.buf;
+ size_t flen = length;
+ if (t->floatingDistance != ROSE_BOUND_INF) {
+ flen = MIN(t->floatingDistance, length);
+ }
+ if (flen <= t->floatingMinDistance) {
+ return 0;
+ }
+
+ DEBUG_PRINTF("BEGIN FLOATING (over %zu/%zu)\n", flen, length);
+ DEBUG_PRINTF("-- %016llx\n", tctxt->groups);
+ hwlmExec(ftable, buffer, flen, t->floatingMinDistance, roseFloatingCallback,
+ scratch, tctxt->groups & t->floating_group_mask);
+
+ return can_stop_matching(scratch);
+}
+
+static rose_inline
+void runEagerPrefixesBlock(const struct RoseEngine *t,
+ struct hs_scratch *scratch) {
+ if (!t->eagerIterOffset) {
+ return;
+ }
+
+ char *state = scratch->core_info.state;
+ u8 *ara = getActiveLeftArray(t, state); /* indexed by offsets into
+ * left_table */
+ const u32 arCount = t->activeLeftCount;
+ const u32 qCount = t->queueCount;
+ const struct LeftNfaInfo *left_table = getLeftTable(t);
+ const struct mmbit_sparse_iter *it = getByOffset(t, t->eagerIterOffset);
+
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+
+ u32 idx = 0;
+ u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
+ for (; ri != MMB_INVALID;
+ ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
+ const struct LeftNfaInfo *left = left_table + ri;
+ u32 qi = ri + t->leftfixBeginQueue;
+ DEBUG_PRINTF("leftfix %u/%u, maxLag=%u\n", ri, arCount, left->maxLag);
+
+ assert(!fatbit_isset(scratch->aqa, qCount, qi));
+ assert(left->eager);
+ assert(!left->infix);
+
+ struct mq *q = scratch->queues + qi;
+ const struct NFA *nfa = getNfaByQueue(t, qi);
+
+ if (scratch->core_info.len < nfa->minWidth) {
+ /* we know that there is not enough data for this to ever match, so
+ * we can immediately squash/ */
+ mmbit_unset(ara, arCount, ri);
+ scratch->tctxt.groups &= left->squash_mask;
+ }
+
+ s64a loc = MIN(scratch->core_info.len, EAGER_STOP_OFFSET);
+
+ fatbit_set(scratch->aqa, qCount, qi);
+ initRoseQueue(t, qi, left, scratch);
+
+ pushQueueAt(q, 0, MQE_START, 0);
+ pushQueueAt(q, 1, MQE_TOP, 0);
+ pushQueueAt(q, 2, MQE_END, loc);
+ nfaQueueInitState(nfa, q);
+
+ char alive = nfaQueueExecToMatch(q->nfa, q, loc);
+
+ if (!alive) {
+ DEBUG_PRINTF("queue %u dead, squashing\n", qi);
+ mmbit_unset(ara, arCount, ri);
+ fatbit_unset(scratch->aqa, qCount, qi);
+ scratch->tctxt.groups &= left->squash_mask;
+ } else if (q->cur == q->end) {
+ assert(alive != MO_MATCHES_PENDING);
+ if (loc == (s64a)scratch->core_info.len) {
+ /* We know that the prefix does not match in the block so we
+ * can squash the groups anyway even though it did not die */
+ /* TODO: if we knew the minimum lag the leftfix is checked at we
+ * could make this check tighter */
+ DEBUG_PRINTF("queue %u has no match in block, squashing\n", qi);
+ mmbit_unset(ara, arCount, ri);
+ fatbit_unset(scratch->aqa, qCount, qi);
+ scratch->tctxt.groups &= left->squash_mask;
+ } else {
+ DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
+ q->cur = q->end = 0;
+ pushQueueAt(q, 0, MQE_START, loc);
+ }
+ } else {
+ assert(alive == MO_MATCHES_PENDING);
+ DEBUG_PRINTF("queue %u unfinished, nfa lives\n", qi);
+ q->end--; /* remove end item */
+ }
+ }
+}
+
+void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
assert(t);
assert(scratch);
assert(scratch->core_info.buf);
assert(mmbit_sparse_iter_state_size(t->rolesWithStateCount)
< MAX_SPARSE_ITER_STATES);
- // We should not have been called if we've already been told to terminate
- // matching.
- assert(!told_to_stop_matching(scratch));
-
- // If this block is shorter than our minimum width, then no pattern in this
- // RoseEngine could match.
- /* minWidth checks should have already been performed by the caller */
- assert(scratch->core_info.len >= t->minWidth);
-
- // Similarly, we may have a maximum width (for engines constructed entirely
- // of bi-anchored patterns).
- /* This check is now handled by the interpreter */
- assert(t->maxBiAnchoredWidth == ROSE_BOUND_INF
- || scratch->core_info.len <= t->maxBiAnchoredWidth);
-
+ // We should not have been called if we've already been told to terminate
+ // matching.
+ assert(!told_to_stop_matching(scratch));
+
+ // If this block is shorter than our minimum width, then no pattern in this
+ // RoseEngine could match.
+ /* minWidth checks should have already been performed by the caller */
+ assert(scratch->core_info.len >= t->minWidth);
+
+ // Similarly, we may have a maximum width (for engines constructed entirely
+ // of bi-anchored patterns).
+ /* This check is now handled by the interpreter */
+ assert(t->maxBiAnchoredWidth == ROSE_BOUND_INF
+ || scratch->core_info.len <= t->maxBiAnchoredWidth);
+
const size_t length = scratch->core_info.len;
// We have optimizations for small block scans: we run a single coalesced
@@ -373,9 +373,9 @@ void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
const char is_small_block =
(length < ROSE_SMALL_BLOCK_LEN && t->sbmatcherOffset);
- char *state = scratch->core_info.state;
+ char *state = scratch->core_info.state;
- init_for_block(t, scratch, state, is_small_block);
+ init_for_block(t, scratch, state, is_small_block);
struct RoseContext *tctxt = &scratch->tctxt;
@@ -388,35 +388,35 @@ void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
DEBUG_PRINTF("BEGIN SMALL BLOCK (over %zu/%zu)\n", sblen, length);
DEBUG_PRINTF("-- %016llx\n", tctxt->groups);
hwlmExec(sbtable, scratch->core_info.buf, sblen, 0, roseCallback,
- scratch, tctxt->groups);
- } else {
- runEagerPrefixesBlock(t, scratch);
+ scratch, tctxt->groups);
+ } else {
+ runEagerPrefixesBlock(t, scratch);
- if (roseBlockAnchored(t, scratch)) {
- return;
+ if (roseBlockAnchored(t, scratch)) {
+ return;
}
- if (roseBlockFloating(t, scratch)) {
- return;
+ if (roseBlockFloating(t, scratch)) {
+ return;
}
- }
+ }
- if (cleanUpDelayed(t, scratch, length, 0) == HWLM_TERMINATE_MATCHING) {
- return;
+ if (cleanUpDelayed(t, scratch, length, 0) == HWLM_TERMINATE_MATCHING) {
+ return;
}
- assert(!can_stop_matching(scratch));
+ assert(!can_stop_matching(scratch));
- roseCatchUpTo(t, scratch, length);
+ roseCatchUpTo(t, scratch, length);
- if (!t->requiresEodCheck || !t->eodProgramOffset) {
- DEBUG_PRINTF("no eod check required\n");
- return;
+ if (!t->requiresEodCheck || !t->eodProgramOffset) {
+ DEBUG_PRINTF("no eod check required\n");
+ return;
}
- if (can_stop_matching(scratch)) {
- DEBUG_PRINTF("bailing, already halted\n");
+ if (can_stop_matching(scratch)) {
+ DEBUG_PRINTF("bailing, already halted\n");
return;
}
- roseBlockEodExec(t, length, scratch);
+ roseBlockEodExec(t, length, scratch);
}
diff --git a/contrib/libs/hyperscan/src/rose/catchup.c b/contrib/libs/hyperscan/src/rose/catchup.c
index 98ebd2f83b6..7a6648da980 100644
--- a/contrib/libs/hyperscan/src/rose/catchup.c
+++ b/contrib/libs/hyperscan/src/rose/catchup.c
@@ -26,20 +26,20 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Rose runtime: code for catching up output-exposed engines.
- */
-
+/**
+ * \file
+ * \brief Rose runtime: code for catching up output-exposed engines.
+ */
+
#include "catchup.h"
#include "match.h"
-#include "program_runtime.h"
+#include "program_runtime.h"
#include "rose.h"
#include "nfa/nfa_rev_api.h"
#include "nfa/mpv.h"
#include "som/som_runtime.h"
#include "util/fatbit.h"
-#include "report.h"
+#include "report.h"
typedef struct queue_match PQ_T;
#define PQ_COMP(pqc_items, a, b) ((pqc_items)[a].loc < (pqc_items)[b].loc)
@@ -48,57 +48,57 @@ typedef struct queue_match PQ_T;
#include "util/pqueue.h"
static really_inline
-int roseNfaRunProgram(const struct RoseEngine *rose, struct hs_scratch *scratch,
- u64a som, u64a offset, ReportID id, const char from_mpv) {
- const u32 program = id;
- u8 flags = ROSE_PROG_FLAG_IN_CATCHUP;
- if (from_mpv) {
- flags |= ROSE_PROG_FLAG_FROM_MPV;
+int roseNfaRunProgram(const struct RoseEngine *rose, struct hs_scratch *scratch,
+ u64a som, u64a offset, ReportID id, const char from_mpv) {
+ const u32 program = id;
+ u8 flags = ROSE_PROG_FLAG_IN_CATCHUP;
+ if (from_mpv) {
+ flags |= ROSE_PROG_FLAG_FROM_MPV;
}
- roseRunProgram(rose, scratch, program, som, offset, flags);
-
- return can_stop_matching(scratch) ? MO_HALT_MATCHING : MO_CONTINUE_MATCHING;
+ roseRunProgram(rose, scratch, program, som, offset, flags);
+
+ return can_stop_matching(scratch) ? MO_HALT_MATCHING : MO_CONTINUE_MATCHING;
}
-static rose_inline
-char roseSuffixInfoIsExhausted(const struct RoseEngine *rose,
- const struct NfaInfo *info,
- const char *exhausted) {
- if (!info->ekeyListOffset) {
+static rose_inline
+char roseSuffixInfoIsExhausted(const struct RoseEngine *rose,
+ const struct NfaInfo *info,
+ const char *exhausted) {
+ if (!info->ekeyListOffset) {
return 0;
}
- DEBUG_PRINTF("check exhaustion -> start at %u\n", info->ekeyListOffset);
+ DEBUG_PRINTF("check exhaustion -> start at %u\n", info->ekeyListOffset);
- /* INVALID_EKEY terminated list */
- const u32 *ekeys = getByOffset(rose, info->ekeyListOffset);
- while (*ekeys != INVALID_EKEY) {
- DEBUG_PRINTF("check %u\n", *ekeys);
- if (!isExhausted(rose, exhausted, *ekeys)) {
- DEBUG_PRINTF("not exhausted -> alive\n");
- return 0;
- }
- ++ekeys;
+ /* INVALID_EKEY terminated list */
+ const u32 *ekeys = getByOffset(rose, info->ekeyListOffset);
+ while (*ekeys != INVALID_EKEY) {
+ DEBUG_PRINTF("check %u\n", *ekeys);
+ if (!isExhausted(rose, exhausted, *ekeys)) {
+ DEBUG_PRINTF("not exhausted -> alive\n");
+ return 0;
+ }
+ ++ekeys;
}
- DEBUG_PRINTF("all ekeys exhausted -> dead\n");
- return 1;
+ DEBUG_PRINTF("all ekeys exhausted -> dead\n");
+ return 1;
}
-static really_inline
-char roseSuffixIsExhausted(const struct RoseEngine *rose, u32 qi,
- const char *exhausted) {
- DEBUG_PRINTF("check queue %u\n", qi);
- const struct NfaInfo *info = getNfaInfoByQueue(rose, qi);
- return roseSuffixInfoIsExhausted(rose, info, exhausted);
+static really_inline
+char roseSuffixIsExhausted(const struct RoseEngine *rose, u32 qi,
+ const char *exhausted) {
+ DEBUG_PRINTF("check queue %u\n", qi);
+ const struct NfaInfo *info = getNfaInfoByQueue(rose, qi);
+ return roseSuffixInfoIsExhausted(rose, info, exhausted);
}
static really_inline
-void deactivateQueue(const struct RoseEngine *t, u8 *aa, u32 qi,
- struct hs_scratch *scratch) {
- u32 aaCount = t->activeArrayCount;
- u32 qCount = t->queueCount;
+void deactivateQueue(const struct RoseEngine *t, u8 *aa, u32 qi,
+ struct hs_scratch *scratch) {
+ u32 aaCount = t->activeArrayCount;
+ u32 qCount = t->queueCount;
/* this is sailing close to the wind with regards to invalidating an
* iteration. We are saved by the fact that unsetting does not clear the
@@ -114,7 +114,7 @@ void ensureQueueActive(const struct RoseEngine *t, u32 qi, u32 qCount,
struct mq *q, struct hs_scratch *scratch) {
if (!fatbit_set(scratch->aqa, qCount, qi)) {
DEBUG_PRINTF("initing %u\n", qi);
- initQueue(q, qi, t, scratch);
+ initQueue(q, qi, t, scratch);
loadStreamState(q->nfa, q, 0);
pushQueueAt(q, 0, MQE_START, 0);
}
@@ -165,8 +165,8 @@ s64a pq_top_loc(struct catchup_pq *pq) {
/* requires that we are the top item on the pq */
static really_inline
-hwlmcb_rv_t runExistingNfaToNextMatch(const struct RoseEngine *t, u32 qi,
- struct mq *q, s64a loc,
+hwlmcb_rv_t runExistingNfaToNextMatch(const struct RoseEngine *t, u32 qi,
+ struct mq *q, s64a loc,
struct hs_scratch *scratch, u8 *aa,
char report_curr) {
assert(pq_top(scratch->catchup_pq.qm)->queue == qi);
@@ -197,7 +197,7 @@ hwlmcb_rv_t runExistingNfaToNextMatch(const struct RoseEngine *t, u32 qi,
return HWLM_TERMINATE_MATCHING;
}
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
} else if (q->cur == q->end) {
DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
q->cur = q->end = 0;
@@ -222,8 +222,8 @@ hwlmcb_rv_t runExistingNfaToNextMatch(const struct RoseEngine *t, u32 qi,
}
static really_inline
-hwlmcb_rv_t runNewNfaToNextMatch(const struct RoseEngine *t, u32 qi,
- struct mq *q, s64a loc,
+hwlmcb_rv_t runNewNfaToNextMatch(const struct RoseEngine *t, u32 qi,
+ struct mq *q, s64a loc,
struct hs_scratch *scratch, u8 *aa,
s64a report_ok_loc) {
assert(!q->report_current);
@@ -256,7 +256,7 @@ restart:
return HWLM_TERMINATE_MATCHING;
}
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
} else if (q->cur == q->end) {
DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
q->cur = q->end = 0;
@@ -279,23 +279,23 @@ restart:
}
/* for use by mpv (chained) only */
-static
-int roseNfaFinalBlastAdaptor(u64a start, u64a end, ReportID id, void *context) {
- struct hs_scratch *scratch = context;
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
- const struct RoseEngine *t = scratch->core_info.rose;
+static
+int roseNfaFinalBlastAdaptor(u64a start, u64a end, ReportID id, void *context) {
+ struct hs_scratch *scratch = context;
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+ const struct RoseEngine *t = scratch->core_info.rose;
- DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
+ DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
- int cb_rv = roseNfaRunProgram(t, scratch, start, end, id, 1);
+ int cb_rv = roseNfaRunProgram(t, scratch, start, end, id, 1);
if (cb_rv == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
} else if (cb_rv == ROSE_CONTINUE_MATCHING_NO_EXHAUST) {
return MO_CONTINUE_MATCHING;
} else {
assert(cb_rv == MO_CONTINUE_MATCHING);
- return !roseSuffixIsExhausted(t, 0,
- scratch->core_info.exhaustionVector);
+ return !roseSuffixIsExhausted(t, 0,
+ scratch->core_info.exhaustionVector);
}
}
@@ -318,7 +318,7 @@ hwlmcb_rv_t add_to_queue(const struct RoseEngine *t, struct mq *queues,
if (roseSuffixInfoIsExhausted(t, info,
scratch->core_info.exhaustionVector)) {
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
return HWLM_CONTINUE_MATCHING;
}
@@ -331,7 +331,7 @@ hwlmcb_rv_t add_to_queue(const struct RoseEngine *t, struct mq *queues,
ensureEnd(q, qi, loc);
- return runNewNfaToNextMatch(t, qi, q, loc, scratch, aa, report_ok_loc);
+ return runNewNfaToNextMatch(t, qi, q, loc, scratch, aa, report_ok_loc);
}
static really_inline
@@ -352,9 +352,9 @@ s64a findSecondPlace(struct catchup_pq *pq, s64a loc_limit) {
}
}
-hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
+hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
struct hs_scratch *scratch) {
- char *state = scratch->core_info.state;
+ char *state = scratch->core_info.state;
struct mq *queues = scratch->queues;
u8 *aa = getActiveLeafArray(t, state);
UNUSED u32 aaCount = t->activeArrayCount;
@@ -377,7 +377,7 @@ hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
if (roseSuffixInfoIsExhausted(t, info,
scratch->core_info.exhaustionVector)) {
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
goto done;
}
@@ -392,7 +392,7 @@ hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
assert(!q->report_current);
- q->cb = roseNfaFinalBlastAdaptor;
+ q->cb = roseNfaFinalBlastAdaptor;
DEBUG_PRINTF("queue %u blasting, %u/%u [%lld/%lld]\n",
qi, q->cur, q->end, q->items[q->cur].location, loc);
@@ -400,13 +400,13 @@ hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
scratch->tctxt.mpv_inactive = 0;
/* we know it is going to be an mpv, skip the indirection */
- next_pos_match_loc = nfaExecMpv_QueueExecRaw(q->nfa, q, loc);
+ next_pos_match_loc = nfaExecMpv_QueueExecRaw(q->nfa, q, loc);
assert(!q->report_current);
if (!next_pos_match_loc) { /* 0 means dead */
DEBUG_PRINTF("mpv is pining for the fjords\n");
if (can_stop_matching(scratch)) {
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
return HWLM_TERMINATE_MATCHING;
}
@@ -441,59 +441,59 @@ done:
: HWLM_CONTINUE_MATCHING;
}
-static really_inline
-char in_mpv(const struct RoseEngine *rose, const struct hs_scratch *scratch) {
- const struct RoseContext *tctxt = &scratch->tctxt;
- assert(tctxt->curr_qi < rose->queueCount);
- if (tctxt->curr_qi < rose->outfixBeginQueue) {
- assert(getNfaByQueue(rose, tctxt->curr_qi)->type == MPV_NFA);
- return 1;
- }
- return 0;
+static really_inline
+char in_mpv(const struct RoseEngine *rose, const struct hs_scratch *scratch) {
+ const struct RoseContext *tctxt = &scratch->tctxt;
+ assert(tctxt->curr_qi < rose->queueCount);
+ if (tctxt->curr_qi < rose->outfixBeginQueue) {
+ assert(getNfaByQueue(rose, tctxt->curr_qi)->type == MPV_NFA);
+ return 1;
+ }
+ return 0;
}
-static
-int roseNfaBlastAdaptor(u64a start, u64a end, ReportID id, void *context) {
- struct hs_scratch *scratch = context;
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
- const struct RoseEngine *t = scratch->core_info.rose;
+static
+int roseNfaBlastAdaptor(u64a start, u64a end, ReportID id, void *context) {
+ struct hs_scratch *scratch = context;
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+ const struct RoseEngine *t = scratch->core_info.rose;
- DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
+ DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
- const char from_mpv = in_mpv(t, scratch);
- int cb_rv = roseNfaRunProgram(t, scratch, start, end, id, from_mpv);
+ const char from_mpv = in_mpv(t, scratch);
+ int cb_rv = roseNfaRunProgram(t, scratch, start, end, id, from_mpv);
if (cb_rv == MO_HALT_MATCHING) {
return MO_HALT_MATCHING;
} else if (cb_rv == ROSE_CONTINUE_MATCHING_NO_EXHAUST) {
return MO_CONTINUE_MATCHING;
} else {
assert(cb_rv == MO_CONTINUE_MATCHING);
- return !roseSuffixIsExhausted(t, scratch->tctxt.curr_qi,
- scratch->core_info.exhaustionVector);
+ return !roseSuffixIsExhausted(t, scratch->tctxt.curr_qi,
+ scratch->core_info.exhaustionVector);
}
}
-int roseNfaAdaptor(u64a start, u64a end, ReportID id, void *context) {
- struct hs_scratch *scratch = context;
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
+int roseNfaAdaptor(u64a start, u64a end, ReportID id, void *context) {
+ struct hs_scratch *scratch = context;
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
- DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
+ DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
/* must be a external report as haig cannot directly participate in chain */
- return roseNfaRunProgram(scratch->core_info.rose, scratch, start, end, id,
- 0);
+ return roseNfaRunProgram(scratch->core_info.rose, scratch, start, end, id,
+ 0);
}
static really_inline
-char blast_queue(struct hs_scratch *scratch, struct mq *q, u32 qi, s64a to_loc,
- char report_current) {
- scratch->tctxt.curr_qi = qi;
- q->cb = roseNfaBlastAdaptor;
+char blast_queue(struct hs_scratch *scratch, struct mq *q, u32 qi, s64a to_loc,
+ char report_current) {
+ scratch->tctxt.curr_qi = qi;
+ q->cb = roseNfaBlastAdaptor;
q->report_current = report_current;
DEBUG_PRINTF("queue %u blasting, %u/%u [%lld/%lld]\n", qi, q->cur, q->end,
q_cur_loc(q), to_loc);
char alive = nfaQueueExec(q->nfa, q, to_loc);
- q->cb = roseNfaAdaptor;
+ q->cb = roseNfaAdaptor;
assert(!q->report_current);
return alive;
@@ -510,7 +510,7 @@ hwlmcb_rv_t buildSufPQ_final(const struct RoseEngine *t, s64a report_ok_loc,
if (roseSuffixInfoIsExhausted(t, info,
scratch->core_info.exhaustionVector)) {
- deactivateQueue(t, aa, a_qi, scratch);
+ deactivateQueue(t, aa, a_qi, scratch);
return HWLM_CONTINUE_MATCHING;
}
@@ -523,9 +523,9 @@ hwlmcb_rv_t buildSufPQ_final(const struct RoseEngine *t, s64a report_ok_loc,
ensureEnd(q, a_qi, final_loc);
- char alive = blast_queue(scratch, q, a_qi, second_place_loc, 0);
+ char alive = blast_queue(scratch, q, a_qi, second_place_loc, 0);
- /* We have three possible outcomes:
+ /* We have three possible outcomes:
* (1) the nfa died
* (2) we completed the queue (implies that second_place_loc == final_loc)
* (3) the queue ran to second_place_loc and stopped. In this case we need
@@ -538,7 +538,7 @@ hwlmcb_rv_t buildSufPQ_final(const struct RoseEngine *t, s64a report_ok_loc,
return HWLM_TERMINATE_MATCHING;
}
- deactivateQueue(t, aa, a_qi, scratch);
+ deactivateQueue(t, aa, a_qi, scratch);
} else if (q->cur == q->end) {
DEBUG_PRINTF("queue %u finished, nfa lives [%lld]\n", a_qi, final_loc);
@@ -554,8 +554,8 @@ hwlmcb_rv_t buildSufPQ_final(const struct RoseEngine *t, s64a report_ok_loc,
assert(second_place_loc < final_loc);
assert(q_cur_loc(q) >= second_place_loc);
- if (runNewNfaToNextMatch(t, a_qi, q, final_loc, scratch, aa,
- report_ok_loc) == HWLM_TERMINATE_MATCHING) {
+ if (runNewNfaToNextMatch(t, a_qi, q, final_loc, scratch, aa,
+ report_ok_loc) == HWLM_TERMINATE_MATCHING) {
DEBUG_PRINTF("roseCatchUpNfas done\n");
return HWLM_TERMINATE_MATCHING;
}
@@ -564,7 +564,7 @@ hwlmcb_rv_t buildSufPQ_final(const struct RoseEngine *t, s64a report_ok_loc,
return HWLM_CONTINUE_MATCHING;
}
-void streamInitSufPQ(const struct RoseEngine *t, char *state,
+void streamInitSufPQ(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch) {
assert(scratch->catchup_pq.qm_size == 0);
assert(t->outfixBeginQueue != t->outfixEndQueue);
@@ -595,7 +595,7 @@ void streamInitSufPQ(const struct RoseEngine *t, char *state,
pq_insert_with(&scratch->catchup_pq, scratch, qi, qcl);
} else if (!alive) {
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
} else {
assert(q->cur == q->end);
/* TODO: can this be simplified? the nfa will never produce any
@@ -609,7 +609,7 @@ void streamInitSufPQ(const struct RoseEngine *t, char *state,
}
}
-void blockInitSufPQ(const struct RoseEngine *t, char *state,
+void blockInitSufPQ(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, char is_small_block) {
DEBUG_PRINTF("initSufPQ: outfixes [%u,%u)\n", t->outfixBeginQueue,
t->outfixEndQueue);
@@ -642,7 +642,7 @@ void blockInitSufPQ(const struct RoseEngine *t, char *state,
mmbit_set(aa, aaCount, qi);
fatbit_set(aqa, qCount, qi);
struct mq *q = queues + qi;
- initQueue(q, qi, t, scratch);
+ initQueue(q, qi, t, scratch);
q->length = len; /* adjust for rev_accel */
nfaQueueInitState(nfa, q);
pushQueueAt(q, 0, MQE_START, 0);
@@ -659,7 +659,7 @@ void blockInitSufPQ(const struct RoseEngine *t, char *state,
pq_insert_with(&scratch->catchup_pq, scratch, qi, qcl);
} else if (!alive) {
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
} else {
assert(q->cur == q->end);
/* TODO: can this be simplified? the nfa will never produce any
@@ -675,7 +675,7 @@ void blockInitSufPQ(const struct RoseEngine *t, char *state,
* safe_loc is ???
*/
static rose_inline
-hwlmcb_rv_t buildSufPQ(const struct RoseEngine *t, char *state, s64a safe_loc,
+hwlmcb_rv_t buildSufPQ(const struct RoseEngine *t, char *state, s64a safe_loc,
s64a final_loc, struct hs_scratch *scratch) {
assert(scratch->catchup_pq.qm_size <= t->outfixEndQueue);
@@ -714,9 +714,9 @@ hwlmcb_rv_t buildSufPQ(const struct RoseEngine *t, char *state, s64a safe_loc,
s64a report_ok_loc = tctxt->minNonMpvMatchOffset + 1
- scratch->core_info.buf_offset;
- hwlmcb_rv_t rv = roseCatchUpMPV(t, report_ok_loc, scratch);
+ hwlmcb_rv_t rv = roseCatchUpMPV(t, report_ok_loc, scratch);
if (rv != HWLM_CONTINUE_MATCHING) {
- DEBUG_PRINTF("terminating...\n");
+ DEBUG_PRINTF("terminating...\n");
return rv;
}
@@ -728,7 +728,7 @@ hwlmcb_rv_t buildSufPQ(const struct RoseEngine *t, char *state, s64a safe_loc,
= scratch->catchup_pq.qm_size ? pq_top_loc(&scratch->catchup_pq)
: safe_loc;
second_place_loc = MIN(second_place_loc, safe_loc);
- if (n_qi == MMB_INVALID && report_ok_loc <= second_place_loc) {
+ if (n_qi == MMB_INVALID && report_ok_loc <= second_place_loc) {
if (buildSufPQ_final(t, report_ok_loc, second_place_loc, final_loc,
scratch, aa, a_qi)
== HWLM_TERMINATE_MATCHING) {
@@ -752,19 +752,19 @@ hwlmcb_rv_t buildSufPQ(const struct RoseEngine *t, char *state, s64a safe_loc,
}
static never_inline
-hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
+hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
s64a final_loc, struct hs_scratch *scratch) {
assert(t->activeArrayCount);
- DEBUG_PRINTF("roseCatchUpNfas offset=%llu + %lld/%lld\n",
- scratch->core_info.buf_offset, loc, final_loc);
+ DEBUG_PRINTF("roseCatchUpNfas offset=%llu + %lld/%lld\n",
+ scratch->core_info.buf_offset, loc, final_loc);
DEBUG_PRINTF("min non mpv match offset %llu\n",
scratch->tctxt.minNonMpvMatchOffset);
- struct RoseContext *tctxt = &scratch->tctxt;
- assert(scratch->core_info.buf_offset + loc >= tctxt->minNonMpvMatchOffset);
-
- char *state = scratch->core_info.state;
+ struct RoseContext *tctxt = &scratch->tctxt;
+ assert(scratch->core_info.buf_offset + loc >= tctxt->minNonMpvMatchOffset);
+
+ char *state = scratch->core_info.state;
struct mq *queues = scratch->queues;
u8 *aa = getActiveLeafArray(t, state);
@@ -785,7 +785,7 @@ hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
}
/* catch up char matches to this point */
- if (roseCatchUpMPV(t, match_loc, scratch)
+ if (roseCatchUpMPV(t, match_loc, scratch)
== HWLM_TERMINATE_MATCHING) {
DEBUG_PRINTF("roseCatchUpNfas done\n");
return HWLM_TERMINATE_MATCHING;
@@ -812,14 +812,14 @@ hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
DEBUG_PRINTF("second place %lld loc %lld\n", second_place_loc, loc);
if (second_place_loc == q_cur_loc(q)) {
- if (runExistingNfaToNextMatch(t, qi, q, q_final_loc, scratch, aa, 1)
+ if (runExistingNfaToNextMatch(t, qi, q, q_final_loc, scratch, aa, 1)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
continue;
}
- char alive = blast_queue(scratch, q, qi, second_place_loc, 1);
+ char alive = blast_queue(scratch, q, qi, second_place_loc, 1);
if (!alive) {
if (can_stop_matching(scratch)) {
@@ -827,7 +827,7 @@ hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
return HWLM_TERMINATE_MATCHING;
}
- deactivateQueue(t, aa, qi, scratch);
+ deactivateQueue(t, aa, qi, scratch);
pq_pop_nice(&scratch->catchup_pq);
} else if (q->cur == q->end) {
DEBUG_PRINTF("queue %u finished, nfa lives [%lld]\n", qi, loc);
@@ -841,7 +841,7 @@ hwlmcb_rv_t roseCatchUpNfas(const struct RoseEngine *t, s64a loc,
} else {
DEBUG_PRINTF("queue %u not finished, %u/%u [%lld/%lld]\n",
qi, q->cur, q->end, q->items[q->cur].location, loc);
- runExistingNfaToNextMatch(t, qi, q, q_final_loc, scratch, aa, 0);
+ runExistingNfaToNextMatch(t, qi, q, q_final_loc, scratch, aa, 0);
}
}
exit:;
@@ -858,23 +858,23 @@ hwlmcb_rv_t roseCatchUpAll(s64a loc, struct hs_scratch *scratch) {
assert(scratch->core_info.buf_offset + loc
> scratch->tctxt.minNonMpvMatchOffset);
- const struct RoseEngine *t = scratch->core_info.rose;
- char *state = scratch->core_info.state;
-
- hwlmcb_rv_t rv = buildSufPQ(t, state, loc, loc, scratch);
+ const struct RoseEngine *t = scratch->core_info.rose;
+ char *state = scratch->core_info.state;
+
+ hwlmcb_rv_t rv = buildSufPQ(t, state, loc, loc, scratch);
if (rv != HWLM_CONTINUE_MATCHING) {
return rv;
}
- rv = roseCatchUpNfas(t, loc, loc, scratch);
+ rv = roseCatchUpNfas(t, loc, loc, scratch);
if (rv != HWLM_CONTINUE_MATCHING) {
return rv;
}
- rv = roseCatchUpMPV(t, loc, scratch);
+ rv = roseCatchUpMPV(t, loc, scratch);
assert(rv != HWLM_CONTINUE_MATCHING
- || scratch->catchup_pq.qm_size <= t->outfixEndQueue);
- assert(!can_stop_matching(scratch) || rv == HWLM_TERMINATE_MATCHING);
+ || scratch->catchup_pq.qm_size <= t->outfixEndQueue);
+ assert(!can_stop_matching(scratch) || rv == HWLM_TERMINATE_MATCHING);
return rv;
}
@@ -884,17 +884,17 @@ hwlmcb_rv_t roseCatchUpSuf(s64a loc, struct hs_scratch *scratch) {
assert(scratch->core_info.buf_offset + loc
> scratch->tctxt.minNonMpvMatchOffset);
- const struct RoseEngine *t = scratch->core_info.rose;
- char *state = scratch->core_info.state;
-
- hwlmcb_rv_t rv = buildSufPQ(t, state, loc, loc, scratch);
+ const struct RoseEngine *t = scratch->core_info.rose;
+ char *state = scratch->core_info.state;
+
+ hwlmcb_rv_t rv = buildSufPQ(t, state, loc, loc, scratch);
if (rv != HWLM_CONTINUE_MATCHING) {
return rv;
}
- rv = roseCatchUpNfas(t, loc, loc, scratch);
- assert(rv != HWLM_CONTINUE_MATCHING ||
- scratch->catchup_pq.qm_size <= t->outfixEndQueue);
+ rv = roseCatchUpNfas(t, loc, loc, scratch);
+ assert(rv != HWLM_CONTINUE_MATCHING ||
+ scratch->catchup_pq.qm_size <= t->outfixEndQueue);
return rv;
}
diff --git a/contrib/libs/hyperscan/src/rose/catchup.h b/contrib/libs/hyperscan/src/rose/catchup.h
index 978a8c7007c..8188d5af01e 100644
--- a/contrib/libs/hyperscan/src/rose/catchup.h
+++ b/contrib/libs/hyperscan/src/rose/catchup.h
@@ -26,25 +26,25 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Rose runtime: code for catching up output-exposed engines.
- *
- * Rose has several components which run behind the main (floating table) clock
- * and need to be caught up before we report matches.
- *
- * Currently we have to deal with:
- * 1. Suffix/Outfix NFAs
- * 2. A single MPV NFA (chained), which may also be triggered by (1).
- *
- * The approach is to:
- * - (A) build a priority queue of the suffix/outfixes based on their first
- * match location;
- * - (B) process the matches from the priority queue in order;
- * - (C) As we report matches from (B) we interleave matches from the MPV if it
- * exists.
- */
-
+/**
+ * \file
+ * \brief Rose runtime: code for catching up output-exposed engines.
+ *
+ * Rose has several components which run behind the main (floating table) clock
+ * and need to be caught up before we report matches.
+ *
+ * Currently we have to deal with:
+ * 1. Suffix/Outfix NFAs
+ * 2. A single MPV NFA (chained), which may also be triggered by (1).
+ *
+ * The approach is to:
+ * - (A) build a priority queue of the suffix/outfixes based on their first
+ * match location;
+ * - (B) process the matches from the priority queue in order;
+ * - (C) As we report matches from (B) we interleave matches from the MPV if it
+ * exists.
+ */
+
#ifndef ROSE_CATCHUP_H
#define ROSE_CATCHUP_H
@@ -59,74 +59,74 @@
hwlmcb_rv_t roseCatchUpAll(s64a loc, struct hs_scratch *scratch);
-/* will only catch mpv up to last reported external match */
+/* will only catch mpv up to last reported external match */
hwlmcb_rv_t roseCatchUpSuf(s64a loc, struct hs_scratch *scratch);
-hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
+hwlmcb_rv_t roseCatchUpMPV_i(const struct RoseEngine *t, s64a loc,
struct hs_scratch *scratch);
-void blockInitSufPQ(const struct RoseEngine *t, char *state,
+void blockInitSufPQ(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, char is_small_block);
-void streamInitSufPQ(const struct RoseEngine *t, char *state,
+void streamInitSufPQ(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch);
static really_inline
-int canSkipCatchUpMPV(const struct RoseEngine *t, struct hs_scratch *scratch,
- u64a cur_offset) {
+int canSkipCatchUpMPV(const struct RoseEngine *t, struct hs_scratch *scratch,
+ u64a cur_offset) {
if (!has_chained_nfas(t)) {
- return 1;
+ return 1;
}
/* note: we may have to run at less than tctxt.minMatchOffset as we may
* have a full queue of postponed events that we need to flush */
if (cur_offset < scratch->tctxt.next_mpv_offset) {
- DEBUG_PRINTF("skipping cur_offset %llu min %llu, mpv %llu\n",
+ DEBUG_PRINTF("skipping cur_offset %llu min %llu, mpv %llu\n",
cur_offset, scratch->tctxt.minMatchOffset,
scratch->tctxt.next_mpv_offset);
- return 1;
+ return 1;
}
assert(t->activeArrayCount);
- DEBUG_PRINTF("cur offset offset: %llu\n", cur_offset);
+ DEBUG_PRINTF("cur offset offset: %llu\n", cur_offset);
DEBUG_PRINTF("min match offset %llu\n", scratch->tctxt.minMatchOffset);
assert(t->outfixBeginQueue == 1); /* if it exists mpv is queue 0 */
- const u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
- return !mmbit_isset(aa, t->activeArrayCount, 0);
-}
-
-/** \brief Catches up the MPV. */
-static really_inline
-hwlmcb_rv_t roseCatchUpMPV(const struct RoseEngine *t, s64a loc,
- struct hs_scratch *scratch) {
- u64a cur_offset = loc + scratch->core_info.buf_offset;
- assert(cur_offset >= scratch->tctxt.minMatchOffset);
- assert(!can_stop_matching(scratch));
-
- if (canSkipCatchUpMPV(t, scratch, cur_offset)) {
+ const u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
+ return !mmbit_isset(aa, t->activeArrayCount, 0);
+}
+
+/** \brief Catches up the MPV. */
+static really_inline
+hwlmcb_rv_t roseCatchUpMPV(const struct RoseEngine *t, s64a loc,
+ struct hs_scratch *scratch) {
+ u64a cur_offset = loc + scratch->core_info.buf_offset;
+ assert(cur_offset >= scratch->tctxt.minMatchOffset);
+ assert(!can_stop_matching(scratch));
+
+ if (canSkipCatchUpMPV(t, scratch, cur_offset)) {
if (t->flushCombProgramOffset) {
if (roseRunFlushCombProgram(t, scratch, cur_offset)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
}
- updateMinMatchOffsetFromMpv(&scratch->tctxt, cur_offset);
- return HWLM_CONTINUE_MATCHING;
+ updateMinMatchOffsetFromMpv(&scratch->tctxt, cur_offset);
+ return HWLM_CONTINUE_MATCHING;
}
/* Note: chained tails MUST not participate in the priority queue as
* they may have events pushed on during this process which may be before
* the catch up point */
- return roseCatchUpMPV_i(t, loc, scratch);
+ return roseCatchUpMPV_i(t, loc, scratch);
}
-/** \brief Catches up NFAs and the MPV. */
+/** \brief Catches up NFAs and the MPV. */
static rose_inline
-hwlmcb_rv_t roseCatchUpTo(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a end) {
+hwlmcb_rv_t roseCatchUpTo(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a end) {
/* no need to catch up if we are at the same offset as last time */
if (end <= scratch->tctxt.minMatchOffset) {
/* we must already be up to date */
@@ -134,48 +134,48 @@ hwlmcb_rv_t roseCatchUpTo(const struct RoseEngine *t,
return HWLM_CONTINUE_MATCHING;
}
- char *state = scratch->core_info.state;
+ char *state = scratch->core_info.state;
s64a loc = end - scratch->core_info.buf_offset;
if (end <= scratch->tctxt.minNonMpvMatchOffset) {
/* only need to catch up the mpv */
- return roseCatchUpMPV(t, loc, scratch);
+ return roseCatchUpMPV(t, loc, scratch);
}
assert(scratch->tctxt.minMatchOffset >= scratch->core_info.buf_offset);
hwlmcb_rv_t rv;
- if (!t->activeArrayCount
- || !mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
+ if (!t->activeArrayCount
+ || !mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
if (t->flushCombProgramOffset) {
if (roseRunFlushCombProgram(t, scratch, end)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
}
- updateMinMatchOffset(&scratch->tctxt, end);
- rv = HWLM_CONTINUE_MATCHING;
+ updateMinMatchOffset(&scratch->tctxt, end);
+ rv = HWLM_CONTINUE_MATCHING;
} else {
- rv = roseCatchUpAll(loc, scratch);
+ rv = roseCatchUpAll(loc, scratch);
}
assert(rv != HWLM_CONTINUE_MATCHING
|| scratch->tctxt.minMatchOffset == end);
assert(rv != HWLM_CONTINUE_MATCHING
|| scratch->tctxt.minNonMpvMatchOffset == end);
- assert(!can_stop_matching(scratch) || rv == HWLM_TERMINATE_MATCHING);
+ assert(!can_stop_matching(scratch) || rv == HWLM_TERMINATE_MATCHING);
return rv;
}
-/**
- * \brief Catches up anything which may add triggers on the MPV (suffixes and
- * outfixes).
- *
- * The MPV will be run only to intersperse matches in the output match stream
- * if external matches are raised.
- */
+/**
+ * \brief Catches up anything which may add triggers on the MPV (suffixes and
+ * outfixes).
+ *
+ * The MPV will be run only to intersperse matches in the output match stream
+ * if external matches are raised.
+ */
static rose_inline
-hwlmcb_rv_t roseCatchUpMpvFeeders(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a end) {
+hwlmcb_rv_t roseCatchUpMpvFeeders(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a end) {
/* no need to catch up if we are at the same offset as last time */
if (end <= scratch->tctxt.minNonMpvMatchOffset) {
/* we must already be up to date */
@@ -188,20 +188,20 @@ hwlmcb_rv_t roseCatchUpMpvFeeders(const struct RoseEngine *t,
assert(t->activeArrayCount); /* mpv is in active array */
assert(scratch->tctxt.minMatchOffset >= scratch->core_info.buf_offset);
- if (!t->mpvTriggeredByLeaf) {
- /* no need to check as they never put triggers onto the mpv */
- return HWLM_CONTINUE_MATCHING;
- }
-
- /* sadly, this branch rarely gets taken as the mpv itself is usually
- * alive. */
- char *state = scratch->core_info.state;
- if (!mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
- scratch->tctxt.minNonMpvMatchOffset = end;
- return HWLM_CONTINUE_MATCHING;
+ if (!t->mpvTriggeredByLeaf) {
+ /* no need to check as they never put triggers onto the mpv */
+ return HWLM_CONTINUE_MATCHING;
+ }
+
+ /* sadly, this branch rarely gets taken as the mpv itself is usually
+ * alive. */
+ char *state = scratch->core_info.state;
+ if (!mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
+ scratch->tctxt.minNonMpvMatchOffset = end;
+ return HWLM_CONTINUE_MATCHING;
}
-
- return roseCatchUpSuf(loc, scratch);
+
+ return roseCatchUpSuf(loc, scratch);
}
#endif
diff --git a/contrib/libs/hyperscan/src/rose/counting_miracle.h b/contrib/libs/hyperscan/src/rose/counting_miracle.h
index c68404925ba..976208b7383 100644
--- a/contrib/libs/hyperscan/src/rose/counting_miracle.h
+++ b/contrib/libs/hyperscan/src/rose/counting_miracle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -82,7 +82,7 @@ char roseCountingMiracleScan(u8 c, const u8 *d, const u8 *d_end,
}
#define GET_LO_4(chars) and128(chars, low4bits)
-#define GET_HI_4(chars) rshift64_m128(andnot128(low4bits, chars), 4)
+#define GET_HI_4(chars) rshift64_m128(andnot128(low4bits, chars), 4)
static really_inline
u32 roseCountingMiracleScanShufti(m128 mask_lo, m128 mask_hi, u8 poison,
@@ -98,8 +98,8 @@ u32 roseCountingMiracleScanShufti(m128 mask_lo, m128 mask_hi, u8 poison,
for (; d + 16 <= d_end; d_end -= 16) {
m128 data = loadu128(d_end - 16);
- m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(data));
- m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(data));
+ m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(data));
+ m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(data));
m128 t = and128(c_lo, c_hi);
u32 z1 = movemask128(eq128(t, zeroes));
count += popcount32(z1 ^ 0xffff);
@@ -117,8 +117,8 @@ u32 roseCountingMiracleScanShufti(m128 mask_lo, m128 mask_hi, u8 poison,
memset(temp, poison, sizeof(temp));
memcpy(temp, d, d_end - d);
m128 data = loadu128(temp);
- m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(data));
- m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(data));
+ m128 c_lo = pshufb_m128(mask_lo, GET_LO_4(data));
+ m128 c_hi = pshufb_m128(mask_hi, GET_HI_4(data));
m128 t = and128(c_lo, c_hi);
u32 z1 = movemask128(eq128(t, zeroes));
count += popcount32(z1 ^ 0xffff);
diff --git a/contrib/libs/hyperscan/src/rose/infix.h b/contrib/libs/hyperscan/src/rose/infix.h
index cfae16abd9c..9cf9c0ad740 100644
--- a/contrib/libs/hyperscan/src/rose/infix.h
+++ b/contrib/libs/hyperscan/src/rose/infix.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,7 @@
#include "ue2common.h"
#include "nfa/nfa_api.h"
#include "nfa/nfa_api_queue.h"
-#include "nfa/nfa_internal.h"
+#include "nfa/nfa_internal.h"
static really_inline
int infixTooOld(struct mq *q, s64a curr_loc) {
@@ -45,27 +45,27 @@ int infixTooOld(struct mq *q, s64a curr_loc) {
return q_last_loc(q) + maxAge < curr_loc;
}
-static really_inline
-int canReduceQueue(const struct mq *q, s64a curr_loc, u32 maxTops, u32 maxAge) {
- u32 qlen = q->end - q->cur; /* includes MQE_START */
-
- if (maxAge && q->items[q->cur].location + maxAge < curr_loc) {
- return 1;
- }
-
- if (qlen - 1 > maxTops) {
- return 1;
- }
-
- if (qlen - 1 == maxTops
- && q->items[q->cur].location != q->items[q->cur + 1].location) {
- /* we can advance start to the first top location */
- return 1;
- }
-
- return 0;
-}
-
+static really_inline
+int canReduceQueue(const struct mq *q, s64a curr_loc, u32 maxTops, u32 maxAge) {
+ u32 qlen = q->end - q->cur; /* includes MQE_START */
+
+ if (maxAge && q->items[q->cur].location + maxAge < curr_loc) {
+ return 1;
+ }
+
+ if (qlen - 1 > maxTops) {
+ return 1;
+ }
+
+ if (qlen - 1 == maxTops
+ && q->items[q->cur].location != q->items[q->cur + 1].location) {
+ /* we can advance start to the first top location */
+ return 1;
+ }
+
+ return 0;
+}
+
/**
* Removes tops which are known not to affect the final state from the queue.
* May also reinitialise the engine state if it is unneeded.
@@ -84,14 +84,14 @@ int canReduceQueue(const struct mq *q, s64a curr_loc, u32 maxTops, u32 maxAge) {
* engine.
*/
static really_inline
-void reduceInfixQueue(struct mq *q, s64a curr_loc, u32 maxTops, u32 maxAge) {
+void reduceInfixQueue(struct mq *q, s64a curr_loc, u32 maxTops, u32 maxAge) {
assert(q->end > q->cur);
assert(maxTops);
u32 qlen = q->end - q->cur; /* includes MQE_START */
DEBUG_PRINTF("q=%p, len=%u, maxTops=%u maxAge=%u\n", q, qlen, maxTops,
maxAge);
- if (!canReduceQueue(q, curr_loc, maxTops, maxAge)) {
+ if (!canReduceQueue(q, curr_loc, maxTops, maxAge)) {
DEBUG_PRINTF("nothing to do\n");
return;
}
diff --git a/contrib/libs/hyperscan/src/rose/init.c b/contrib/libs/hyperscan/src/rose/init.c
index 0c6a1cfcdec..025ecca0d61 100644
--- a/contrib/libs/hyperscan/src/rose/init.c
+++ b/contrib/libs/hyperscan/src/rose/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -42,14 +42,14 @@
#include <string.h>
static really_inline
-void init_rstate(const struct RoseEngine *t, char *state) {
- // Set runtime state: we take our initial groups from the RoseEngine.
+void init_rstate(const struct RoseEngine *t, char *state) {
+ // Set runtime state: we take our initial groups from the RoseEngine.
DEBUG_PRINTF("setting initial groups to 0x%016llx\n", t->initialGroups);
storeGroups(t, state, t->initialGroups);
}
static really_inline
-void init_outfixes(const struct RoseEngine *t, char *state) {
+void init_outfixes(const struct RoseEngine *t, char *state) {
/* The active leaf array has been init'ed by the scatter with outfix
* bits set on */
@@ -71,12 +71,12 @@ void init_outfixes(const struct RoseEngine *t, char *state) {
}
}
-void roseInitState(const struct RoseEngine *t, char *state) {
+void roseInitState(const struct RoseEngine *t, char *state) {
assert(t);
assert(state);
- DEBUG_PRINTF("init for Rose %p with %u state indices)\n", t,
- t->rolesWithStateCount);
+ DEBUG_PRINTF("init for Rose %p with %u state indices)\n", t,
+ t->rolesWithStateCount);
// Rose is guaranteed 8-aligned state
assert(ISALIGNED_N(state, 8));
diff --git a/contrib/libs/hyperscan/src/rose/init.h b/contrib/libs/hyperscan/src/rose/init.h
index bb622e6e0b7..b37053b2619 100644
--- a/contrib/libs/hyperscan/src/rose/init.h
+++ b/contrib/libs/hyperscan/src/rose/init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,7 +39,7 @@
*/
static really_inline
-void init_state(const struct RoseEngine *t, char *state) {
+void init_state(const struct RoseEngine *t, char *state) {
scatter(state, t, &t->state_init);
}
diff --git a/contrib/libs/hyperscan/src/rose/match.c b/contrib/libs/hyperscan/src/rose/match.c
index 7fdacd22a3e..84d3b1fdc2c 100644
--- a/contrib/libs/hyperscan/src/rose/match.c
+++ b/contrib/libs/hyperscan/src/rose/match.c
@@ -28,7 +28,7 @@
#include "catchup.h"
#include "match.h"
-#include "program_runtime.h"
+#include "program_runtime.h"
#include "rose.h"
#include "util/bitutils.h"
#include "util/fatbit.h"
@@ -66,32 +66,32 @@ void printMatch(const struct core_info *ci, u64a start, u64a end) {
}
#endif
-hwlmcb_rv_t roseDelayRebuildCallback(size_t end, u32 id,
- struct hs_scratch *scratch) {
+hwlmcb_rv_t roseDelayRebuildCallback(size_t end, u32 id,
+ struct hs_scratch *scratch) {
struct RoseContext *tctx = &scratch->tctxt;
struct core_info *ci = &scratch->core_info;
- const struct RoseEngine *t = ci->rose;
+ const struct RoseEngine *t = ci->rose;
size_t rb_len = MIN(ci->hlen, t->delayRebuildLength);
u64a real_end = ci->buf_offset - rb_len + end + 1; // index after last byte
#ifdef DEBUG
- DEBUG_PRINTF("REBUILD MATCH id=%u end offset@%llu]: ", id, real_end);
- u64a start = real_end < 8 ? 1 : real_end - 7;
- printMatch(ci, start, real_end);
+ DEBUG_PRINTF("REBUILD MATCH id=%u end offset@%llu]: ", id, real_end);
+ u64a start = real_end < 8 ? 1 : real_end - 7;
+ printMatch(ci, start, real_end);
printf("\n");
#endif
- DEBUG_PRINTF("STATE groups=0x%016llx\n", tctx->groups);
+ DEBUG_PRINTF("STATE groups=0x%016llx\n", tctx->groups);
- assert(id && id < t->size); // id is a program offset
- const u64a som = 0;
- const u8 flags = 0;
- UNUSED hwlmcb_rv_t rv =
- roseRunProgram(t, scratch, id, som, real_end, flags);
- assert(rv != HWLM_TERMINATE_MATCHING);
+ assert(id && id < t->size); // id is a program offset
+ const u64a som = 0;
+ const u8 flags = 0;
+ UNUSED hwlmcb_rv_t rv =
+ roseRunProgram(t, scratch, id, som, real_end, flags);
+ assert(rv != HWLM_TERMINATE_MATCHING);
- /* we are just repopulating the delay queue, groups should be
+ /* we are just repopulating the delay queue, groups should be
* already set from the original scan. */
return tctx->groups;
@@ -100,23 +100,23 @@ hwlmcb_rv_t roseDelayRebuildCallback(size_t end, u32 id,
static really_inline
hwlmcb_rv_t ensureMpvQueueFlushed(const struct RoseEngine *t,
struct hs_scratch *scratch, u32 qi, s64a loc,
- char in_chained) {
- return ensureQueueFlushed_i(t, scratch, qi, loc, 1, in_chained);
+ char in_chained) {
+ return ensureQueueFlushed_i(t, scratch, qi, loc, 1, in_chained);
}
-hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 event,
- u64a top_squash_distance, u64a end,
- char in_catchup) {
- assert(event == MQE_TOP || event >= MQE_TOP_FIRST);
+hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 event,
+ u64a top_squash_distance, u64a end,
+ char in_catchup) {
+ assert(event == MQE_TOP || event >= MQE_TOP_FIRST);
struct core_info *ci = &scratch->core_info;
- u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
+ u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
u32 aaCount = t->activeArrayCount;
struct fatbit *activeQueues = scratch->aqa;
u32 qCount = t->queueCount;
- const u32 qi = 0; /* MPV is always queue 0 if it exists */
+ const u32 qi = 0; /* MPV is always queue 0 if it exists */
struct mq *q = &scratch->queues[qi];
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
@@ -124,7 +124,7 @@ hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
assert(loc <= (s64a)ci->len && loc >= -(s64a)ci->hlen);
if (!mmbit_set(aa, aaCount, qi)) {
- initQueue(q, qi, t, scratch);
+ initQueue(q, qi, t, scratch);
nfaQueueInitState(q->nfa, q);
pushQueueAt(q, 0, MQE_START, loc);
fatbit_set(activeQueues, qCount, qi);
@@ -133,25 +133,25 @@ hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
/* nfa only needs one top; we can go home now */
return HWLM_CONTINUE_MATCHING;
} else if (!fatbit_set(activeQueues, qCount, qi)) {
- initQueue(q, qi, t, scratch);
+ initQueue(q, qi, t, scratch);
loadStreamState(q->nfa, q, 0);
pushQueueAt(q, 0, MQE_START, 0);
} else if (isQueueFull(q)) {
DEBUG_PRINTF("queue %u full -> catching up nfas\n", qi);
/* we know it is a chained nfa and the suffixes/outfixes must already
* be known to be consistent */
- if (ensureMpvQueueFlushed(t, scratch, qi, loc, in_catchup)
+ if (ensureMpvQueueFlushed(t, scratch, qi, loc, in_catchup)
== HWLM_TERMINATE_MATCHING) {
- DEBUG_PRINTF("terminating...\n");
+ DEBUG_PRINTF("terminating...\n");
return HWLM_TERMINATE_MATCHING;
}
}
- if (top_squash_distance) {
- assert(q->cur < q->end);
+ if (top_squash_distance) {
+ assert(q->cur < q->end);
struct mq_item *last = &q->items[q->end - 1];
if (last->type == event
- && last->location >= loc - (s64a)top_squash_distance) {
+ && last->location >= loc - (s64a)top_squash_distance) {
last->location = loc;
goto event_enqueued;
}
@@ -166,7 +166,7 @@ event_enqueued:
pushQueueNoMerge(q, MQE_END, loc);
char alive = nfaQueueExec(q->nfa, q, loc);
if (alive) {
- scratch->tctxt.mpv_inactive = 0;
+ scratch->tctxt.mpv_inactive = 0;
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, loc);
} else {
@@ -176,24 +176,24 @@ event_enqueued:
}
DEBUG_PRINTF("added mpv event at %lld\n", loc);
- scratch->tctxt.next_mpv_offset = 0; /* the top event may result in matches
- * earlier than expected */
+ scratch->tctxt.next_mpv_offset = 0; /* the top event may result in matches
+ * earlier than expected */
return HWLM_CONTINUE_MATCHING;
}
-int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx) {
- struct hs_scratch *scratch = ctx;
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
- struct RoseContext *tctxt = &scratch->tctxt;
+int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx) {
+ struct hs_scratch *scratch = ctx;
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+ struct RoseContext *tctxt = &scratch->tctxt;
struct core_info *ci = &scratch->core_info;
- const struct RoseEngine *t = ci->rose;
+ const struct RoseEngine *t = ci->rose;
u64a real_end = ci->buf_offset + end; // index after last byte
DEBUG_PRINTF("MATCH id=%u offsets=[???,%llu]\n", id, real_end);
- DEBUG_PRINTF("STATE groups=0x%016llx\n", tctxt->groups);
+ DEBUG_PRINTF("STATE groups=0x%016llx\n", tctxt->groups);
- if (can_stop_matching(scratch)) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("received a match when we're already dead!\n");
return MO_HALT_MATCHING;
}
@@ -206,38 +206,38 @@ int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx) {
* boundary */
if (real_end <= t->floatingMinLiteralMatchOffset) {
- roseFlushLastByteHistory(t, scratch, real_end);
+ roseFlushLastByteHistory(t, scratch, real_end);
tctxt->lastEndOffset = real_end;
}
- // Note that the "id" we have been handed is the program offset.
- const u8 flags = ROSE_PROG_FLAG_IN_ANCHORED;
- if (roseRunProgram(t, scratch, id, start, real_end, flags)
- == HWLM_TERMINATE_MATCHING) {
- assert(can_stop_matching(scratch));
+ // Note that the "id" we have been handed is the program offset.
+ const u8 flags = ROSE_PROG_FLAG_IN_ANCHORED;
+ if (roseRunProgram(t, scratch, id, start, real_end, flags)
+ == HWLM_TERMINATE_MATCHING) {
+ assert(can_stop_matching(scratch));
DEBUG_PRINTF("caller requested termination\n");
return MO_HALT_MATCHING;
}
- DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
+ DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
return MO_CONTINUE_MATCHING;
}
-/**
- * \brief Run the program for the given literal ID, with the interpreter
- * inlined into this call.
- *
- * Assumes not in_anchored.
- */
+/**
+ * \brief Run the program for the given literal ID, with the interpreter
+ * inlined into this call.
+ *
+ * Assumes not in_anchored.
+ */
static really_inline
-hwlmcb_rv_t roseProcessMatchInline(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a end,
- u32 id) {
+hwlmcb_rv_t roseProcessMatchInline(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a end,
+ u32 id) {
DEBUG_PRINTF("id=%u\n", id);
- assert(id && id < t->size); // id is an offset into bytecode
- const u64a som = 0;
- const u8 flags = 0;
+ assert(id && id < t->size); // id is an offset into bytecode
+ const u64a som = 0;
+ const u8 flags = 0;
if (t->pureLiteral) {
return roseRunProgram_l(t, scratch, id, som, end, flags);
} else {
@@ -246,38 +246,38 @@ hwlmcb_rv_t roseProcessMatchInline(const struct RoseEngine *t,
}
static rose_inline
-hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t,
- struct hs_scratch *scratch,
- struct fatbit **delaySlots, u32 vicIndex,
- u64a offset) {
+hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t,
+ struct hs_scratch *scratch,
+ struct fatbit **delaySlots, u32 vicIndex,
+ u64a offset) {
/* assert(!tctxt->in_anchored); */
assert(vicIndex < DELAY_SLOT_COUNT);
- const struct fatbit *vicSlot = delaySlots[vicIndex];
- u32 delay_count = t->delay_count;
+ const struct fatbit *vicSlot = delaySlots[vicIndex];
+ u32 delay_count = t->delay_count;
- if (offset < t->floatingMinLiteralMatchOffset) {
+ if (offset < t->floatingMinLiteralMatchOffset) {
DEBUG_PRINTF("too soon\n");
return HWLM_CONTINUE_MATCHING;
}
- struct RoseContext *tctxt = &scratch->tctxt;
- roseFlushLastByteHistory(t, scratch, offset);
+ struct RoseContext *tctxt = &scratch->tctxt;
+ roseFlushLastByteHistory(t, scratch, offset);
tctxt->lastEndOffset = offset;
- const u32 *programs = getByOffset(t, t->delayProgramOffset);
+ const u32 *programs = getByOffset(t, t->delayProgramOffset);
- for (u32 it = fatbit_iterate(vicSlot, delay_count, MMB_INVALID);
- it != MMB_INVALID; it = fatbit_iterate(vicSlot, delay_count, it)) {
+ for (u32 it = fatbit_iterate(vicSlot, delay_count, MMB_INVALID);
+ it != MMB_INVALID; it = fatbit_iterate(vicSlot, delay_count, it)) {
UNUSED rose_group old_groups = tctxt->groups;
- DEBUG_PRINTF("DELAYED MATCH id=%u offset=%llu\n", it, offset);
- const u64a som = 0;
- const u8 flags = 0;
- hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, offset,
- flags);
- DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
+ DEBUG_PRINTF("DELAYED MATCH id=%u offset=%llu\n", it, offset);
+ const u64a som = 0;
+ const u8 flags = 0;
+ hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, offset,
+ flags);
+ DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
- /* delayed literals can't safely set groups.
+ /* delayed literals can't safely set groups.
* However we may be setting groups that successors already have
* worked out that we don't need to match the group */
DEBUG_PRINTF("groups in %016llx out %016llx\n", old_groups,
@@ -292,30 +292,30 @@ hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t,
}
static really_inline
-hwlmcb_rv_t flushAnchoredLiteralAtLoc(const struct RoseEngine *t,
- struct hs_scratch *scratch,
- u32 curr_loc) {
- struct RoseContext *tctxt = &scratch->tctxt;
- struct fatbit *curr_row = getAnchoredLiteralLog(scratch)[curr_loc - 1];
- u32 region_width = t->anchored_count;
-
- const u32 *programs = getByOffset(t, t->anchoredProgramOffset);
-
+hwlmcb_rv_t flushAnchoredLiteralAtLoc(const struct RoseEngine *t,
+ struct hs_scratch *scratch,
+ u32 curr_loc) {
+ struct RoseContext *tctxt = &scratch->tctxt;
+ struct fatbit *curr_row = getAnchoredLiteralLog(scratch)[curr_loc - 1];
+ u32 region_width = t->anchored_count;
+
+ const u32 *programs = getByOffset(t, t->anchoredProgramOffset);
+
DEBUG_PRINTF("report matches at curr loc\n");
- for (u32 it = fatbit_iterate(curr_row, region_width, MMB_INVALID);
- it != MMB_INVALID; it = fatbit_iterate(curr_row, region_width, it)) {
+ for (u32 it = fatbit_iterate(curr_row, region_width, MMB_INVALID);
+ it != MMB_INVALID; it = fatbit_iterate(curr_row, region_width, it)) {
DEBUG_PRINTF("it = %u/%u\n", it, region_width);
rose_group old_groups = tctxt->groups;
- DEBUG_PRINTF("ANCH REPLAY MATCH id=%u offset=%u\n", it, curr_loc);
- const u64a som = 0;
- const u8 flags = 0;
- hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, curr_loc,
- flags);
- DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
-
- /* anchored literals can't safely set groups.
- * However we may be setting groups that successors already
+ DEBUG_PRINTF("ANCH REPLAY MATCH id=%u offset=%u\n", it, curr_loc);
+ const u64a som = 0;
+ const u8 flags = 0;
+ hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, curr_loc,
+ flags);
+ DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
+
+ /* anchored literals can't safely set groups.
+ * However we may be setting groups that successors already
* have worked out that we don't need to match the group */
DEBUG_PRINTF("groups in %016llx out %016llx\n", old_groups,
tctxt->groups);
@@ -333,22 +333,22 @@ hwlmcb_rv_t flushAnchoredLiteralAtLoc(const struct RoseEngine *t,
}
static really_inline
-u32 anchored_it_begin(struct hs_scratch *scratch) {
- struct RoseContext *tctxt = &scratch->tctxt;
+u32 anchored_it_begin(struct hs_scratch *scratch) {
+ struct RoseContext *tctxt = &scratch->tctxt;
if (tctxt->lastEndOffset >= scratch->anchored_literal_region_len) {
return MMB_INVALID;
}
u32 begin = tctxt->lastEndOffset;
begin--;
- return bf64_iterate(scratch->al_log_sum, begin);
+ return bf64_iterate(scratch->al_log_sum, begin);
}
static really_inline
-hwlmcb_rv_t flushAnchoredLiterals(const struct RoseEngine *t,
- struct hs_scratch *scratch,
+hwlmcb_rv_t flushAnchoredLiterals(const struct RoseEngine *t,
+ struct hs_scratch *scratch,
u32 *anchored_it_param, u64a to_off) {
- struct RoseContext *tctxt = &scratch->tctxt;
+ struct RoseContext *tctxt = &scratch->tctxt;
u32 anchored_it = *anchored_it_param;
/* catch up any remaining anchored matches */
for (; anchored_it != MMB_INVALID && anchored_it < to_off;
@@ -356,10 +356,10 @@ hwlmcb_rv_t flushAnchoredLiterals(const struct RoseEngine *t,
assert(anchored_it < scratch->anchored_literal_region_len);
DEBUG_PRINTF("loc_it = %u\n", anchored_it);
u32 curr_off = anchored_it + 1;
- roseFlushLastByteHistory(t, scratch, curr_off);
+ roseFlushLastByteHistory(t, scratch, curr_off);
tctxt->lastEndOffset = curr_off;
- if (flushAnchoredLiteralAtLoc(t, scratch, curr_off)
+ if (flushAnchoredLiteralAtLoc(t, scratch, curr_off)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
@@ -370,21 +370,21 @@ hwlmcb_rv_t flushAnchoredLiterals(const struct RoseEngine *t,
}
static really_inline
-hwlmcb_rv_t playVictims(const struct RoseEngine *t, struct hs_scratch *scratch,
- u32 *anchored_it, u64a lastEnd, u64a victimDelaySlots,
- struct fatbit **delaySlots) {
+hwlmcb_rv_t playVictims(const struct RoseEngine *t, struct hs_scratch *scratch,
+ u32 *anchored_it, u64a lastEnd, u64a victimDelaySlots,
+ struct fatbit **delaySlots) {
while (victimDelaySlots) {
u32 vic = findAndClearLSB_64(&victimDelaySlots);
DEBUG_PRINTF("vic = %u\n", vic);
u64a vicOffset = vic + (lastEnd & ~(u64a)DELAY_MASK);
- if (flushAnchoredLiterals(t, scratch, anchored_it, vicOffset)
+ if (flushAnchoredLiterals(t, scratch, anchored_it, vicOffset)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
- if (playDelaySlot(t, scratch, delaySlots, vic % DELAY_SLOT_COUNT,
- vicOffset) == HWLM_TERMINATE_MATCHING) {
+ if (playDelaySlot(t, scratch, delaySlots, vic % DELAY_SLOT_COUNT,
+ vicOffset) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
}
@@ -393,16 +393,16 @@ hwlmcb_rv_t playVictims(const struct RoseEngine *t, struct hs_scratch *scratch,
}
/* call flushQueuedLiterals instead */
-hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a currEnd) {
- struct RoseContext *tctxt = &scratch->tctxt;
+hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a currEnd) {
+ struct RoseContext *tctxt = &scratch->tctxt;
u64a lastEnd = tctxt->delayLastEndOffset;
DEBUG_PRINTF("flushing backed up matches @%llu up from %llu\n", currEnd,
lastEnd);
assert(currEnd != lastEnd); /* checked in main entry point */
- u32 anchored_it = anchored_it_begin(scratch);
+ u32 anchored_it = anchored_it_begin(scratch);
if (!tctxt->filledDelayedSlots) {
DEBUG_PRINTF("no delayed, no flush\n");
@@ -410,7 +410,7 @@ hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
}
{
- struct fatbit **delaySlots = getDelaySlots(scratch);
+ struct fatbit **delaySlots = getDelaySlots(scratch);
u32 lastIndex = lastEnd & DELAY_MASK;
u32 currIndex = currEnd & DELAY_MASK;
@@ -463,45 +463,45 @@ hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
second_half, victimDelaySlots, lastIndex);
}
- if (playVictims(t, scratch, &anchored_it, lastEnd, victimDelaySlots,
- delaySlots) == HWLM_TERMINATE_MATCHING) {
+ if (playVictims(t, scratch, &anchored_it, lastEnd, victimDelaySlots,
+ delaySlots) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
}
anchored_leftovers:;
- hwlmcb_rv_t rv = flushAnchoredLiterals(t, scratch, &anchored_it, currEnd);
+ hwlmcb_rv_t rv = flushAnchoredLiterals(t, scratch, &anchored_it, currEnd);
tctxt->delayLastEndOffset = currEnd;
return rv;
}
-static really_inline
-hwlmcb_rv_t roseCallback_i(size_t end, u32 id, struct hs_scratch *scratch) {
- struct RoseContext *tctx = &scratch->tctxt;
- const struct RoseEngine *t = scratch->core_info.rose;
-
+static really_inline
+hwlmcb_rv_t roseCallback_i(size_t end, u32 id, struct hs_scratch *scratch) {
+ struct RoseContext *tctx = &scratch->tctxt;
+ const struct RoseEngine *t = scratch->core_info.rose;
+
u64a real_end = end + tctx->lit_offset_adjust;
#if defined(DEBUG)
- DEBUG_PRINTF("MATCH id=%u end offset@%llu: ", id, real_end);
- u64a start = real_end < 8 ? 1 : real_end - 7;
- printMatch(&scratch->core_info, start, real_end);
+ DEBUG_PRINTF("MATCH id=%u end offset@%llu: ", id, real_end);
+ u64a start = real_end < 8 ? 1 : real_end - 7;
+ printMatch(&scratch->core_info, start, real_end);
printf("\n");
#endif
DEBUG_PRINTF("last end %llu\n", tctx->lastEndOffset);
- DEBUG_PRINTF("STATE groups=0x%016llx\n", tctx->groups);
+ DEBUG_PRINTF("STATE groups=0x%016llx\n", tctx->groups);
- if (can_stop_matching(scratch)) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("received a match when we're already dead!\n");
return HWLM_TERMINATE_MATCHING;
}
- hwlmcb_rv_t rv = flushQueuedLiterals(t, scratch, real_end);
+ hwlmcb_rv_t rv = flushQueuedLiterals(t, scratch, real_end);
/* flushDelayed may have advanced tctx->lastEndOffset */
- if (real_end >= t->floatingMinLiteralMatchOffset) {
- roseFlushLastByteHistory(t, scratch, real_end);
+ if (real_end >= t->floatingMinLiteralMatchOffset) {
+ roseFlushLastByteHistory(t, scratch, real_end);
tctx->lastEndOffset = real_end;
}
@@ -509,72 +509,72 @@ hwlmcb_rv_t roseCallback_i(size_t end, u32 id, struct hs_scratch *scratch) {
return HWLM_TERMINATE_MATCHING;
}
- rv = roseProcessMatchInline(t, scratch, real_end, id);
+ rv = roseProcessMatchInline(t, scratch, real_end, id);
- DEBUG_PRINTF("DONE groups=0x%016llx\n", tctx->groups);
+ DEBUG_PRINTF("DONE groups=0x%016llx\n", tctx->groups);
if (rv != HWLM_TERMINATE_MATCHING) {
return tctx->groups;
}
- assert(can_stop_matching(scratch));
+ assert(can_stop_matching(scratch));
DEBUG_PRINTF("user requested halt\n");
return HWLM_TERMINATE_MATCHING;
}
-hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch) {
- return roseCallback_i(end, id, scratch);
-}
-
-hwlmcb_rv_t roseFloatingCallback(size_t end, u32 id,
- struct hs_scratch *scratch) {
- const struct RoseEngine *t = scratch->core_info.rose;
-
- return roseCallback_i(end, id, scratch) & t->floating_group_mask;
-}
-
-/**
- * \brief Execute a boundary report program.
- *
- * Returns MO_HALT_MATCHING if the stream is exhausted or the user has
- * instructed us to halt, or MO_CONTINUE_MATCHING otherwise.
- */
-int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program,
- u64a stream_offset, struct hs_scratch *scratch) {
- DEBUG_PRINTF("running boundary program at offset %u\n", program);
-
- if (can_stop_matching(scratch)) {
- DEBUG_PRINTF("can stop matching\n");
- return MO_HALT_MATCHING;
- }
-
- if (rose->hasSom && scratch->deduper.current_report_offset == ~0ULL) {
- /* we cannot delay the initialization of the som deduper logs any longer
- * as we are reporting matches. This is done explicitly as we are
- * shortcutting the som handling in the vacuous repeats as we know they
- * all come from non-som patterns. */
- fatbit_clear(scratch->deduper.som_log[0]);
- fatbit_clear(scratch->deduper.som_log[1]);
- scratch->deduper.som_log_dirty = 0;
- }
-
- // Keep assertions in program report path happy. At offset zero, there can
- // have been no earlier reports. At EOD, all earlier reports should have
- // been handled and we will have been caught up to the stream offset by the
- // time we are running boundary report programs.
- scratch->tctxt.minMatchOffset = stream_offset;
-
- const u64a som = 0;
- const u8 flags = 0;
- hwlmcb_rv_t rv = roseRunProgram(rose, scratch, program, som, stream_offset,
- flags);
- if (rv == HWLM_TERMINATE_MATCHING) {
- return MO_HALT_MATCHING;
- }
-
- return MO_CONTINUE_MATCHING;
+hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch) {
+ return roseCallback_i(end, id, scratch);
+}
+
+hwlmcb_rv_t roseFloatingCallback(size_t end, u32 id,
+ struct hs_scratch *scratch) {
+ const struct RoseEngine *t = scratch->core_info.rose;
+
+ return roseCallback_i(end, id, scratch) & t->floating_group_mask;
}
-
+
+/**
+ * \brief Execute a boundary report program.
+ *
+ * Returns MO_HALT_MATCHING if the stream is exhausted or the user has
+ * instructed us to halt, or MO_CONTINUE_MATCHING otherwise.
+ */
+int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program,
+ u64a stream_offset, struct hs_scratch *scratch) {
+ DEBUG_PRINTF("running boundary program at offset %u\n", program);
+
+ if (can_stop_matching(scratch)) {
+ DEBUG_PRINTF("can stop matching\n");
+ return MO_HALT_MATCHING;
+ }
+
+ if (rose->hasSom && scratch->deduper.current_report_offset == ~0ULL) {
+ /* we cannot delay the initialization of the som deduper logs any longer
+ * as we are reporting matches. This is done explicitly as we are
+ * shortcutting the som handling in the vacuous repeats as we know they
+ * all come from non-som patterns. */
+ fatbit_clear(scratch->deduper.som_log[0]);
+ fatbit_clear(scratch->deduper.som_log[1]);
+ scratch->deduper.som_log_dirty = 0;
+ }
+
+ // Keep assertions in program report path happy. At offset zero, there can
+ // have been no earlier reports. At EOD, all earlier reports should have
+ // been handled and we will have been caught up to the stream offset by the
+ // time we are running boundary report programs.
+ scratch->tctxt.minMatchOffset = stream_offset;
+
+ const u64a som = 0;
+ const u8 flags = 0;
+ hwlmcb_rv_t rv = roseRunProgram(rose, scratch, program, som, stream_offset,
+ flags);
+ if (rv == HWLM_TERMINATE_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+
+ return MO_CONTINUE_MATCHING;
+}
+
/**
* \brief Execute a flush combination program.
*
@@ -608,26 +608,26 @@ int roseRunLastFlushCombProgram(const struct RoseEngine *rose,
return MO_CONTINUE_MATCHING;
}
-int roseReportAdaptor(u64a start, u64a end, ReportID id, void *context) {
- struct hs_scratch *scratch = context;
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
-
- DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
-
- const struct RoseEngine *rose = scratch->core_info.rose;
-
- // Our match ID is the program offset.
- const u32 program = id;
- const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
+int roseReportAdaptor(u64a start, u64a end, ReportID id, void *context) {
+ struct hs_scratch *scratch = context;
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+
+ DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end);
+
+ const struct RoseEngine *rose = scratch->core_info.rose;
+
+ // Our match ID is the program offset.
+ const u32 program = id;
+ const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
hwlmcb_rv_t rv;
if (rose->pureLiteral) {
rv = roseRunProgram_l(rose, scratch, program, start, end, flags);
} else {
rv = roseRunProgram(rose, scratch, program, start, end, flags);
}
- if (rv == HWLM_TERMINATE_MATCHING) {
- return MO_HALT_MATCHING;
- }
-
- return can_stop_matching(scratch) ? MO_HALT_MATCHING : MO_CONTINUE_MATCHING;
-}
+ if (rv == HWLM_TERMINATE_MATCHING) {
+ return MO_HALT_MATCHING;
+ }
+
+ return can_stop_matching(scratch) ? MO_HALT_MATCHING : MO_CONTINUE_MATCHING;
+}
diff --git a/contrib/libs/hyperscan/src/rose/match.h b/contrib/libs/hyperscan/src/rose/match.h
index 28d21391ea8..c03b1ebbaed 100644
--- a/contrib/libs/hyperscan/src/rose/match.h
+++ b/contrib/libs/hyperscan/src/rose/match.h
@@ -29,61 +29,61 @@
#ifndef ROSE_MATCH_H
#define ROSE_MATCH_H
-#include "catchup.h"
+#include "catchup.h"
#include "runtime.h"
#include "scratch.h"
-#include "report.h"
+#include "report.h"
#include "rose_common.h"
#include "rose_internal.h"
#include "ue2common.h"
-#include "hwlm/hwlm.h"
+#include "hwlm/hwlm.h"
#include "nfa/nfa_api.h"
#include "nfa/nfa_api_queue.h"
#include "nfa/nfa_api_util.h"
#include "som/som_runtime.h"
#include "util/bitutils.h"
-#include "util/exhaust.h"
-#include "util/fatbit.h"
+#include "util/exhaust.h"
+#include "util/fatbit.h"
#include "util/multibit.h"
/* Callbacks, defined in catchup.c */
-int roseNfaAdaptor(u64a start, u64a end, ReportID id, void *context);
+int roseNfaAdaptor(u64a start, u64a end, ReportID id, void *context);
/* Callbacks, defined in match.c */
-hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch);
-hwlmcb_rv_t roseFloatingCallback(size_t end, u32 id,
- struct hs_scratch *scratch);
-hwlmcb_rv_t roseDelayRebuildCallback(size_t end, u32 id,
- struct hs_scratch *scratch);
-int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx);
+hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch);
+hwlmcb_rv_t roseFloatingCallback(size_t end, u32 id,
+ struct hs_scratch *scratch);
+hwlmcb_rv_t roseDelayRebuildCallback(size_t end, u32 id,
+ struct hs_scratch *scratch);
+int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx);
/* Common code, used all over Rose runtime */
-hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 event,
- u64a top_squash_distance, u64a end,
- char in_catchup);
+hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 event,
+ u64a top_squash_distance, u64a end,
+ char in_catchup);
/** \brief Initialize the queue for a suffix/outfix engine. */
static really_inline
void initQueue(struct mq *q, u32 qi, const struct RoseEngine *t,
- struct hs_scratch *scratch) {
+ struct hs_scratch *scratch) {
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
assert(scratch->fullState);
q->nfa = getNfaByInfo(t, info);
q->end = 0;
q->cur = 0;
q->state = scratch->fullState + info->fullStateOffset;
- q->streamState = scratch->core_info.state + info->stateOffset;
+ q->streamState = scratch->core_info.state + info->stateOffset;
q->offset = scratch->core_info.buf_offset;
q->buffer = scratch->core_info.buf;
q->length = scratch->core_info.len;
q->history = scratch->core_info.hbuf;
q->hlength = scratch->core_info.hlen;
- q->cb = roseNfaAdaptor;
- q->context = scratch;
+ q->cb = roseNfaAdaptor;
+ q->context = scratch;
q->report_current = 0;
DEBUG_PRINTF("qi=%u, offset=%llu, fullState=%u, streamState=%u, "
@@ -95,7 +95,7 @@ void initQueue(struct mq *q, u32 qi, const struct RoseEngine *t,
static really_inline
void initRoseQueue(const struct RoseEngine *t, u32 qi,
const struct LeftNfaInfo *left,
- struct hs_scratch *scratch) {
+ struct hs_scratch *scratch) {
struct mq *q = scratch->queues + qi;
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
q->nfa = getNfaByInfo(t, info);
@@ -110,7 +110,7 @@ void initRoseQueue(const struct RoseEngine *t, u32 qi,
if (left->transient) {
q->streamState = (char *)scratch->tstate + info->stateOffset;
} else {
- q->streamState = scratch->core_info.state + info->stateOffset;
+ q->streamState = scratch->core_info.state + info->stateOffset;
}
q->offset = scratch->core_info.buf_offset;
@@ -142,7 +142,7 @@ void loadStreamState(const struct NFA *nfa, struct mq *q, s64a loc) {
}
static really_inline
-void storeRoseDelay(const struct RoseEngine *t, char *state,
+void storeRoseDelay(const struct RoseEngine *t, char *state,
const struct LeftNfaInfo *left, u32 loc) {
u32 di = left->lagIndex;
if (di == ROSE_OFFSET_INVALID) {
@@ -157,7 +157,7 @@ void storeRoseDelay(const struct RoseEngine *t, char *state,
}
static really_inline
-void setAsZombie(const struct RoseEngine *t, char *state,
+void setAsZombie(const struct RoseEngine *t, char *state,
const struct LeftNfaInfo *left) {
u32 di = left->lagIndex;
assert(di != ROSE_OFFSET_INVALID);
@@ -172,7 +172,7 @@ void setAsZombie(const struct RoseEngine *t, char *state,
/* loadRoseDelay MUST NOT be called on the first stream write as it is only
* initialized for running nfas on stream boundaries */
static really_inline
-u32 loadRoseDelay(const struct RoseEngine *t, const char *state,
+u32 loadRoseDelay(const struct RoseEngine *t, const char *state,
const struct LeftNfaInfo *left) {
u32 di = left->lagIndex;
if (di == ROSE_OFFSET_INVALID) {
@@ -186,7 +186,7 @@ u32 loadRoseDelay(const struct RoseEngine *t, const char *state,
}
static really_inline
-char isZombie(const struct RoseEngine *t, const char *state,
+char isZombie(const struct RoseEngine *t, const char *state,
const struct LeftNfaInfo *left) {
u32 di = left->lagIndex;
assert(di != ROSE_OFFSET_INVALID);
@@ -199,46 +199,46 @@ char isZombie(const struct RoseEngine *t, const char *state,
return leftfixDelay[di] == OWB_ZOMBIE_ALWAYS_YES;
}
-hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a end);
+hwlmcb_rv_t flushQueuedLiterals_i(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a end);
static really_inline
-hwlmcb_rv_t flushQueuedLiterals(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a end) {
- struct RoseContext *tctxt = &scratch->tctxt;
-
+hwlmcb_rv_t flushQueuedLiterals(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a end) {
+ struct RoseContext *tctxt = &scratch->tctxt;
+
if (tctxt->delayLastEndOffset == end) {
DEBUG_PRINTF("no progress, no flush\n");
return HWLM_CONTINUE_MATCHING;
}
- if (!tctxt->filledDelayedSlots && !scratch->al_log_sum) {
+ if (!tctxt->filledDelayedSlots && !scratch->al_log_sum) {
tctxt->delayLastEndOffset = end;
return HWLM_CONTINUE_MATCHING;
}
- return flushQueuedLiterals_i(t, scratch, end);
+ return flushQueuedLiterals_i(t, scratch, end);
}
static really_inline
-hwlmcb_rv_t cleanUpDelayed(const struct RoseEngine *t,
- struct hs_scratch *scratch, size_t length,
- u64a offset) {
- if (can_stop_matching(scratch)) {
+hwlmcb_rv_t cleanUpDelayed(const struct RoseEngine *t,
+ struct hs_scratch *scratch, size_t length,
+ u64a offset) {
+ if (can_stop_matching(scratch)) {
return HWLM_TERMINATE_MATCHING;
}
- if (flushQueuedLiterals(t, scratch, length + offset)
+ if (flushQueuedLiterals(t, scratch, length + offset)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
- struct RoseContext *tctxt = &scratch->tctxt;
+ struct RoseContext *tctxt = &scratch->tctxt;
if (tctxt->filledDelayedSlots) {
DEBUG_PRINTF("dirty\n");
- scratch->core_info.status |= STATUS_DELAY_DIRTY;
+ scratch->core_info.status |= STATUS_DELAY_DIRTY;
} else {
- scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
+ scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
}
tctxt->filledDelayedSlots = 0;
@@ -248,13 +248,13 @@ hwlmcb_rv_t cleanUpDelayed(const struct RoseEngine *t,
}
static rose_inline
-void roseFlushLastByteHistory(const struct RoseEngine *t,
- struct hs_scratch *scratch, u64a currEnd) {
+void roseFlushLastByteHistory(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u64a currEnd) {
if (!t->lastByteHistoryIterOffset) {
return;
}
- struct RoseContext *tctxt = &scratch->tctxt;
+ struct RoseContext *tctxt = &scratch->tctxt;
struct core_info *ci = &scratch->core_info;
/* currEnd is last byte of string + 1 */
@@ -266,118 +266,118 @@ void roseFlushLastByteHistory(const struct RoseEngine *t,
DEBUG_PRINTF("flushing\n");
- const struct mmbit_sparse_iter *it =
- getByOffset(t, t->lastByteHistoryIterOffset);
- assert(ISALIGNED(it));
-
+ const struct mmbit_sparse_iter *it =
+ getByOffset(t, t->lastByteHistoryIterOffset);
+ assert(ISALIGNED(it));
+
const u32 numStates = t->rolesWithStateCount;
- void *role_state = getRoleState(scratch->core_info.state);
+ void *role_state = getRoleState(scratch->core_info.state);
+
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+
+ mmbit_sparse_iter_unset(role_state, numStates, it, si_state);
+}
+
+static rose_inline
+int roseHasInFlightMatches(const struct RoseEngine *t, char *state,
+ const struct hs_scratch *scratch) {
+ if (scratch->al_log_sum) {
+ DEBUG_PRINTF("anchored literals in log\n");
+ return 1;
+ }
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
-
- mmbit_sparse_iter_unset(role_state, numStates, it, si_state);
+ if (scratch->tctxt.filledDelayedSlots) {
+ DEBUG_PRINTF("delayed literal\n");
+ return 1;
+ }
+
+ if (mmbit_any(getRoleState(state), t->rolesWithStateCount)) {
+ DEBUG_PRINTF("role state is set\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static rose_inline
+hwlmcb_rv_t roseHaltIfExhausted(const struct RoseEngine *t,
+ struct hs_scratch *scratch) {
+ struct core_info *ci = &scratch->core_info;
+ if (isAllExhausted(t, ci->exhaustionVector)) {
+ ci->status |= STATUS_EXHAUSTED;
+ scratch->tctxt.groups = 0;
+ DEBUG_PRINTF("all exhausted, termination requested\n");
+ return HWLM_TERMINATE_MATCHING;
+ }
+
+ return HWLM_CONTINUE_MATCHING;
+}
+
+static really_inline
+hwlmcb_rv_t ensureQueueFlushed_i(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 qi, s64a loc,
+ char is_mpv, char in_catchup) {
+ struct RoseContext *tctxt = &scratch->tctxt;
+ u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
+ struct fatbit *activeQueues = scratch->aqa;
+ u32 aaCount = t->activeArrayCount;
+ u32 qCount = t->queueCount;
+
+ struct mq *q = &scratch->queues[qi];
+ DEBUG_PRINTF("qcl %lld, loc: %lld, min (non mpv) match offset: %llu\n",
+ q_cur_loc(q), loc, tctxt->minNonMpvMatchOffset);
+ if (q_cur_loc(q) == loc) {
+ /* too many tops enqueued at the one spot; need to flatten this queue.
+ * We can use the full catchups as it will short circuit as we are
+ * already at this location. It also saves waking everybody up */
+ pushQueueNoMerge(q, MQE_END, loc);
+ nfaQueueExec(q->nfa, q, loc);
+ q->cur = q->end = 0;
+ pushQueueAt(q, 0, MQE_START, loc);
+ } else if (!in_catchup) {
+ if (is_mpv) {
+ tctxt->next_mpv_offset = 0; /* force us to catch the mpv */
+ if (loc + scratch->core_info.buf_offset
+ <= tctxt->minNonMpvMatchOffset) {
+ DEBUG_PRINTF("flushing chained\n");
+ if (roseCatchUpMPV(t, loc, scratch) ==
+ HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ goto done_queue_empty;
+ }
+ }
+
+ if (roseCatchUpTo(t, scratch, loc + scratch->core_info.buf_offset) ==
+ HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ } else {
+ /* we must be a chained nfa */
+ assert(is_mpv);
+ DEBUG_PRINTF("flushing chained\n");
+ tctxt->next_mpv_offset = 0; /* force us to catch the mpv */
+ if (roseCatchUpMPV(t, loc, scratch) == HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ }
+done_queue_empty:
+ if (!mmbit_set(aa, aaCount, qi)) {
+ initQueue(q, qi, t, scratch);
+ nfaQueueInitState(q->nfa, q);
+ pushQueueAt(q, 0, MQE_START, loc);
+ fatbit_set(activeQueues, qCount, qi);
+ }
+
+ assert(!isQueueFull(q));
+
+ return roseHaltIfExhausted(t, scratch);
+}
+
+static rose_inline
+hwlmcb_rv_t ensureQueueFlushed(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 qi, s64a loc) {
+ return ensureQueueFlushed_i(t, scratch, qi, loc, 0, 0);
}
-static rose_inline
-int roseHasInFlightMatches(const struct RoseEngine *t, char *state,
- const struct hs_scratch *scratch) {
- if (scratch->al_log_sum) {
- DEBUG_PRINTF("anchored literals in log\n");
- return 1;
- }
-
- if (scratch->tctxt.filledDelayedSlots) {
- DEBUG_PRINTF("delayed literal\n");
- return 1;
- }
-
- if (mmbit_any(getRoleState(state), t->rolesWithStateCount)) {
- DEBUG_PRINTF("role state is set\n");
- return 1;
- }
-
- return 0;
-}
-
-static rose_inline
-hwlmcb_rv_t roseHaltIfExhausted(const struct RoseEngine *t,
- struct hs_scratch *scratch) {
- struct core_info *ci = &scratch->core_info;
- if (isAllExhausted(t, ci->exhaustionVector)) {
- ci->status |= STATUS_EXHAUSTED;
- scratch->tctxt.groups = 0;
- DEBUG_PRINTF("all exhausted, termination requested\n");
- return HWLM_TERMINATE_MATCHING;
- }
-
- return HWLM_CONTINUE_MATCHING;
-}
-
-static really_inline
-hwlmcb_rv_t ensureQueueFlushed_i(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 qi, s64a loc,
- char is_mpv, char in_catchup) {
- struct RoseContext *tctxt = &scratch->tctxt;
- u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
- struct fatbit *activeQueues = scratch->aqa;
- u32 aaCount = t->activeArrayCount;
- u32 qCount = t->queueCount;
-
- struct mq *q = &scratch->queues[qi];
- DEBUG_PRINTF("qcl %lld, loc: %lld, min (non mpv) match offset: %llu\n",
- q_cur_loc(q), loc, tctxt->minNonMpvMatchOffset);
- if (q_cur_loc(q) == loc) {
- /* too many tops enqueued at the one spot; need to flatten this queue.
- * We can use the full catchups as it will short circuit as we are
- * already at this location. It also saves waking everybody up */
- pushQueueNoMerge(q, MQE_END, loc);
- nfaQueueExec(q->nfa, q, loc);
- q->cur = q->end = 0;
- pushQueueAt(q, 0, MQE_START, loc);
- } else if (!in_catchup) {
- if (is_mpv) {
- tctxt->next_mpv_offset = 0; /* force us to catch the mpv */
- if (loc + scratch->core_info.buf_offset
- <= tctxt->minNonMpvMatchOffset) {
- DEBUG_PRINTF("flushing chained\n");
- if (roseCatchUpMPV(t, loc, scratch) ==
- HWLM_TERMINATE_MATCHING) {
- return HWLM_TERMINATE_MATCHING;
- }
- goto done_queue_empty;
- }
- }
-
- if (roseCatchUpTo(t, scratch, loc + scratch->core_info.buf_offset) ==
- HWLM_TERMINATE_MATCHING) {
- return HWLM_TERMINATE_MATCHING;
- }
- } else {
- /* we must be a chained nfa */
- assert(is_mpv);
- DEBUG_PRINTF("flushing chained\n");
- tctxt->next_mpv_offset = 0; /* force us to catch the mpv */
- if (roseCatchUpMPV(t, loc, scratch) == HWLM_TERMINATE_MATCHING) {
- return HWLM_TERMINATE_MATCHING;
- }
- }
-done_queue_empty:
- if (!mmbit_set(aa, aaCount, qi)) {
- initQueue(q, qi, t, scratch);
- nfaQueueInitState(q->nfa, q);
- pushQueueAt(q, 0, MQE_START, loc);
- fatbit_set(activeQueues, qCount, qi);
- }
-
- assert(!isQueueFull(q));
-
- return roseHaltIfExhausted(t, scratch);
-}
-
-static rose_inline
-hwlmcb_rv_t ensureQueueFlushed(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 qi, s64a loc) {
- return ensureQueueFlushed_i(t, scratch, qi, loc, 0, 0);
-}
-
#endif
diff --git a/contrib/libs/hyperscan/src/rose/program_runtime.c b/contrib/libs/hyperscan/src/rose/program_runtime.c
index d8aa8b2f8cd..ff5a5099c92 100644
--- a/contrib/libs/hyperscan/src/rose/program_runtime.c
+++ b/contrib/libs/hyperscan/src/rose/program_runtime.c
@@ -1,38 +1,38 @@
-/*
+/*
* Copyright (c) 2015-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose runtime: program interpreter.
- */
-
-#include "program_runtime.h"
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose runtime: program interpreter.
+ */
+
+#include "program_runtime.h"
+
#include "catchup.h"
#include "counting_miracle.h"
#include "infix.h"
@@ -1689,14 +1689,14 @@ int roseCheckMultipathShufti64(const struct hs_scratch *scratch,
}
static rose_inline
-int roseNfaEarliestSom(u64a start, UNUSED u64a end, UNUSED ReportID id,
- void *context) {
- assert(context);
- u64a *som = context;
- *som = MIN(*som, start);
- return MO_CONTINUE_MATCHING;
-}
-
+int roseNfaEarliestSom(u64a start, UNUSED u64a end, UNUSED ReportID id,
+ void *context) {
+ assert(context);
+ u64a *som = context;
+ *som = MIN(*som, start);
+ return MO_CONTINUE_MATCHING;
+}
+
static rose_inline
u64a roseGetHaigSom(const struct RoseEngine *t, struct hs_scratch *scratch,
const u32 qi, UNUSED const u32 leftfixLag) {
@@ -2148,9 +2148,9 @@ hwlmcb_rv_t checkPurelyNegatives(const struct RoseEngine *t,
#define PROGRAM_NEXT_INSTRUCTION_JUMP continue;
#endif
-hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 programOffset,
- u64a som, u64a end, u8 prog_flags) {
+hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 programOffset,
+ u64a som, u64a end, u8 prog_flags) {
DEBUG_PRINTF("program=%u, offsets [%llu,%llu], flags=%u\n", programOffset,
som, end, prog_flags);
@@ -3082,7 +3082,7 @@ hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
assert(0); // unreachable
return HWLM_CONTINUE_MATCHING;
-}
+}
#define L_PROGRAM_CASE(name) \
case ROSE_INSTR_##name: { \
diff --git a/contrib/libs/hyperscan/src/rose/program_runtime.h b/contrib/libs/hyperscan/src/rose/program_runtime.h
index aad2bb3666d..50bf202c6f8 100644
--- a/contrib/libs/hyperscan/src/rose/program_runtime.h
+++ b/contrib/libs/hyperscan/src/rose/program_runtime.h
@@ -1,61 +1,61 @@
-/*
+/*
* Copyright (c) 2015-2019, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose runtime: program interpreter.
- */
-
-#ifndef PROGRAM_RUNTIME_H
-#define PROGRAM_RUNTIME_H
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose runtime: program interpreter.
+ */
+
+#ifndef PROGRAM_RUNTIME_H
+#define PROGRAM_RUNTIME_H
+
#include "hwlm/hwlm.h" // for hwlmcb_rv_t
-#include "rose.h"
-#include "scratch.h"
-#include "ue2common.h"
-
-/*
- * Program context flags, which control the behaviour of some instructions at
- * based on runtime contexts (whether the program is triggered by the anchored
- * matcher, engine catchup, etc).
- */
-
-#define ROSE_PROG_FLAG_IN_ANCHORED 1
-#define ROSE_PROG_FLAG_IN_CATCHUP 2
-#define ROSE_PROG_FLAG_FROM_MPV 4
-#define ROSE_PROG_FLAG_SKIP_MPV_CATCHUP 8
-
-hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 programOffset,
- u64a som, u64a end, u8 prog_flags);
-
+#include "rose.h"
+#include "scratch.h"
+#include "ue2common.h"
+
+/*
+ * Program context flags, which control the behaviour of some instructions at
+ * based on runtime contexts (whether the program is triggered by the anchored
+ * matcher, engine catchup, etc).
+ */
+
+#define ROSE_PROG_FLAG_IN_ANCHORED 1
+#define ROSE_PROG_FLAG_IN_CATCHUP 2
+#define ROSE_PROG_FLAG_FROM_MPV 4
+#define ROSE_PROG_FLAG_SKIP_MPV_CATCHUP 8
+
+hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
+ struct hs_scratch *scratch, u32 programOffset,
+ u64a som, u64a end, u8 prog_flags);
+
hwlmcb_rv_t roseRunProgram_l(const struct RoseEngine *t,
- struct hs_scratch *scratch, u32 programOffset,
+ struct hs_scratch *scratch, u32 programOffset,
u64a som, u64a end, u8 prog_flags);
-
-#endif // PROGRAM_RUNTIME_H
+
+#endif // PROGRAM_RUNTIME_H
diff --git a/contrib/libs/hyperscan/src/rose/rose.h b/contrib/libs/hyperscan/src/rose/rose.h
index 4519b09de28..409b70028fc 100644
--- a/contrib/libs/hyperscan/src/rose/rose.h
+++ b/contrib/libs/hyperscan/src/rose/rose.h
@@ -31,27 +31,27 @@
#include "ue2common.h"
-struct RoseEngine;
-struct hs_scratch;
-
+struct RoseEngine;
+struct hs_scratch;
+
// Initialise state space for engine use.
-void roseInitState(const struct RoseEngine *t, char *state);
+void roseInitState(const struct RoseEngine *t, char *state);
-/* assumes core_info in scratch has been init to point to data */
-void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch);
+/* assumes core_info in scratch has been init to point to data */
+void roseBlockExec(const struct RoseEngine *t, struct hs_scratch *scratch);
/* assumes core_info in scratch has been init to point to data */
-void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch);
+void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch);
-void roseStreamEodExec(const struct RoseEngine *t, u64a offset,
- struct hs_scratch *scratch);
+void roseStreamEodExec(const struct RoseEngine *t, u64a offset,
+ struct hs_scratch *scratch);
-hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch);
+hwlmcb_rv_t roseCallback(size_t end, u32 id, struct hs_scratch *scratch);
-int roseReportAdaptor(u64a start, u64a end, ReportID id, void *context);
+int roseReportAdaptor(u64a start, u64a end, ReportID id, void *context);
-int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program,
- u64a stream_offset, struct hs_scratch *scratch);
+int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program,
+ u64a stream_offset, struct hs_scratch *scratch);
int roseRunFlushCombProgram(const struct RoseEngine *rose,
struct hs_scratch *scratch, u64a end);
diff --git a/contrib/libs/hyperscan/src/rose/rose_build.h b/contrib/libs/hyperscan/src/rose/rose_build.h
index 1640a660bda..ca3ba3696e7 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,10 +40,10 @@
#include "ue2common.h"
#include "rose_common.h"
#include "rose_in_graph.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/charreach.h"
-#include "util/flat_containers.h"
-#include "util/noncopyable.h"
+#include "util/flat_containers.h"
+#include "util/noncopyable.h"
#include "util/ue2string.h"
#include <memory>
@@ -64,7 +64,7 @@ struct raw_som_dfa;
class CharReach;
class NGHolder;
class ReportManager;
-class SmallWriteBuild;
+class SmallWriteBuild;
class SomSlotManager;
class RoseDedupeAux {
@@ -73,21 +73,21 @@ public:
/** \brief True if we can not establish that at most a single callback will
* be generated at a given offset from this set of reports. */
- virtual bool requiresDedupeSupport(const flat_set<ReportID> &reports)
+ virtual bool requiresDedupeSupport(const flat_set<ReportID> &reports)
const = 0;
};
/** \brief Abstract interface intended for callers from elsewhere in the tree,
* real underlying implementation is RoseBuildImpl in rose_build_impl.h. */
-class RoseBuild : noncopyable {
+class RoseBuild : noncopyable {
public:
virtual ~RoseBuild();
/** \brief Adds a single literal. */
virtual void add(bool anchored, bool eod, const ue2_literal &lit,
- const flat_set<ReportID> &ids) = 0;
+ const flat_set<ReportID> &ids) = 0;
- virtual bool addRose(const RoseInGraph &ig, bool prefilter) = 0;
+ virtual bool addRose(const RoseInGraph &ig, bool prefilter) = 0;
virtual bool addSombeRose(const RoseInGraph &ig) = 0;
virtual bool addOutfix(const NGHolder &h) = 0;
@@ -99,21 +99,21 @@ public:
/** \brief Returns true if we were able to add it as a mask. */
virtual bool add(bool anchored, const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports) = 0;
+ const flat_set<ReportID> &reports) = 0;
/** \brief Attempts to add the graph to the anchored acyclic table. Returns
* true on success. */
virtual bool addAnchoredAcyclic(const NGHolder &graph) = 0;
virtual bool validateMask(const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports,
+ const flat_set<ReportID> &reports,
bool anchored, bool eod) const = 0;
virtual void addMask(const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool anchored,
+ const flat_set<ReportID> &reports, bool anchored,
bool eod) = 0;
/** \brief Construct a runtime implementation. */
- virtual bytecode_ptr<RoseEngine> buildRose(u32 minWidth) = 0;
+ virtual bytecode_ptr<RoseEngine> buildRose(u32 minWidth) = 0;
virtual std::unique_ptr<RoseDedupeAux> generateDedupeAux() const = 0;
@@ -127,7 +127,7 @@ public:
// Construct a usable Rose builder.
std::unique_ptr<RoseBuild> makeRoseBuilder(ReportManager &rm,
SomSlotManager &ssm,
- SmallWriteBuild &smwr,
+ SmallWriteBuild &smwr,
const CompileContext &cc,
const BoundaryReports &boundary);
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_add.cpp b/contrib/libs/hyperscan/src/rose/rose_build_add.cpp
index b3fe94b5972..4929c95fce3 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_add.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_add.cpp
@@ -55,9 +55,9 @@
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
-#include "util/insertion_ordered.h"
+#include "util/insertion_ordered.h"
#include "util/make_unique.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include "util/order_check.h"
#include "util/report_manager.h"
#include "util/ue2string.h"
@@ -77,7 +77,7 @@ namespace ue2 {
/**
* \brief Data used by most of the construction code in this file.
*/
-struct RoseBuildData : noncopyable {
+struct RoseBuildData : noncopyable {
RoseBuildData(const RoseInGraph &ig_in, bool som_in)
: ig(ig_in), som(som_in) {}
@@ -86,7 +86,7 @@ struct RoseBuildData : noncopyable {
/** Edges we've transformed (in \ref transformAnchoredLiteralOverlap) which
* require ANCH history to prevent overlap. */
- unordered_set<RoseInEdge> anch_history_edges;
+ unordered_set<RoseInEdge> anch_history_edges;
/** True if we're tracking Start of Match. */
bool som;
@@ -111,7 +111,7 @@ RoseVertex createVertex(RoseBuildImpl *build, u32 literalId, u32 min_offset,
g[v].min_offset = min_offset;
g[v].max_offset = max_offset;
- DEBUG_PRINTF("insert vertex %zu into literal %u's vertex set\n", g[v].index,
+ DEBUG_PRINTF("insert vertex %zu into literal %u's vertex set\n", g[v].index,
literalId);
g[v].literals.insert(literalId);
build->literal_info[literalId].vertices.insert(v);
@@ -122,7 +122,7 @@ RoseVertex createVertex(RoseBuildImpl *build, u32 literalId, u32 min_offset,
RoseVertex createVertex(RoseBuildImpl *build, const RoseVertex parent,
u32 minBound, u32 maxBound, u32 literalId,
size_t literalLength,
- const flat_set<ReportID> &reports) {
+ const flat_set<ReportID> &reports) {
assert(parent != RoseGraph::null_vertex());
RoseGraph &g = build->g;
@@ -132,7 +132,7 @@ RoseVertex createVertex(RoseBuildImpl *build, const RoseVertex parent,
/* fill in report information */
g[v].reports.insert(reports.begin(), reports.end());
- RoseEdge e = add_edge(parent, v, g);
+ RoseEdge e = add_edge(parent, v, g);
DEBUG_PRINTF("adding edge (%u, %u) to parent\n", minBound, maxBound);
g[e].minBound = minBound;
@@ -159,10 +159,10 @@ RoseVertex createAnchoredVertex(RoseBuildImpl *build, u32 literalId,
RoseGraph &g = build->g;
RoseVertex v = createVertex(build, literalId, min_offset, max_offset);
- DEBUG_PRINTF("created anchored vertex %zu with lit id %u\n", g[v].index,
+ DEBUG_PRINTF("created anchored vertex %zu with lit id %u\n", g[v].index,
literalId);
- RoseEdge e = add_edge(build->anchored_root, v, g);
+ RoseEdge e = add_edge(build->anchored_root, v, g);
g[e].minBound = min_offset;
g[e].maxBound = max_offset;
@@ -173,7 +173,7 @@ static
RoseVertex duplicate(RoseBuildImpl *build, RoseVertex v) {
RoseGraph &g = build->g;
RoseVertex w = add_vertex(g[v], g);
- DEBUG_PRINTF("added vertex %zu\n", g[w].index);
+ DEBUG_PRINTF("added vertex %zu\n", g[w].index);
for (auto lit_id : g[w].literals) {
build->literal_info[lit_id].vertices.insert(w);
@@ -182,7 +182,7 @@ RoseVertex duplicate(RoseBuildImpl *build, RoseVertex v) {
for (const auto &e : in_edges_range(v, g)) {
RoseVertex s = source(e, g);
add_edge(s, w, g[e], g);
- DEBUG_PRINTF("added edge (%zu,%zu)\n", g[s].index, g[w].index);
+ DEBUG_PRINTF("added edge (%zu,%zu)\n", g[s].index, g[w].index);
}
return w;
@@ -191,7 +191,7 @@ RoseVertex duplicate(RoseBuildImpl *build, RoseVertex v) {
namespace {
struct created_key {
explicit created_key(const RoseInEdgeProps &trep)
- : prefix(trep.graph.get()), lag(trep.graph_lag) {
+ : prefix(trep.graph.get()), lag(trep.graph_lag) {
}
bool operator<(const created_key &b) const {
const created_key &a = *this;
@@ -218,7 +218,7 @@ RoseRoleHistory selectHistory(const RoseBuildImpl &tbi, const RoseBuildData &bd,
const bool has_bounds = g[e].minBound || (g[e].maxBound != ROSE_BOUND_INF);
DEBUG_PRINTF("edge %zu->%zu, bounds=[%u,%u], fixed_u=%d, prefix=%d\n",
- g[u].index, g[v].index, g[e].minBound, g[e].maxBound,
+ g[u].index, g[v].index, g[e].minBound, g[e].maxBound,
(int)g[u].fixedOffset(), (int)g[v].left);
if (g[v].left) {
@@ -277,8 +277,8 @@ void createVertices(RoseBuildImpl *tbi,
if (prefix_graph) {
g[w].left.graph = prefix_graph;
- if (edge_props.dfa) {
- g[w].left.dfa = edge_props.dfa;
+ if (edge_props.dfa) {
+ g[w].left.dfa = edge_props.dfa;
}
g[w].left.haig = edge_props.haig;
g[w].left.lag = prefix_lag;
@@ -296,19 +296,19 @@ void createVertices(RoseBuildImpl *tbi,
if (bd.som && !g[w].left.haig) {
/* no prefix - som based on literal start */
assert(!prefix_graph);
- g[w].som_adjust = tbi->literals.at(literalId).elength();
+ g[w].som_adjust = tbi->literals.at(literalId).elength();
DEBUG_PRINTF("set som_adjust to %u\n", g[w].som_adjust);
}
- DEBUG_PRINTF(" adding new vertex index=%zu\n", tbi->g[w].index);
+ DEBUG_PRINTF(" adding new vertex index=%zu\n", tbi->g[w].index);
vertex_map[iv].push_back(w);
} else {
w = created[key];
}
- RoseVertex p = pv.first;
+ RoseVertex p = pv.first;
- RoseEdge e = add_edge(p, w, g);
+ RoseEdge e = add_edge(p, w, g);
DEBUG_PRINTF("adding edge (%u,%u) to parent\n", edge_props.minBound,
edge_props.maxBound);
g[e].minBound = edge_props.minBound;
@@ -334,7 +334,7 @@ void createVertices(RoseBuildImpl *tbi,
u32 ghostId = tbi->literal_info[literalId].undelayed_id;
DEBUG_PRINTF("creating delay ghost vertex, id=%u\n", ghostId);
assert(ghostId != literalId);
- assert(tbi->literals.at(ghostId).delay == 0);
+ assert(tbi->literals.at(ghostId).delay == 0);
// Adjust offsets, removing delay.
u32 ghost_min = min_offset, ghost_max = max_offset;
@@ -346,7 +346,7 @@ void createVertices(RoseBuildImpl *tbi,
for (const auto &pv : parents) {
const RoseInEdgeProps &edge_props = bd.ig[pv.second];
- RoseEdge e = add_edge(pv.first, g_v, tbi->g);
+ RoseEdge e = add_edge(pv.first, g_v, tbi->g);
g[e].minBound = edge_props.minBound;
g[e].maxBound = edge_props.maxBound;
g[e].history = selectHistory(*tbi, bd, pv.second, e);
@@ -363,7 +363,7 @@ void createVertices(RoseBuildImpl *tbi,
/* ensure the holder does not accept any paths which do not end with lit */
static
void removeFalsePaths(NGHolder &g, const ue2_literal &lit) {
- DEBUG_PRINTF("strip '%s'\n", dumpString(lit).c_str());
+ DEBUG_PRINTF("strip '%s'\n", dumpString(lit).c_str());
set<NFAVertex> curr, next;
curr.insert(g.accept);
curr.insert(g.acceptEod);
@@ -371,7 +371,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) {
for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) {
next.clear();
for (auto curr_v : curr) {
- DEBUG_PRINTF("handling %zu\n", g[curr_v].index);
+ DEBUG_PRINTF("handling %zu\n", g[curr_v].index);
vector<NFAVertex> next_cand;
insert(&next_cand, next_cand.end(),
inv_adjacent_vertices(curr_v, g));
@@ -389,7 +389,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) {
const CharReach &cr = g[v].char_reach;
if (!overlaps(*it, cr)) {
- DEBUG_PRINTF("false edge %zu\n", g[v].index);
+ DEBUG_PRINTF("false edge %zu\n", g[v].index);
continue;
}
@@ -397,7 +397,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) {
clone_in_edges(g, v, v2);
add_edge(v2, curr_v, g);
g[v2].char_reach &= *it;
- DEBUG_PRINTF("next <- %zu\n", g[v2].index);
+ DEBUG_PRINTF("next <- %zu\n", g[v2].index);
next.insert(v2);
}
}
@@ -406,7 +406,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) {
}
pruneUseless(g);
- clearReports(g);
+ clearReports(g);
assert(in_degree(g.accept, g) || in_degree(g.acceptEod, g) > 1);
assert(allMatchStatesHaveReports(g));
@@ -545,7 +545,7 @@ void findRoseLiteralMask(const NGHolder &h, const u32 lag, vector<u8> &msk,
next.clear();
CharReach cr;
for (auto v : curr) {
- DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index,
+ DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index,
describeClass(h[v].char_reach).c_str());
cr |= h[v].char_reach;
insert(&next, inv_adjacent_vertices(v, h));
@@ -640,96 +640,96 @@ floating:
}
static
-unique_ptr<NGHolder> makeRoseEodPrefix(const NGHolder &h, RoseBuildImpl &build,
- map<flat_set<ReportID>, ReportID> &remap) {
+unique_ptr<NGHolder> makeRoseEodPrefix(const NGHolder &h, RoseBuildImpl &build,
+ map<flat_set<ReportID>, ReportID> &remap) {
assert(generates_callbacks(h));
- assert(!in_degree(h.accept, h));
- auto gg = cloneHolder(h);
- NGHolder &g = *gg;
- g.kind = is_triggered(h) ? NFA_INFIX : NFA_PREFIX;
+ assert(!in_degree(h.accept, h));
+ auto gg = cloneHolder(h);
+ NGHolder &g = *gg;
+ g.kind = is_triggered(h) ? NFA_INFIX : NFA_PREFIX;
// Move acceptEod edges over to accept.
vector<NFAEdge> dead;
- for (const auto &e : in_edges_range(g.acceptEod, g)) {
- NFAVertex u = source(e, g);
- if (u == g.accept) {
+ for (const auto &e : in_edges_range(g.acceptEod, g)) {
+ NFAVertex u = source(e, g);
+ if (u == g.accept) {
continue;
}
- add_edge_if_not_present(u, g.accept, g);
+ add_edge_if_not_present(u, g.accept, g);
dead.push_back(e);
-
- if (!contains(remap, g[u].reports)) {
- remap[g[u].reports] = build.getNewNfaReport();
- }
-
- g[u].reports = { remap[g[u].reports] };
+
+ if (!contains(remap, g[u].reports)) {
+ remap[g[u].reports] = build.getNewNfaReport();
+ }
+
+ g[u].reports = { remap[g[u].reports] };
}
- remove_edges(dead, g);
- return gg;
+ remove_edges(dead, g);
+ return gg;
+}
+
+static
+u32 getEodEventID(RoseBuildImpl &build) {
+ // Allocate the EOD event if it hasn't been already.
+ if (build.eod_event_literal_id == MO_INVALID_IDX) {
+ build.eod_event_literal_id = build.getLiteralId({}, 0, ROSE_EVENT);
+ }
+
+ return build.eod_event_literal_id;
+}
+
+static
+void makeEodEventLeftfix(RoseBuildImpl &build, RoseVertex u,
+ const NGHolder &h) {
+ assert(!build.isInETable(u));
+
+ RoseGraph &g = build.g;
+ map<flat_set<ReportID>, ReportID> report_remap;
+ shared_ptr<NGHolder> eod_leftfix
+ = makeRoseEodPrefix(h, build, report_remap);
+
+ u32 eod_event = getEodEventID(build);
+
+ for (const auto &report_mapping : report_remap) {
+ RoseVertex v = add_vertex(g);
+ g[v].literals.insert(eod_event);
+ build.literal_info[eod_event].vertices.insert(v);
+
+ g[v].left.graph = eod_leftfix;
+ g[v].left.leftfix_report = report_mapping.second;
+ g[v].left.lag = 0;
+ RoseEdge e1 = add_edge(u, v, g);
+ g[e1].minBound = 0;
+ g[e1].maxBound = ROSE_BOUND_INF;
+ g[v].min_offset = add_rose_depth(g[u].min_offset,
+ findMinWidth(*g[v].left.graph));
+ g[v].max_offset = ROSE_BOUND_INF;
+
+ depth max_width = findMaxWidth(*g[v].left.graph);
+ if (u != build.root && max_width.is_finite()
+ && (!build.isAnyStart(u) || isPureAnchored(*g[v].left.graph))) {
+ g[e1].maxBound = max_width;
+ g[v].max_offset = add_rose_depth(g[u].max_offset, max_width);
+ }
+
+ g[e1].history = ROSE_ROLE_HISTORY_NONE; // handled by prefix
+ RoseVertex w = add_vertex(g);
+ g[w].eod_accept = true;
+ g[w].reports = report_mapping.first;
+ g[w].min_offset = g[v].min_offset;
+ g[w].max_offset = g[v].max_offset;
+ RoseEdge e = add_edge(v, w, g);
+ g[e].minBound = 0;
+ g[e].maxBound = 0;
+ /* No need to set history as the event is only delivered at the last
+ * byte anyway - no need to invalidate stale entries. */
+ g[e].history = ROSE_ROLE_HISTORY_NONE;
+ DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
+ }
}
static
-u32 getEodEventID(RoseBuildImpl &build) {
- // Allocate the EOD event if it hasn't been already.
- if (build.eod_event_literal_id == MO_INVALID_IDX) {
- build.eod_event_literal_id = build.getLiteralId({}, 0, ROSE_EVENT);
- }
-
- return build.eod_event_literal_id;
-}
-
-static
-void makeEodEventLeftfix(RoseBuildImpl &build, RoseVertex u,
- const NGHolder &h) {
- assert(!build.isInETable(u));
-
- RoseGraph &g = build.g;
- map<flat_set<ReportID>, ReportID> report_remap;
- shared_ptr<NGHolder> eod_leftfix
- = makeRoseEodPrefix(h, build, report_remap);
-
- u32 eod_event = getEodEventID(build);
-
- for (const auto &report_mapping : report_remap) {
- RoseVertex v = add_vertex(g);
- g[v].literals.insert(eod_event);
- build.literal_info[eod_event].vertices.insert(v);
-
- g[v].left.graph = eod_leftfix;
- g[v].left.leftfix_report = report_mapping.second;
- g[v].left.lag = 0;
- RoseEdge e1 = add_edge(u, v, g);
- g[e1].minBound = 0;
- g[e1].maxBound = ROSE_BOUND_INF;
- g[v].min_offset = add_rose_depth(g[u].min_offset,
- findMinWidth(*g[v].left.graph));
- g[v].max_offset = ROSE_BOUND_INF;
-
- depth max_width = findMaxWidth(*g[v].left.graph);
- if (u != build.root && max_width.is_finite()
- && (!build.isAnyStart(u) || isPureAnchored(*g[v].left.graph))) {
- g[e1].maxBound = max_width;
- g[v].max_offset = add_rose_depth(g[u].max_offset, max_width);
- }
-
- g[e1].history = ROSE_ROLE_HISTORY_NONE; // handled by prefix
- RoseVertex w = add_vertex(g);
- g[w].eod_accept = true;
- g[w].reports = report_mapping.first;
- g[w].min_offset = g[v].min_offset;
- g[w].max_offset = g[v].max_offset;
- RoseEdge e = add_edge(v, w, g);
- g[e].minBound = 0;
- g[e].maxBound = 0;
- /* No need to set history as the event is only delivered at the last
- * byte anyway - no need to invalidate stale entries. */
- g[e].history = ROSE_ROLE_HISTORY_NONE;
- DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
- }
-}
-
-static
void doRoseAcceptVertex(RoseBuildImpl *tbi,
const vector<pair<RoseVertex, RoseInEdge> > &parents,
RoseInVertex iv, const RoseBuildData &bd) {
@@ -742,22 +742,22 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi,
RoseVertex u = pv.first;
const RoseInEdgeProps &edge_props = bd.ig[pv.second];
- /* We need to duplicate the parent vertices if:
- *
- * 1) It already has a suffix, etc as we are going to add the specified
- * suffix, etc to the parents and we do not want to overwrite the
- * existing information.
- *
- * 2) We are making the an EOD accept and the vertex already has other
- * out-edges - The LAST_BYTE history used for EOD accepts is
- * incompatible with normal successors. As accepts are processed last we
- * do not need to worry about other normal successors being added later.
- */
+ /* We need to duplicate the parent vertices if:
+ *
+ * 1) It already has a suffix, etc as we are going to add the specified
+ * suffix, etc to the parents and we do not want to overwrite the
+ * existing information.
+ *
+ * 2) We are making the an EOD accept and the vertex already has other
+ * out-edges - The LAST_BYTE history used for EOD accepts is
+ * incompatible with normal successors. As accepts are processed last we
+ * do not need to worry about other normal successors being added later.
+ */
if (g[u].suffix || !g[u].reports.empty()
- || (ig[iv].type == RIV_ACCEPT_EOD && out_degree(u, g)
- && !edge_props.graph)
+ || (ig[iv].type == RIV_ACCEPT_EOD && out_degree(u, g)
+ && !edge_props.graph)
|| (!isLeafNode(u, g) && !tbi->isAnyStart(u))) {
- DEBUG_PRINTF("duplicating for parent %zu\n", g[u].index);
+ DEBUG_PRINTF("duplicating for parent %zu\n", g[u].index);
assert(!tbi->isAnyStart(u));
u = duplicate(tbi, u);
g[u].suffix.reset();
@@ -767,56 +767,56 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi,
assert(!g[u].suffix);
if (ig[iv].type == RIV_ACCEPT) {
assert(!tbi->isAnyStart(u));
- if (edge_props.dfa) {
- DEBUG_PRINTF("adding early dfa suffix to i%zu\n", g[u].index);
- g[u].suffix.rdfa = edge_props.dfa;
+ if (edge_props.dfa) {
+ DEBUG_PRINTF("adding early dfa suffix to i%zu\n", g[u].index);
+ g[u].suffix.rdfa = edge_props.dfa;
g[u].suffix.dfa_min_width = findMinWidth(*edge_props.graph);
g[u].suffix.dfa_max_width = findMaxWidth(*edge_props.graph);
} else if (edge_props.graph) {
- DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index);
+ DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index);
g[u].suffix.graph = edge_props.graph;
assert(g[u].suffix.graph->kind == NFA_SUFFIX);
/* TODO: set dfa_(min|max)_width */
} else if (edge_props.haig) {
- DEBUG_PRINTF("adding suffaig to i%zu\n", g[u].index);
+ DEBUG_PRINTF("adding suffaig to i%zu\n", g[u].index);
g[u].suffix.haig = edge_props.haig;
} else {
- DEBUG_PRINTF("adding boring accept to i%zu\n", g[u].index);
+ DEBUG_PRINTF("adding boring accept to i%zu\n", g[u].index);
assert(!g[u].eod_accept);
g[u].reports = ig[iv].reports;
}
} else {
assert(ig[iv].type == RIV_ACCEPT_EOD);
- assert(!edge_props.haig);
-
- if (!edge_props.graph) {
- RoseVertex w = add_vertex(g);
- g[w].eod_accept = true;
- g[w].reports = ig[iv].reports;
- g[w].min_offset = g[u].min_offset;
- g[w].max_offset = g[u].max_offset;
- RoseEdge e = add_edge(u, w, g);
- g[e].minBound = 0;
- g[e].maxBound = 0;
- g[e].history = ROSE_ROLE_HISTORY_LAST_BYTE;
- DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
- continue;
- }
-
- const NGHolder &h = *edge_props.graph;
- assert(!in_degree(h.accept, h));
- assert(generates_callbacks(h));
-
- if (tbi->isInETable(u)) {
- assert(h.kind == NFA_SUFFIX);
+ assert(!edge_props.haig);
+
+ if (!edge_props.graph) {
+ RoseVertex w = add_vertex(g);
+ g[w].eod_accept = true;
+ g[w].reports = ig[iv].reports;
+ g[w].min_offset = g[u].min_offset;
+ g[w].max_offset = g[u].max_offset;
+ RoseEdge e = add_edge(u, w, g);
+ g[e].minBound = 0;
+ g[e].maxBound = 0;
+ g[e].history = ROSE_ROLE_HISTORY_LAST_BYTE;
+ DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
+ continue;
+ }
+
+ const NGHolder &h = *edge_props.graph;
+ assert(!in_degree(h.accept, h));
+ assert(generates_callbacks(h));
+
+ if (tbi->isInETable(u)) {
+ assert(h.kind == NFA_SUFFIX);
assert(!tbi->isAnyStart(u));
/* etable can't/shouldn't use eod event */
- DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index);
+ DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index);
g[u].suffix.graph = edge_props.graph;
continue;
}
- makeEodEventLeftfix(*tbi, u, h);
+ makeEodEventLeftfix(*tbi, u, h);
}
}
}
@@ -917,8 +917,8 @@ bool suitableForEod(const RoseInGraph &ig, vector<RoseInVertex> topo,
ENSURE_AT_LEAST(&v_depth, (u32)max_width);
}
- if (v_depth == ROSE_BOUND_INF
- || v_depth > cc.grey.maxHistoryAvailable) {
+ if (v_depth == ROSE_BOUND_INF
+ || v_depth > cc.grey.maxHistoryAvailable) {
DEBUG_PRINTF("not suitable for eod table %u\n", v_depth);
return false;
}
@@ -932,13 +932,13 @@ bool suitableForEod(const RoseInGraph &ig, vector<RoseInVertex> topo,
}
static
-void shift_accepts_to_end(const RoseInGraph &ig,
- vector<RoseInVertex> &topo_order) {
- stable_partition(begin(topo_order), end(topo_order),
- [&](RoseInVertex v){ return !is_any_accept(v, ig); });
-}
-
-static
+void shift_accepts_to_end(const RoseInGraph &ig,
+ vector<RoseInVertex> &topo_order) {
+ stable_partition(begin(topo_order), end(topo_order),
+ [&](RoseInVertex v){ return !is_any_accept(v, ig); });
+}
+
+static
void populateRoseGraph(RoseBuildImpl *tbi, RoseBuildData &bd) {
const RoseInGraph &ig = bd.ig;
@@ -950,7 +950,7 @@ void populateRoseGraph(RoseBuildImpl *tbi, RoseBuildData &bd) {
map<RoseInVertex, vector<RoseVertex> > vertex_map;
vector<RoseInVertex> v_order = topo_order(ig);
- shift_accepts_to_end(ig, v_order);
+ shift_accepts_to_end(ig, v_order);
u32 eod_space_required;
bool use_eod_table = suitableForEod(ig, v_order, &eod_space_required,
@@ -963,7 +963,7 @@ void populateRoseGraph(RoseBuildImpl *tbi, RoseBuildData &bd) {
|| ig[v_order.front()].type == RIV_ANCHORED_START);
for (RoseInVertex iv : v_order) {
- DEBUG_PRINTF("vertex %zu\n", ig[iv].index);
+ DEBUG_PRINTF("vertex %zu\n", ig[iv].index);
if (ig[iv].type == RIV_START) {
DEBUG_PRINTF("is root\n");
@@ -982,7 +982,7 @@ void populateRoseGraph(RoseBuildImpl *tbi, RoseBuildData &bd) {
const vector<RoseVertex> &images = vertex_map[u];
// We should have no dupes.
- assert(set<RoseVertex>(images.begin(), images.end()).size()
+ assert(set<RoseVertex>(images.begin(), images.end()).size()
== images.size());
for (auto v_image : images) {
@@ -1032,8 +1032,8 @@ bool empty(const GraphT &g) {
}
static
-bool canImplementGraph(NGHolder &h, bool prefilter, const ReportManager &rm,
- const CompileContext &cc) {
+bool canImplementGraph(NGHolder &h, bool prefilter, const ReportManager &rm,
+ const CompileContext &cc) {
if (isImplementableNFA(h, &rm, cc)) {
return true;
}
@@ -1106,7 +1106,7 @@ u32 maxAvailableDelay(const ue2_literal &pred_key, const ue2_literal &lit_key) {
}
static
-u32 findMaxSafeDelay(const RoseInGraph &ig, RoseInVertex u, RoseInVertex v) {
+u32 findMaxSafeDelay(const RoseInGraph &ig, RoseInVertex u, RoseInVertex v) {
// First, check the overlap constraints on (u,v).
size_t max_delay;
if (ig[v].type == RIV_LITERAL) {
@@ -1504,10 +1504,10 @@ bool validateKinds(const RoseInGraph &g) {
}
#endif
-bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
+bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
DEBUG_PRINTF("trying to rose\n");
assert(validateKinds(ig));
- assert(hasCorrectlyNumberedVertices(ig));
+ assert(hasCorrectlyNumberedVertices(ig));
if (::ue2::empty(ig)) {
assert(0);
@@ -1523,38 +1523,38 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
transformAnchoredLiteralOverlap(in, bd, cc);
transformSuffixDelay(in, cc);
- renumber_vertices(in);
- assert(validateKinds(in));
+ renumber_vertices(in);
+ assert(validateKinds(in));
- insertion_ordered_map<NGHolder *, vector<RoseInEdge>> graphs;
+ insertion_ordered_map<NGHolder *, vector<RoseInEdge>> graphs;
for (const auto &e : edges_range(in)) {
if (!in[e].graph) {
- assert(!in[e].dfa);
- assert(!in[e].haig);
+ assert(!in[e].dfa);
+ assert(!in[e].haig);
continue; // no graph
}
- if (in[e].haig || in[e].dfa) {
- /* Early DFAs/Haigs are always implementable (we've already built
- * the raw DFA). */
+ if (in[e].haig || in[e].dfa) {
+ /* Early DFAs/Haigs are always implementable (we've already built
+ * the raw DFA). */
continue;
}
NGHolder *h = in[e].graph.get();
-
- assert(isCorrectlyTopped(*h));
+
+ assert(isCorrectlyTopped(*h));
graphs[h].push_back(e);
}
vector<RoseInEdge> graph_edges;
- for (const auto &m : graphs) {
- NGHolder *h = m.first;
- if (!canImplementGraph(*h, prefilter, rm, cc)) {
+ for (const auto &m : graphs) {
+ NGHolder *h = m.first;
+ if (!canImplementGraph(*h, prefilter, rm, cc)) {
return false;
}
- insert(&graph_edges, graph_edges.end(), m.second);
+ insert(&graph_edges, graph_edges.end(), m.second);
}
/* we are now past the point of no return. We can start making irreversible
@@ -1569,7 +1569,7 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
if (!generates_callbacks(whatRoseIsThis(in, e))
&& in[target(e, in)].type != RIV_ACCEPT_EOD) {
- set_report(h, getNewNfaReport());
+ set_report(h, getNewNfaReport());
}
}
@@ -1612,7 +1612,7 @@ bool roseCheckRose(const RoseInGraph &ig, bool prefilter,
return false;
}
- vector<NGHolder *> graphs;
+ vector<NGHolder *> graphs;
for (const auto &e : edges_range(ig)) {
if (!ig[e].graph) {
@@ -1624,11 +1624,11 @@ bool roseCheckRose(const RoseInGraph &ig, bool prefilter,
continue;
}
- graphs.push_back(ig[e].graph.get());
+ graphs.push_back(ig[e].graph.get());
}
- for (const auto &g : graphs) {
- if (!canImplementGraph(*g, prefilter, rm, cc)) {
+ for (const auto &g : graphs) {
+ if (!canImplementGraph(*g, prefilter, rm, cc)) {
return false;
}
}
@@ -1637,7 +1637,7 @@ bool roseCheckRose(const RoseInGraph &ig, bool prefilter,
}
void RoseBuildImpl::add(bool anchored, bool eod, const ue2_literal &lit,
- const flat_set<ReportID> &reports) {
+ const flat_set<ReportID> &reports) {
assert(!reports.empty());
if (cc.grey.floodAsPuffette && !anchored && !eod && is_flood(lit) &&
@@ -1672,7 +1672,7 @@ static
u32 findMaxBAWidth(const NGHolder &h) {
// Must be bi-anchored: no out-edges from startDs (other than its
// self-loop), no in-edges to accept.
- if (out_degree(h.startDs, h) > 1 || in_degree(h.accept, h)) {
+ if (out_degree(h.startDs, h) > 1 || in_degree(h.accept, h)) {
return ROSE_BOUND_INF;
}
depth d = findMaxWidth(h);
@@ -1694,70 +1694,70 @@ void populateOutfixInfo(OutfixInfo &outfix, const NGHolder &h,
populateReverseAccelerationInfo(outfix.rev_info, h);
}
-static
-bool addEodOutfix(RoseBuildImpl &build, const NGHolder &h) {
- map<flat_set<ReportID>, ReportID> report_remap;
- shared_ptr<NGHolder> eod_leftfix
- = makeRoseEodPrefix(h, build, report_remap);
-
- bool nfa_ok = isImplementableNFA(h, &build.rm, build.cc);
-
- /* TODO: check if early dfa is possible */
-
- if (!nfa_ok) {
- DEBUG_PRINTF("could not build as NFA\n");
- return false;
- }
-
- u32 eod_event = getEodEventID(build);
-
- auto &g = build.g;
- for (const auto &report_mapping : report_remap) {
- RoseVertex v = add_vertex(g);
- g[v].literals.insert(eod_event);
- build.literal_info[eod_event].vertices.insert(v);
-
- g[v].left.graph = eod_leftfix;
- g[v].left.leftfix_report = report_mapping.second;
- g[v].left.lag = 0;
- RoseEdge e1 = add_edge(build.anchored_root, v, g);
- g[e1].minBound = 0;
- g[e1].maxBound = ROSE_BOUND_INF;
- g[v].min_offset = findMinWidth(*eod_leftfix);
- g[v].max_offset = ROSE_BOUND_INF;
-
- depth max_width = findMaxWidth(*g[v].left.graph);
- if (max_width.is_finite() && isPureAnchored(*eod_leftfix)) {
- g[e1].maxBound = max_width;
- g[v].max_offset = max_width;
- }
-
- g[e1].history = ROSE_ROLE_HISTORY_NONE; // handled by prefix
- RoseVertex w = add_vertex(g);
- g[w].eod_accept = true;
- g[w].reports = report_mapping.first;
- g[w].min_offset = g[v].min_offset;
- g[w].max_offset = g[v].max_offset;
- RoseEdge e = add_edge(v, w, g);
- g[e].minBound = 0;
- g[e].maxBound = 0;
- g[e].history = ROSE_ROLE_HISTORY_NONE;
- DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
- }
-
- return true;
-}
-
+static
+bool addEodOutfix(RoseBuildImpl &build, const NGHolder &h) {
+ map<flat_set<ReportID>, ReportID> report_remap;
+ shared_ptr<NGHolder> eod_leftfix
+ = makeRoseEodPrefix(h, build, report_remap);
+
+ bool nfa_ok = isImplementableNFA(h, &build.rm, build.cc);
+
+ /* TODO: check if early dfa is possible */
+
+ if (!nfa_ok) {
+ DEBUG_PRINTF("could not build as NFA\n");
+ return false;
+ }
+
+ u32 eod_event = getEodEventID(build);
+
+ auto &g = build.g;
+ for (const auto &report_mapping : report_remap) {
+ RoseVertex v = add_vertex(g);
+ g[v].literals.insert(eod_event);
+ build.literal_info[eod_event].vertices.insert(v);
+
+ g[v].left.graph = eod_leftfix;
+ g[v].left.leftfix_report = report_mapping.second;
+ g[v].left.lag = 0;
+ RoseEdge e1 = add_edge(build.anchored_root, v, g);
+ g[e1].minBound = 0;
+ g[e1].maxBound = ROSE_BOUND_INF;
+ g[v].min_offset = findMinWidth(*eod_leftfix);
+ g[v].max_offset = ROSE_BOUND_INF;
+
+ depth max_width = findMaxWidth(*g[v].left.graph);
+ if (max_width.is_finite() && isPureAnchored(*eod_leftfix)) {
+ g[e1].maxBound = max_width;
+ g[v].max_offset = max_width;
+ }
+
+ g[e1].history = ROSE_ROLE_HISTORY_NONE; // handled by prefix
+ RoseVertex w = add_vertex(g);
+ g[w].eod_accept = true;
+ g[w].reports = report_mapping.first;
+ g[w].min_offset = g[v].min_offset;
+ g[w].max_offset = g[v].max_offset;
+ RoseEdge e = add_edge(v, w, g);
+ g[e].minBound = 0;
+ g[e].maxBound = 0;
+ g[e].history = ROSE_ROLE_HISTORY_NONE;
+ DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index);
+ }
+
+ return true;
+}
+
bool RoseBuildImpl::addOutfix(const NGHolder &h) {
DEBUG_PRINTF("%zu vertices, %zu edges\n", num_vertices(h), num_edges(h));
- /* TODO: handle more than one report */
- if (!in_degree(h.accept, h)
- && all_reports(h).size() == 1
- && addEodOutfix(*this, h)) {
- return true;
- }
-
+ /* TODO: handle more than one report */
+ if (!in_degree(h.accept, h)
+ && all_reports(h).size() == 1
+ && addEodOutfix(*this, h)) {
+ return true;
+ }
+
const u32 nfa_states = isImplementableNFA(h, &rm, cc);
if (nfa_states) {
DEBUG_PRINTF("implementable as an NFA in %u states\n", nfa_states);
@@ -1802,12 +1802,12 @@ bool RoseBuildImpl::addOutfix(const NGHolder &h, const raw_som_dfa &haig) {
bool RoseBuildImpl::addOutfix(const raw_puff &rp) {
if (!mpv_outfix) {
- mpv_outfix = std::make_unique<OutfixInfo>(MpvProto());
+ mpv_outfix = std::make_unique<OutfixInfo>(MpvProto());
}
- auto *mpv = mpv_outfix->mpv();
- assert(mpv);
- mpv->puffettes.push_back(rp);
+ auto *mpv = mpv_outfix->mpv();
+ assert(mpv);
+ mpv->puffettes.push_back(rp);
mpv_outfix->maxBAWidth = ROSE_BOUND_INF; /* not ba */
mpv_outfix->minWidth = min(mpv_outfix->minWidth, depth(rp.repeats));
@@ -1827,12 +1827,12 @@ bool RoseBuildImpl::addOutfix(const raw_puff &rp) {
bool RoseBuildImpl::addChainTail(const raw_puff &rp, u32 *queue_out,
u32 *event_out) {
if (!mpv_outfix) {
- mpv_outfix = std::make_unique<OutfixInfo>(MpvProto());
+ mpv_outfix = std::make_unique<OutfixInfo>(MpvProto());
}
- auto *mpv = mpv_outfix->mpv();
- assert(mpv);
- mpv->triggered_puffettes.push_back(rp);
+ auto *mpv = mpv_outfix->mpv();
+ assert(mpv);
+ mpv->triggered_puffettes.push_back(rp);
mpv_outfix->maxBAWidth = ROSE_BOUND_INF; /* not ba */
mpv_outfix->minWidth = min(mpv_outfix->minWidth, depth(rp.repeats));
@@ -1844,7 +1844,7 @@ bool RoseBuildImpl::addChainTail(const raw_puff &rp, u32 *queue_out,
* the caller */
*queue_out = mpv_outfix->get_queue(qif);
- *event_out = MQE_TOP_FIRST + mpv->triggered_puffettes.size() - 1;
+ *event_out = MQE_TOP_FIRST + mpv->triggered_puffettes.size() - 1;
return true; /* failure is not yet an option */
}
@@ -1858,9 +1858,9 @@ bool prepAcceptForAddAnchoredNFA(RoseBuildImpl &tbi, const NGHolder &w,
map<ReportID, u32> &allocated_reports,
flat_set<u32> &added_lit_ids) {
const depth max_anchored_depth(tbi.cc.grey.maxAnchoredRegion);
- const size_t index = w[u].index;
- assert(index < vertexDepths.size());
- const DepthMinMax &d = vertexDepths.at(index);
+ const size_t index = w[u].index;
+ assert(index < vertexDepths.size());
+ const DepthMinMax &d = vertexDepths.at(index);
for (const auto &int_report : w[u].reports) {
assert(int_report != MO_INVALID_IDX);
@@ -1902,20 +1902,20 @@ void removeAddedLiterals(RoseBuildImpl &tbi, const flat_set<u32> &lit_ids) {
return;
}
- DEBUG_PRINTF("remove last %zu literals\n", lit_ids.size());
-
+ DEBUG_PRINTF("remove last %zu literals\n", lit_ids.size());
+
// lit_ids should be a contiguous range.
assert(lit_ids.size() == *lit_ids.rbegin() - *lit_ids.begin() + 1);
- assert(*lit_ids.rbegin() == tbi.literals.size() - 1);
+ assert(*lit_ids.rbegin() == tbi.literals.size() - 1);
- assert(all_of_in(lit_ids, [&](u32 lit_id) {
- return lit_id < tbi.literal_info.size() &&
- tbi.literals.at(lit_id).table == ROSE_ANCHORED &&
- tbi.literal_info[lit_id].vertices.empty();
- }));
+ assert(all_of_in(lit_ids, [&](u32 lit_id) {
+ return lit_id < tbi.literal_info.size() &&
+ tbi.literals.at(lit_id).table == ROSE_ANCHORED &&
+ tbi.literal_info[lit_id].vertices.empty();
+ }));
- tbi.literals.erase_back(lit_ids.size());
- assert(tbi.literals.size() == *lit_ids.begin());
+ tbi.literals.erase_back(lit_ids.size());
+ assert(tbi.literals.size() == *lit_ids.begin());
// lit_ids should be at the end of tbi.literal_info.
assert(tbi.literal_info.size() == *lit_ids.rbegin() + 1);
@@ -1923,7 +1923,7 @@ void removeAddedLiterals(RoseBuildImpl &tbi, const flat_set<u32> &lit_ids) {
}
bool RoseBuildImpl::addAnchoredAcyclic(const NGHolder &h) {
- auto vertexDepths = calcDepthsFrom(h, h.start);
+ auto vertexDepths = calcDepthsFrom(h, h.start);
map<NFAVertex, set<u32> > reportMap; /* NFAVertex -> literal ids */
map<u32, DepthMinMax> depthMap; /* literal id -> min/max depth */
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_add_internal.h b/contrib/libs/hyperscan/src/rose/rose_build_add_internal.h
index b119f3bc718..143f1dfa58f 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_add_internal.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_add_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,7 @@
#include "rose_graph.h"
#include "ue2common.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
namespace ue2 {
@@ -40,8 +40,8 @@ class RoseBuildImpl;
RoseVertex createVertex(RoseBuildImpl *build, const RoseVertex parent,
u32 minBound, u32 maxBound, u32 literalId,
size_t literalLength,
- const flat_set<ReportID> &reports);
+ const flat_set<ReportID> &reports);
} // namespace ue2
-#endif // ROSE_BUILD_ADD_INTERNAL_H
+#endif // ROSE_BUILD_ADD_INTERNAL_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_add_mask.cpp b/contrib/libs/hyperscan/src/rose/rose_build_add_mask.cpp
index 067b847dff9..0a7e44c370b 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_add_mask.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_add_mask.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -144,7 +144,7 @@ void findMaskLiteral(const vector<CharReach> &mask, bool streaming,
}
static
-bool initFmlCandidates(const CharReach &cr, vector<ue2_literal> &cand) {
+bool initFmlCandidates(const CharReach &cr, vector<ue2_literal> &cand) {
for (size_t i = cr.find_first(); i != cr.npos; i = cr.find_next(i)) {
char c = (char)i;
bool nocase = myisupper(c) && cr.test(mytolower(c));
@@ -152,25 +152,25 @@ bool initFmlCandidates(const CharReach &cr, vector<ue2_literal> &cand) {
continue;
}
- if (cand.size() >= MAX_MASK_LITS) {
+ if (cand.size() >= MAX_MASK_LITS) {
DEBUG_PRINTF("hit lit limit of %u\n", MAX_MASK_LITS);
return false;
}
- cand.emplace_back(c, nocase);
+ cand.emplace_back(c, nocase);
}
- assert(cand.size() <= MAX_MASK_LITS);
- return !cand.empty();
+ assert(cand.size() <= MAX_MASK_LITS);
+ return !cand.empty();
}
static
-bool expandFmlCandidates(const CharReach &cr, vector<ue2_literal> &curr,
- vector<ue2_literal> &cand) {
+bool expandFmlCandidates(const CharReach &cr, vector<ue2_literal> &curr,
+ vector<ue2_literal> &cand) {
DEBUG_PRINTF("expanding string with cr of %zu\n", cr.count());
- DEBUG_PRINTF(" current cand list size %zu\n", cand.size());
+ DEBUG_PRINTF(" current cand list size %zu\n", cand.size());
- curr.clear();
+ curr.clear();
for (size_t i = cr.find_first(); i != cr.npos; i = cr.find_next(i)) {
char c = (char)i;
@@ -179,14 +179,14 @@ bool expandFmlCandidates(const CharReach &cr, vector<ue2_literal> &curr,
continue;
}
- for (const auto &lit : cand) {
+ for (const auto &lit : cand) {
if (curr.size() >= MAX_MASK_LITS) {
DEBUG_PRINTF("hit lit limit of %u\n", MAX_MASK_LITS);
return false;
}
- curr.push_back(lit);
- curr.back().push_back(c, nocase);
+ curr.push_back(lit);
+ curr.back().push_back(c, nocase);
}
}
@@ -197,7 +197,7 @@ bool expandFmlCandidates(const CharReach &cr, vector<ue2_literal> &curr,
}
assert(curr.size() <= MAX_MASK_LITS);
- cand.swap(curr);
+ cand.swap(curr);
return true;
}
@@ -214,7 +214,7 @@ u32 scoreFmlCandidates(const vector<ue2_literal> &cand) {
u32 min_period = len;
for (const auto &lit : cand) {
- DEBUG_PRINTF("candidate: %s\n", dumpString(lit).c_str());
+ DEBUG_PRINTF("candidate: %s\n", dumpString(lit).c_str());
u32 period = lit.length() - maxStringSelfOverlap(lit);
min_period = min(min_period, period);
}
@@ -240,37 +240,37 @@ bool findMaskLiterals(const vector<CharReach> &mask, vector<ue2_literal> *lit,
*minBound = 0;
*length = 0;
- vector<ue2_literal> candidates, best_candidates, curr_candidates;
+ vector<ue2_literal> candidates, best_candidates, curr_candidates;
u32 best_score = 0;
u32 best_minOffset = 0;
-
- for (auto it = mask.begin(); it != mask.end(); ++it) {
+
+ for (auto it = mask.begin(); it != mask.end(); ++it) {
candidates.clear();
- if (!initFmlCandidates(*it, candidates)) {
+ if (!initFmlCandidates(*it, candidates)) {
DEBUG_PRINTF("failed to init\n");
continue;
}
DEBUG_PRINTF("++\n");
- auto jt = it;
- while (jt != mask.begin()) {
+ auto jt = it;
+ while (jt != mask.begin()) {
--jt;
DEBUG_PRINTF("--\n");
- if (!expandFmlCandidates(*jt, curr_candidates, candidates)) {
+ if (!expandFmlCandidates(*jt, curr_candidates, candidates)) {
DEBUG_PRINTF("expansion stopped\n");
break;
}
}
-
- // Candidates have been expanded in reverse order.
- for (auto &cand : candidates) {
- cand = reverse_literal(cand);
- }
-
+
+ // Candidates have been expanded in reverse order.
+ for (auto &cand : candidates) {
+ cand = reverse_literal(cand);
+ }
+
u32 score = scoreFmlCandidates(candidates);
DEBUG_PRINTF("scored %u for literal set of size %zu\n", score,
candidates.size());
if (!candidates.empty() && score >= best_score) {
- best_minOffset = it - mask.begin() - candidates.back().length() + 1;
+ best_minOffset = it - mask.begin() - candidates.back().length() + 1;
best_candidates.swap(candidates);
best_score = score;
}
@@ -286,11 +286,11 @@ bool findMaskLiterals(const vector<CharReach> &mask, vector<ue2_literal> *lit,
DEBUG_PRINTF("best minbound %u length %u\n", *minBound, *length);
- assert(all_of_in(best_candidates, [&](const ue2_literal &s) {
- return s.length() == *length;
- }));
-
- *lit = std::move(best_candidates);
+ assert(all_of_in(best_candidates, [&](const ue2_literal &s) {
+ return s.length() == *length;
+ }));
+
+ *lit = std::move(best_candidates);
return true;
}
@@ -345,8 +345,8 @@ void buildLiteralMask(const vector<CharReach> &mask, vector<u8> &msk,
}
static
-bool validateTransientMask(const vector<CharReach> &mask, bool anchored,
- bool eod, const Grey &grey) {
+bool validateTransientMask(const vector<CharReach> &mask, bool anchored,
+ bool eod, const Grey &grey) {
assert(!mask.empty());
// An EOD anchored mask requires that everything fit into history, while an
@@ -358,12 +358,12 @@ bool validateTransientMask(const vector<CharReach> &mask, bool anchored,
return false;
}
- /* although anchored masks cannot be transient, short masks may be placed
- * into the atable. */
- if (anchored && mask.size() > grey.maxAnchoredRegion) {
- return false;
- }
-
+ /* although anchored masks cannot be transient, short masks may be placed
+ * into the atable. */
+ if (anchored && mask.size() > grey.maxAnchoredRegion) {
+ return false;
+ }
+
vector<ue2_literal> lits;
u32 lit_minBound; /* minBound of each literal in lit */
u32 lit_length; /* length of each literal in lit */
@@ -423,8 +423,8 @@ bool validateTransientMask(const vector<CharReach> &mask, bool anchored,
static
bool maskIsNeeded(const ue2_literal &lit, const NGHolder &g) {
- flat_set<NFAVertex> curr = {g.accept};
- flat_set<NFAVertex> next;
+ flat_set<NFAVertex> curr = {g.accept};
+ flat_set<NFAVertex> next;
for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) {
const CharReach &cr = *it;
@@ -460,7 +460,7 @@ bool maskIsNeeded(const ue2_literal &lit, const NGHolder &g) {
static
void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool anchored,
+ const flat_set<ReportID> &reports, bool anchored,
bool eod) {
vector<ue2_literal> lits;
u32 lit_minBound; /* minBound of each literal in lit */
@@ -489,7 +489,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
// Everyone gets the same report ID.
ReportID mask_report = build.getNewNfaReport();
- set_report(*mask_graph, mask_report);
+ set_report(*mask_graph, mask_report);
// Build the HWLM literal mask.
vector<u8> msk, cmp;
@@ -525,7 +525,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
ENSURE_AT_LEAST(&build.ematcher_region_size, mask.size());
}
- const flat_set<ReportID> no_reports;
+ const flat_set<ReportID> no_reports;
for (const auto &lit : lits) {
u32 lit_id = build.getLiteralId(lit, msk, cmp, delay, table);
@@ -541,7 +541,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
g[v].left.leftfix_report = mask_report;
} else {
// Make sure our edge bounds are correct.
- RoseEdge e = edge(parent, v, g);
+ RoseEdge e = edge(parent, v, g);
g[e].minBound = 0;
g[e].maxBound = anchored ? 0 : ROSE_BOUND_INF;
g[e].history = anchored ? ROSE_ROLE_HISTORY_ANCH
@@ -553,7 +553,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
g[v].max_offset = v_max_offset;
if (eod) {
- RoseEdge e = add_edge(v, eod_v, g);
+ RoseEdge e = add_edge(v, eod_v, g);
g[e].minBound = 0;
g[e].maxBound = 0;
g[e].history = ROSE_ROLE_HISTORY_LAST_BYTE;
@@ -562,7 +562,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &mask,
}
static
-unique_ptr<NGHolder> buildMaskRhs(const flat_set<ReportID> &reports,
+unique_ptr<NGHolder> buildMaskRhs(const flat_set<ReportID> &reports,
const vector<CharReach> &mask,
u32 suffix_len) {
assert(suffix_len);
@@ -583,16 +583,16 @@ unique_ptr<NGHolder> buildMaskRhs(const flat_set<ReportID> &reports,
succ = u;
}
- NFAEdge e = add_edge(h.start, succ, h);
- h[e].tops.insert(DEFAULT_TOP);
+ NFAEdge e = add_edge(h.start, succ, h);
+ h[e].tops.insert(DEFAULT_TOP);
return rhs;
}
static
-void doAddMask(RoseBuildImpl &tbi, bool anchored, const vector<CharReach> &mask,
- const ue2_literal &lit, u32 prefix_len, u32 suffix_len,
- const flat_set<ReportID> &reports) {
+void doAddMask(RoseBuildImpl &tbi, bool anchored, const vector<CharReach> &mask,
+ const ue2_literal &lit, u32 prefix_len, u32 suffix_len,
+ const flat_set<ReportID> &reports) {
/* Note: bounds are relative to literal start */
RoseInGraph ig;
RoseInVertex s = add_vertex(RoseInVertexProps::makeStart(anchored), ig);
@@ -641,7 +641,7 @@ void doAddMask(RoseBuildImpl &tbi, bool anchored, const vector<CharReach> &mask,
= buildMaskLhs(true, minBound - prefix2_len + overlap,
mask3);
mhs->kind = NFA_INFIX;
- setTops(*mhs);
+ setTops(*mhs);
add_edge(u, v, RoseInEdgeProps(mhs, delay), ig);
DEBUG_PRINTF("add anch literal too!\n");
@@ -719,8 +719,8 @@ bool checkAllowMask(const vector<CharReach> &mask, ue2_literal *lit,
}
bool RoseBuildImpl::add(bool anchored, const vector<CharReach> &mask,
- const flat_set<ReportID> &reports) {
- if (validateTransientMask(mask, anchored, false, cc.grey)) {
+ const flat_set<ReportID> &reports) {
+ if (validateTransientMask(mask, anchored, false, cc.grey)) {
bool eod = false;
addTransientMask(*this, mask, reports, anchored, eod);
return true;
@@ -742,14 +742,14 @@ bool RoseBuildImpl::add(bool anchored, const vector<CharReach> &mask,
}
bool RoseBuildImpl::validateMask(const vector<CharReach> &mask,
- UNUSED const flat_set<ReportID> &reports,
- bool anchored, bool eod) const {
- return validateTransientMask(mask, anchored, eod, cc.grey);
+ UNUSED const flat_set<ReportID> &reports,
+ bool anchored, bool eod) const {
+ return validateTransientMask(mask, anchored, eod, cc.grey);
}
static
unique_ptr<NGHolder> makeAnchoredGraph(const vector<CharReach> &mask,
- const flat_set<ReportID> &reports,
+ const flat_set<ReportID> &reports,
bool eod) {
auto gp = ue2::make_unique<NGHolder>();
NGHolder &g = *gp;
@@ -771,7 +771,7 @@ unique_ptr<NGHolder> makeAnchoredGraph(const vector<CharReach> &mask,
static
bool addAnchoredMask(RoseBuildImpl &build, const vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool eod) {
+ const flat_set<ReportID> &reports, bool eod) {
if (!build.cc.grey.allowAnchoredAcyclic) {
return false;
}
@@ -783,8 +783,8 @@ bool addAnchoredMask(RoseBuildImpl &build, const vector<CharReach> &mask,
}
void RoseBuildImpl::addMask(const vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool anchored,
- bool eod) {
+ const flat_set<ReportID> &reports, bool anchored,
+ bool eod) {
if (anchored && addAnchoredMask(*this, mask, reports, eod)) {
DEBUG_PRINTF("added mask as anchored acyclic graph\n");
return;
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_anchored.cpp b/contrib/libs/hyperscan/src/rose/rose_build_anchored.cpp
index d247b33c3a4..23688b8d22e 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_anchored.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_anchored.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,7 +30,7 @@
#include "grey.h"
#include "rose_build_impl.h"
-#include "rose_build_matchers.h"
+#include "rose_build_matchers.h"
#include "rose_internal.h"
#include "ue2common.h"
#include "nfa/dfa_min.h"
@@ -49,12 +49,12 @@
#include "util/compile_error.h"
#include "util/container.h"
#include "util/determinise.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/make_unique.h"
#include "util/order_check.h"
#include "util/ue2string.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include "util/verify_types.h"
#include <map>
@@ -73,8 +73,8 @@ namespace ue2 {
#define INIT_STATE (DEAD_STATE + 1)
-#define NO_FRAG_ID (~0U)
-
+#define NO_FRAG_ID (~0U)
+
// Adds a vertex with the given reach.
static
NFAVertex add_vertex(NGHolder &h, const CharReach &cr) {
@@ -177,90 +177,90 @@ void mergeAnchoredDfas(vector<unique_ptr<raw_dfa>> &dfas,
}
static
-void remapAnchoredReports(raw_dfa &rdfa, const vector<u32> &frag_map) {
- for (dstate &ds : rdfa.states) {
- assert(ds.reports_eod.empty()); // Not used in anchored matcher.
- if (ds.reports.empty()) {
- continue;
- }
-
- flat_set<ReportID> new_reports;
- for (auto id : ds.reports) {
- assert(id < frag_map.size());
- new_reports.insert(frag_map[id]);
- }
- ds.reports = std::move(new_reports);
+void remapAnchoredReports(raw_dfa &rdfa, const vector<u32> &frag_map) {
+ for (dstate &ds : rdfa.states) {
+ assert(ds.reports_eod.empty()); // Not used in anchored matcher.
+ if (ds.reports.empty()) {
+ continue;
+ }
+
+ flat_set<ReportID> new_reports;
+ for (auto id : ds.reports) {
+ assert(id < frag_map.size());
+ new_reports.insert(frag_map[id]);
+ }
+ ds.reports = std::move(new_reports);
}
}
-/**
- * \brief Replaces the report ids currently in the dfas (rose graph literal
- * ids) with the fragment id for each literal.
- */
+/**
+ * \brief Replaces the report ids currently in the dfas (rose graph literal
+ * ids) with the fragment id for each literal.
+ */
static
-void remapAnchoredReports(RoseBuildImpl &build, const vector<u32> &frag_map) {
- for (auto &m : build.anchored_nfas) {
- for (auto &rdfa : m.second) {
- assert(rdfa);
- remapAnchoredReports(*rdfa, frag_map);
- }
+void remapAnchoredReports(RoseBuildImpl &build, const vector<u32> &frag_map) {
+ for (auto &m : build.anchored_nfas) {
+ for (auto &rdfa : m.second) {
+ assert(rdfa);
+ remapAnchoredReports(*rdfa, frag_map);
+ }
}
}
-/**
- * Returns mapping from literal ids to fragment ids.
- */
+/**
+ * Returns mapping from literal ids to fragment ids.
+ */
static
-vector<u32> reverseFragMap(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments) {
- vector<u32> rev(build.literal_info.size(), NO_FRAG_ID);
- for (const auto &f : fragments) {
- for (u32 lit_id : f.lit_ids) {
- assert(lit_id < rev.size());
- rev[lit_id] = f.fragment_id;
+vector<u32> reverseFragMap(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments) {
+ vector<u32> rev(build.literal_info.size(), NO_FRAG_ID);
+ for (const auto &f : fragments) {
+ for (u32 lit_id : f.lit_ids) {
+ assert(lit_id < rev.size());
+ rev[lit_id] = f.fragment_id;
}
}
- return rev;
+ return rev;
}
-/**
- * \brief Replace the reports (which are literal final_ids) in the given
- * raw_dfa with program offsets.
- */
+/**
+ * \brief Replace the reports (which are literal final_ids) in the given
+ * raw_dfa with program offsets.
+ */
static
-void remapIdsToPrograms(const vector<LitFragment> &fragments, raw_dfa &rdfa) {
- for (dstate &ds : rdfa.states) {
- assert(ds.reports_eod.empty()); // Not used in anchored matcher.
- if (ds.reports.empty()) {
- continue;
- }
-
- flat_set<ReportID> new_reports;
- for (auto fragment_id : ds.reports) {
- const auto &frag = fragments.at(fragment_id);
- new_reports.insert(frag.lit_program_offset);
- }
- ds.reports = std::move(new_reports);
- }
-}
-
-static
-unique_ptr<NGHolder> populate_holder(const simple_anchored_info &sai,
- const flat_set<u32> &exit_ids) {
+void remapIdsToPrograms(const vector<LitFragment> &fragments, raw_dfa &rdfa) {
+ for (dstate &ds : rdfa.states) {
+ assert(ds.reports_eod.empty()); // Not used in anchored matcher.
+ if (ds.reports.empty()) {
+ continue;
+ }
+
+ flat_set<ReportID> new_reports;
+ for (auto fragment_id : ds.reports) {
+ const auto &frag = fragments.at(fragment_id);
+ new_reports.insert(frag.lit_program_offset);
+ }
+ ds.reports = std::move(new_reports);
+ }
+}
+
+static
+unique_ptr<NGHolder> populate_holder(const simple_anchored_info &sai,
+ const flat_set<u32> &exit_ids) {
DEBUG_PRINTF("populating holder for ^.{%u,%u}%s\n", sai.min_bound,
sai.max_bound, dumpString(sai.literal).c_str());
- auto h_ptr = std::make_unique<NGHolder>();
- NGHolder &h = *h_ptr;
- auto ends = addDotsToGraph(h, h.start, sai.min_bound, sai.max_bound,
- CharReach::dot());
+ auto h_ptr = std::make_unique<NGHolder>();
+ NGHolder &h = *h_ptr;
+ auto ends = addDotsToGraph(h, h.start, sai.min_bound, sai.max_bound,
+ CharReach::dot());
NFAVertex v = addToGraph(h, ends, sai.literal);
add_edge(v, h.accept, h);
h[v].reports.insert(exit_ids.begin(), exit_ids.end());
- return h_ptr;
+ return h_ptr;
}
-u32 anchoredStateSize(const anchored_matcher_info &atable) {
- const struct anchored_matcher_info *curr = &atable;
+u32 anchoredStateSize(const anchored_matcher_info &atable) {
+ const struct anchored_matcher_info *curr = &atable;
// Walk the list until we find the last element; total state size will be
// that engine's state offset plus its state requirement.
@@ -270,12 +270,12 @@ u32 anchoredStateSize(const anchored_matcher_info &atable) {
}
const NFA *nfa = (const NFA *)((const char *)curr + sizeof(*curr));
- return curr->state_offset + nfa->streamStateSize;
+ return curr->state_offset + nfa->streamStateSize;
}
namespace {
-using nfa_state_set = bitfield<ANCHORED_NFA_STATE_LIMIT>;
+using nfa_state_set = bitfield<ANCHORED_NFA_STATE_LIMIT>;
struct Holder_StateSet {
Holder_StateSet() : wdelay(0) {}
@@ -286,16 +286,16 @@ struct Holder_StateSet {
bool operator==(const Holder_StateSet &b) const {
return wdelay == b.wdelay && wrap_state == b.wrap_state;
}
-
- size_t hash() const {
- return hash_all(wrap_state, wdelay);
- }
+
+ size_t hash() const {
+ return hash_all(wrap_state, wdelay);
+ }
};
class Automaton_Holder {
public:
- using StateSet = Holder_StateSet;
- using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
+ using StateSet = Holder_StateSet;
+ using StateMap = ue2_unordered_map<StateSet, dstate_id_t>;
explicit Automaton_Holder(const NGHolder &g_in) : g(g_in) {
for (auto v : vertices_range(g)) {
@@ -414,7 +414,7 @@ public:
private:
const NGHolder &g;
- unordered_map<NFAVertex, u32> vertexToIndex;
+ unordered_map<NFAVertex, u32> vertexToIndex;
vector<NFAVertex> indexToVertex;
vector<CharReach> cr_by_index;
StateSet init;
@@ -486,7 +486,7 @@ bool check_dupe(const raw_dfa &rdfa,
}
static
-bool check_dupe_simple(const RoseBuildImpl &build, u32 min_bound, u32 max_bound,
+bool check_dupe_simple(const RoseBuildImpl &build, u32 min_bound, u32 max_bound,
const ue2_literal &lit, ReportID *remap) {
if (!remap) {
DEBUG_PRINTF("no remap\n");
@@ -494,8 +494,8 @@ bool check_dupe_simple(const RoseBuildImpl &build, u32 min_bound, u32 max_bound,
}
simple_anchored_info sai(min_bound, max_bound, lit);
- if (contains(build.anchored_simple, sai)) {
- *remap = *build.anchored_simple.at(sai).begin();
+ if (contains(build.anchored_simple, sai)) {
+ *remap = *build.anchored_simple.at(sai).begin();
return true;
}
@@ -515,7 +515,7 @@ NFAVertex extractLiteral(const NGHolder &h, ue2_literal *lit) {
}
if (lit_verts.empty()) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
bool nocase = false;
@@ -527,7 +527,7 @@ NFAVertex extractLiteral(const NGHolder &h, ue2_literal *lit) {
if (cr.isAlpha()) {
bool cr_nocase = cr.count() != 1;
if (case_set && cr_nocase != nocase) {
- return NGHolder::null_vertex();
+ return NGHolder::null_vertex();
}
case_set = true;
@@ -550,7 +550,7 @@ bool isSimple(const NGHolder &h, u32 *min_bound, u32 *max_bound,
DEBUG_PRINTF("looking for simple case\n");
NFAVertex lit_head = extractLiteral(h, lit);
- if (lit_head == NGHolder::null_vertex()) {
+ if (lit_head == NGHolder::null_vertex()) {
DEBUG_PRINTF("no literal found\n");
return false;
}
@@ -568,7 +568,7 @@ bool isSimple(const NGHolder &h, u32 *min_bound, u32 *max_bound,
/* lit should only be connected to dot vertices */
for (auto u : inv_adjacent_vertices_range(lit_head, h)) {
- DEBUG_PRINTF("checking %zu\n", h[u].index);
+ DEBUG_PRINTF("checking %zu\n", h[u].index);
if (!h[u].char_reach.all()) {
return false;
}
@@ -659,7 +659,7 @@ bool isSimple(const NGHolder &h, u32 *min_bound, u32 *max_bound,
}
static
-int finalise_out(RoseBuildImpl &build, const NGHolder &h,
+int finalise_out(RoseBuildImpl &build, const NGHolder &h,
const Automaton_Holder &autom, unique_ptr<raw_dfa> out_dfa,
ReportID *remap) {
u32 min_bound = ~0U;
@@ -668,12 +668,12 @@ int finalise_out(RoseBuildImpl &build, const NGHolder &h,
u32 simple_report = MO_INVALID_IDX;
if (isSimple(h, &min_bound, &max_bound, &lit, &simple_report)) {
assert(simple_report != MO_INVALID_IDX);
- if (check_dupe_simple(build, min_bound, max_bound, lit, remap)) {
+ if (check_dupe_simple(build, min_bound, max_bound, lit, remap)) {
DEBUG_PRINTF("found duplicate remapping to %u\n", *remap);
return ANCHORED_REMAP;
}
DEBUG_PRINTF("add with report %u\n", simple_report);
- build.anchored_simple[simple_anchored_info(min_bound, max_bound, lit)]
+ build.anchored_simple[simple_anchored_info(min_bound, max_bound, lit)]
.insert(simple_report);
return ANCHORED_SUCCESS;
}
@@ -683,15 +683,15 @@ int finalise_out(RoseBuildImpl &build, const NGHolder &h,
out_dfa->alpha_size = autom.alphasize;
out_dfa->alpha_remap = autom.alpha;
auto hash = hash_dfa_no_reports(*out_dfa);
- if (check_dupe(*out_dfa, build.anchored_nfas[hash], remap)) {
+ if (check_dupe(*out_dfa, build.anchored_nfas[hash], remap)) {
return ANCHORED_REMAP;
}
- build.anchored_nfas[hash].push_back(move(out_dfa));
+ build.anchored_nfas[hash].push_back(move(out_dfa));
return ANCHORED_SUCCESS;
}
static
-int addAutomaton(RoseBuildImpl &build, const NGHolder &h, ReportID *remap) {
+int addAutomaton(RoseBuildImpl &build, const NGHolder &h, ReportID *remap) {
if (num_vertices(h) > ANCHORED_NFA_STATE_LIMIT) {
DEBUG_PRINTF("autom bad!\n");
return ANCHORED_FAIL;
@@ -699,9 +699,9 @@ int addAutomaton(RoseBuildImpl &build, const NGHolder &h, ReportID *remap) {
Automaton_Holder autom(h);
- auto out_dfa = ue2::make_unique<raw_dfa>(NFA_OUTFIX_RAW);
- if (determinise(autom, out_dfa->states, MAX_DFA_STATES)) {
- return finalise_out(build, h, autom, move(out_dfa), remap);
+ auto out_dfa = ue2::make_unique<raw_dfa>(NFA_OUTFIX_RAW);
+ if (determinise(autom, out_dfa->states, MAX_DFA_STATES)) {
+ return finalise_out(build, h, autom, move(out_dfa), remap);
}
DEBUG_PRINTF("determinise failed\n");
@@ -710,7 +710,7 @@ int addAutomaton(RoseBuildImpl &build, const NGHolder &h, ReportID *remap) {
static
void setReports(NGHolder &h, const map<NFAVertex, set<u32>> &reportMap,
- const unordered_map<NFAVertex, NFAVertex> &orig_to_copy) {
+ const unordered_map<NFAVertex, NFAVertex> &orig_to_copy) {
for (const auto &m : reportMap) {
NFAVertex t = orig_to_copy.at(m.first);
assert(!m.second.empty());
@@ -719,10 +719,10 @@ void setReports(NGHolder &h, const map<NFAVertex, set<u32>> &reportMap,
}
}
-int addAnchoredNFA(RoseBuildImpl &build, const NGHolder &wrapper,
+int addAnchoredNFA(RoseBuildImpl &build, const NGHolder &wrapper,
const map<NFAVertex, set<u32>> &reportMap) {
NGHolder h;
- unordered_map<NFAVertex, NFAVertex> orig_to_copy;
+ unordered_map<NFAVertex, NFAVertex> orig_to_copy;
cloneHolder(h, wrapper, &orig_to_copy);
clear_in_edges(h.accept, h);
clear_in_edges(h.acceptEod, h);
@@ -730,10 +730,10 @@ int addAnchoredNFA(RoseBuildImpl &build, const NGHolder &wrapper,
clearReports(h);
setReports(h, reportMap, orig_to_copy);
- return addAutomaton(build, h, nullptr);
+ return addAutomaton(build, h, nullptr);
}
-int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
+int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
u32 exit_id, ReportID *remap) {
NGHolder h;
cloneHolder(h, anchored);
@@ -744,26 +744,26 @@ int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
h[v].reports.insert(exit_id);
}
- return addAutomaton(build, h, remap);
+ return addAutomaton(build, h, remap);
}
static
-void buildSimpleDfas(const RoseBuildImpl &build, const vector<u32> &frag_map,
+void buildSimpleDfas(const RoseBuildImpl &build, const vector<u32> &frag_map,
vector<unique_ptr<raw_dfa>> *anchored_dfas) {
/* we should have determinised all of these before so there should be no
* chance of failure. */
- flat_set<u32> exit_ids;
- for (const auto &simple : build.anchored_simple) {
- exit_ids.clear();
+ flat_set<u32> exit_ids;
+ for (const auto &simple : build.anchored_simple) {
+ exit_ids.clear();
for (auto lit_id : simple.second) {
- assert(lit_id < frag_map.size());
- exit_ids.insert(frag_map[lit_id]);
+ assert(lit_id < frag_map.size());
+ exit_ids.insert(frag_map[lit_id]);
}
- auto h = populate_holder(simple.first, exit_ids);
- Automaton_Holder autom(*h);
- auto rdfa = ue2::make_unique<raw_dfa>(NFA_OUTFIX_RAW);
- UNUSED bool rv = determinise(autom, rdfa->states, MAX_DFA_STATES);
- assert(rv);
+ auto h = populate_holder(simple.first, exit_ids);
+ Automaton_Holder autom(*h);
+ auto rdfa = ue2::make_unique<raw_dfa>(NFA_OUTFIX_RAW);
+ UNUSED bool rv = determinise(autom, rdfa->states, MAX_DFA_STATES);
+ assert(rv);
rdfa->start_anchored = INIT_STATE;
rdfa->start_floating = DEAD_STATE;
rdfa->alpha_size = autom.alphasize;
@@ -778,25 +778,25 @@ void buildSimpleDfas(const RoseBuildImpl &build, const vector<u32> &frag_map,
* from RoseBuildImpl.
*/
static
-vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build,
- const vector<u32> &frag_map) {
- vector<unique_ptr<raw_dfa>> dfas;
-
+vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build,
+ const vector<u32> &frag_map) {
+ vector<unique_ptr<raw_dfa>> dfas;
+
// DFAs that already exist as raw_dfas.
- for (auto &anch_dfas : build.anchored_nfas) {
+ for (auto &anch_dfas : build.anchored_nfas) {
for (auto &rdfa : anch_dfas.second) {
- dfas.push_back(move(rdfa));
+ dfas.push_back(move(rdfa));
}
}
- build.anchored_nfas.clear();
+ build.anchored_nfas.clear();
// DFAs we currently have as simple literals.
- if (!build.anchored_simple.empty()) {
- buildSimpleDfas(build, frag_map, &dfas);
- build.anchored_simple.clear();
+ if (!build.anchored_simple.empty()) {
+ buildSimpleDfas(build, frag_map, &dfas);
+ build.anchored_simple.clear();
}
-
- return dfas;
+
+ return dfas;
}
/**
@@ -810,10 +810,10 @@ vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build,
* \return Total bytes required for the complete anchored matcher.
*/
static
-size_t buildNfas(vector<raw_dfa> &anchored_dfas,
- vector<bytecode_ptr<NFA>> *nfas,
- vector<u32> *start_offset, const CompileContext &cc,
- const ReportManager &rm) {
+size_t buildNfas(vector<raw_dfa> &anchored_dfas,
+ vector<bytecode_ptr<NFA>> *nfas,
+ vector<u32> *start_offset, const CompileContext &cc,
+ const ReportManager &rm) {
const size_t num_dfas = anchored_dfas.size();
nfas->reserve(num_dfas);
@@ -822,12 +822,12 @@ size_t buildNfas(vector<raw_dfa> &anchored_dfas,
size_t total_size = 0;
for (auto &rdfa : anchored_dfas) {
- u32 removed_dots = remove_leading_dots(rdfa);
+ u32 removed_dots = remove_leading_dots(rdfa);
start_offset->push_back(removed_dots);
- minimize_hopcroft(rdfa, cc.grey);
+ minimize_hopcroft(rdfa, cc.grey);
- auto nfa = mcclellanCompile(rdfa, cc, rm, false);
+ auto nfa = mcclellanCompile(rdfa, cc, rm, false);
if (!nfa) {
assert(0);
throw std::bad_alloc();
@@ -844,53 +844,53 @@ size_t buildNfas(vector<raw_dfa> &anchored_dfas,
return total_size;
}
-vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
- const vector<LitFragment> &fragments) {
- vector<raw_dfa> dfas;
+vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
+ const vector<LitFragment> &fragments) {
+ vector<raw_dfa> dfas;
- if (build.anchored_nfas.empty() && build.anchored_simple.empty()) {
+ if (build.anchored_nfas.empty() && build.anchored_simple.empty()) {
+ DEBUG_PRINTF("empty\n");
+ return dfas;
+ }
+
+ const auto frag_map = reverseFragMap(build, fragments);
+ remapAnchoredReports(build, frag_map);
+
+ auto anch_dfas = getAnchoredDfas(build, frag_map);
+ mergeAnchoredDfas(anch_dfas, build);
+
+ dfas.reserve(anch_dfas.size());
+ for (auto &rdfa : anch_dfas) {
+ assert(rdfa);
+ dfas.push_back(move(*rdfa));
+ }
+ return dfas;
+}
+
+bytecode_ptr<anchored_matcher_info>
+buildAnchoredMatcher(RoseBuildImpl &build, const vector<LitFragment> &fragments,
+ vector<raw_dfa> &dfas) {
+ const CompileContext &cc = build.cc;
+
+ if (dfas.empty()) {
DEBUG_PRINTF("empty\n");
- return dfas;
- }
-
- const auto frag_map = reverseFragMap(build, fragments);
- remapAnchoredReports(build, frag_map);
-
- auto anch_dfas = getAnchoredDfas(build, frag_map);
- mergeAnchoredDfas(anch_dfas, build);
-
- dfas.reserve(anch_dfas.size());
- for (auto &rdfa : anch_dfas) {
- assert(rdfa);
- dfas.push_back(move(*rdfa));
- }
- return dfas;
-}
-
-bytecode_ptr<anchored_matcher_info>
-buildAnchoredMatcher(RoseBuildImpl &build, const vector<LitFragment> &fragments,
- vector<raw_dfa> &dfas) {
- const CompileContext &cc = build.cc;
-
- if (dfas.empty()) {
- DEBUG_PRINTF("empty\n");
return nullptr;
}
- for (auto &rdfa : dfas) {
- remapIdsToPrograms(fragments, rdfa);
- }
+ for (auto &rdfa : dfas) {
+ remapIdsToPrograms(fragments, rdfa);
+ }
- vector<bytecode_ptr<NFA>> nfas;
+ vector<bytecode_ptr<NFA>> nfas;
vector<u32> start_offset; // start offset for each dfa (dots removed)
- size_t total_size = buildNfas(dfas, &nfas, &start_offset, cc, build.rm);
+ size_t total_size = buildNfas(dfas, &nfas, &start_offset, cc, build.rm);
if (total_size > cc.grey.limitRoseAnchoredSize) {
throw ResourceLimitError();
}
- auto atable =
- make_zeroed_bytecode_ptr<anchored_matcher_info>(total_size, 64);
+ auto atable =
+ make_zeroed_bytecode_ptr<anchored_matcher_info>(total_size, 64);
char *curr = (char *)atable.get();
u32 state_offset = 0;
@@ -912,11 +912,11 @@ buildAnchoredMatcher(RoseBuildImpl &build, const vector<LitFragment> &fragments,
}
ami->state_offset = state_offset;
- state_offset += nfa->streamStateSize;
+ state_offset += nfa->streamStateSize;
ami->anchoredMinDistance = start_offset[i];
}
- DEBUG_PRINTF("success %zu\n", atable.size());
+ DEBUG_PRINTF("success %zu\n", atable.size());
return atable;
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_anchored.h b/contrib/libs/hyperscan/src/rose/rose_build_anchored.h
index ef9d575e310..37d268ac5a7 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_anchored.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_anchored.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,50 +30,50 @@
#define ROSE_BUILD_ANCHORED
#include "ue2common.h"
-#include "rose_build_impl.h"
+#include "rose_build_impl.h"
#include "nfagraph/ng_holder.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include <map>
#include <vector>
#include <set>
-struct anchored_matcher_info;
+struct anchored_matcher_info;
namespace ue2 {
class RoseBuildImpl;
-struct raw_dfa;
-struct LitFragment;
+struct raw_dfa;
+struct LitFragment;
-/**
- * \brief Construct a set of anchored DFAs from our anchored literals/engines.
- */
-std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments);
+/**
+ * \brief Construct a set of anchored DFAs from our anchored literals/engines.
+ */
+std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments);
+
+/**
+ * \brief Construct an anchored_matcher_info runtime structure from the given
+ * set of DFAs.
+ *
+ * Remap the literal final_ids used for raw_dfa reports to the program offsets
+ * given in litPrograms.
+ */
+bytecode_ptr<anchored_matcher_info>
+buildAnchoredMatcher(RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments,
+ std::vector<raw_dfa> &dfas);
+
+u32 anchoredStateSize(const anchored_matcher_info &atable);
-/**
- * \brief Construct an anchored_matcher_info runtime structure from the given
- * set of DFAs.
- *
- * Remap the literal final_ids used for raw_dfa reports to the program offsets
- * given in litPrograms.
- */
-bytecode_ptr<anchored_matcher_info>
-buildAnchoredMatcher(RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments,
- std::vector<raw_dfa> &dfas);
-
-u32 anchoredStateSize(const anchored_matcher_info &atable);
-
#define ANCHORED_FAIL 0
#define ANCHORED_SUCCESS 1
#define ANCHORED_REMAP 2
-int addAnchoredNFA(RoseBuildImpl &build, const NGHolder &wrapper,
+int addAnchoredNFA(RoseBuildImpl &build, const NGHolder &wrapper,
const std::map<NFAVertex, std::set<u32>> &reportMap);
-int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
+int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
u32 exit_id, ReportID *remap);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_bytecode.cpp b/contrib/libs/hyperscan/src/rose/rose_build_bytecode.cpp
index 6327e537357..df464c2800a 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_bytecode.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_bytecode.cpp
@@ -33,38 +33,38 @@
#include "hs_compile.h" // for HS_MODE_*
#include "rose_build_add_internal.h"
#include "rose_build_anchored.h"
-#include "rose_build_dump.h"
-#include "rose_build_engine_blob.h"
-#include "rose_build_exclusive.h"
-#include "rose_build_groups.h"
+#include "rose_build_dump.h"
+#include "rose_build_engine_blob.h"
+#include "rose_build_exclusive.h"
+#include "rose_build_groups.h"
#include "rose_build_infix.h"
-#include "rose_build_long_lit.h"
+#include "rose_build_long_lit.h"
#include "rose_build_lookaround.h"
-#include "rose_build_matchers.h"
-#include "rose_build_misc.h"
-#include "rose_build_program.h"
-#include "rose_build_resources.h"
+#include "rose_build_matchers.h"
+#include "rose_build_misc.h"
+#include "rose_build_program.h"
+#include "rose_build_resources.h"
#include "rose_build_scatter.h"
#include "rose_build_util.h"
#include "rose_build_width.h"
-#include "rose_internal.h"
-#include "rose_program.h"
+#include "rose_internal.h"
+#include "rose_program.h"
#include "hwlm/hwlm.h" /* engine types */
#include "hwlm/hwlm_build.h"
-#include "hwlm/hwlm_literal.h"
+#include "hwlm/hwlm_literal.h"
#include "nfa/castlecompile.h"
#include "nfa/goughcompile.h"
#include "nfa/mcclellancompile.h"
-#include "nfa/mcclellancompile_util.h"
-#include "nfa/mcsheng_compile.h"
+#include "nfa/mcclellancompile_util.h"
+#include "nfa/mcsheng_compile.h"
#include "nfa/nfa_api_queue.h"
#include "nfa/nfa_build_util.h"
#include "nfa/nfa_internal.h"
-#include "nfa/shengcompile.h"
+#include "nfa/shengcompile.h"
#include "nfa/shufticompile.h"
-#include "nfa/tamaramacompile.h"
-#include "nfa/tamarama_internal.h"
-#include "nfagraph/ng_execute.h"
+#include "nfa/tamaramacompile.h"
+#include "nfa/tamarama_internal.h"
+#include "nfagraph/ng_execute.h"
#include "nfagraph/ng_holder.h"
#include "nfagraph/ng_lbr.h"
#include "nfagraph/ng_limex.h"
@@ -75,7 +75,7 @@
#include "nfagraph/ng_stop.h"
#include "nfagraph/ng_util.h"
#include "nfagraph/ng_width.h"
-#include "smallwrite/smallwrite_build.h"
+#include "smallwrite/smallwrite_build.h"
#include "som/slot_manager.h"
#include "util/bitutils.h"
#include "util/boundary_reports.h"
@@ -84,21 +84,21 @@
#include "util/compile_context.h"
#include "util/compile_error.h"
#include "util/container.h"
-#include "util/fatbit_build.h"
+#include "util/fatbit_build.h"
#include "util/graph_range.h"
-#include "util/insertion_ordered.h"
-#include "util/make_unique.h"
+#include "util/insertion_ordered.h"
+#include "util/make_unique.h"
#include "util/multibit_build.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include "util/order_check.h"
-#include "util/popcount.h"
+#include "util/popcount.h"
#include "util/queue_index_factory.h"
#include "util/report_manager.h"
#include "util/ue2string.h"
#include "util/verify_types.h"
#include <algorithm>
-#include <array>
+#include <array>
#include <map>
#include <queue>
#include <set>
@@ -135,73 +135,73 @@ namespace ue2 {
namespace /* anon */ {
-struct build_context : noncopyable {
- /** \brief information about engines to the left of a vertex */
- map<RoseVertex, left_build_info> leftfix_info;
-
- /** \brief mapping from suffix to queue index. */
- map<suffix_id, u32> suffixes;
-
- /** \brief engine info by queue. */
- map<u32, engine_info> engine_info_by_queue;
-
- /** \brief Simple cache of programs written to engine blob, used for
- * deduplication. */
- unordered_map<RoseProgram, u32, RoseProgramHash,
- RoseProgramEquivalence> program_cache;
-
- /** \brief State indices, for those roles that have them.
- * Each vertex present has a unique state index in the range
- * [0, roleStateIndices.size()). */
- unordered_map<RoseVertex, u32> roleStateIndices;
-
- /** \brief Mapping from queue index to bytecode offset for built engines
- * that have already been pushed into the engine_blob. */
- unordered_map<u32, u32> engineOffsets;
-
- /** \brief List of long literals (ones with CHECK_LONG_LIT instructions)
- * that need hash table support. */
- vector<ue2_case_string> longLiterals;
-
- /** \brief Contents of the Rose bytecode immediately following the
- * RoseEngine. */
- RoseEngineBlob engine_blob;
-
- /** \brief True if this Rose engine has an MPV engine. */
- bool needs_mpv_catchup = false;
-
- /** \brief Resources in use (tracked as programs are added). */
- RoseResources resources;
-};
-
-/** \brief subengine info including built engine and
-* corresponding triggering rose vertices */
-struct ExclusiveSubengine {
- bytecode_ptr<NFA> nfa;
- vector<RoseVertex> vertices;
-};
-
-/** \brief exclusive info to build tamarama */
-struct ExclusiveInfo : noncopyable {
- // subengine info
- vector<ExclusiveSubengine> subengines;
- // all the report in tamarama
- set<ReportID> reports;
- // assigned queue id
- u32 queue;
+struct build_context : noncopyable {
+ /** \brief information about engines to the left of a vertex */
+ map<RoseVertex, left_build_info> leftfix_info;
+
+ /** \brief mapping from suffix to queue index. */
+ map<suffix_id, u32> suffixes;
+
+ /** \brief engine info by queue. */
+ map<u32, engine_info> engine_info_by_queue;
+
+ /** \brief Simple cache of programs written to engine blob, used for
+ * deduplication. */
+ unordered_map<RoseProgram, u32, RoseProgramHash,
+ RoseProgramEquivalence> program_cache;
+
+ /** \brief State indices, for those roles that have them.
+ * Each vertex present has a unique state index in the range
+ * [0, roleStateIndices.size()). */
+ unordered_map<RoseVertex, u32> roleStateIndices;
+
+ /** \brief Mapping from queue index to bytecode offset for built engines
+ * that have already been pushed into the engine_blob. */
+ unordered_map<u32, u32> engineOffsets;
+
+ /** \brief List of long literals (ones with CHECK_LONG_LIT instructions)
+ * that need hash table support. */
+ vector<ue2_case_string> longLiterals;
+
+ /** \brief Contents of the Rose bytecode immediately following the
+ * RoseEngine. */
+ RoseEngineBlob engine_blob;
+
+ /** \brief True if this Rose engine has an MPV engine. */
+ bool needs_mpv_catchup = false;
+
+ /** \brief Resources in use (tracked as programs are added). */
+ RoseResources resources;
+};
+
+/** \brief subengine info including built engine and
+* corresponding triggering rose vertices */
+struct ExclusiveSubengine {
+ bytecode_ptr<NFA> nfa;
+ vector<RoseVertex> vertices;
+};
+
+/** \brief exclusive info to build tamarama */
+struct ExclusiveInfo : noncopyable {
+ // subengine info
+ vector<ExclusiveSubengine> subengines;
+ // all the report in tamarama
+ set<ReportID> reports;
+ // assigned queue id
+ u32 queue;
};
}
static
-void add_nfa_to_blob(build_context &bc, NFA &nfa) {
- u32 qi = nfa.queueIndex;
- u32 nfa_offset = bc.engine_blob.add(nfa, nfa.length);
- DEBUG_PRINTF("added nfa qi=%u, type=%u, length=%u at offset=%u\n", qi,
- nfa.type, nfa.length, nfa_offset);
-
- assert(!contains(bc.engineOffsets, qi));
- bc.engineOffsets.emplace(qi, nfa_offset);
+void add_nfa_to_blob(build_context &bc, NFA &nfa) {
+ u32 qi = nfa.queueIndex;
+ u32 nfa_offset = bc.engine_blob.add(nfa, nfa.length);
+ DEBUG_PRINTF("added nfa qi=%u, type=%u, length=%u at offset=%u\n", qi,
+ nfa.type, nfa.length, nfa_offset);
+
+ assert(!contains(bc.engineOffsets, qi));
+ bc.engineOffsets.emplace(qi, nfa_offset);
}
static
@@ -215,96 +215,96 @@ u32 countRosePrefixes(const vector<LeftNfaInfo> &roses) {
return num;
}
-/**
- * \brief True if this Rose engine needs to run a catch up whenever a literal
- * report is generated.
- *
- * Catch up is necessary if there are output-exposed engines (suffixes,
- * outfixes).
- */
-static
-bool needsCatchup(const RoseBuildImpl &build) {
- /* Note: we could be more selective about when we need to generate catch up
- * instructions rather than just a boolean yes/no - for instance, if we know
- * that a role can only match before the point that an outfix/suffix could
- * match, we do not strictly need a catchup instruction.
- *
- * However, this would add a certain amount of complexity to the
- * catchup logic and would likely have limited applicability - how many
- * reporting roles have a fixed max offset and how much time is spent on
- * catchup for these cases?
- */
-
- if (!build.outfixes.empty()) {
- /* TODO: check that they have non-eod reports */
+/**
+ * \brief True if this Rose engine needs to run a catch up whenever a literal
+ * report is generated.
+ *
+ * Catch up is necessary if there are output-exposed engines (suffixes,
+ * outfixes).
+ */
+static
+bool needsCatchup(const RoseBuildImpl &build) {
+ /* Note: we could be more selective about when we need to generate catch up
+ * instructions rather than just a boolean yes/no - for instance, if we know
+ * that a role can only match before the point that an outfix/suffix could
+ * match, we do not strictly need a catchup instruction.
+ *
+ * However, this would add a certain amount of complexity to the
+ * catchup logic and would likely have limited applicability - how many
+ * reporting roles have a fixed max offset and how much time is spent on
+ * catchup for these cases?
+ */
+
+ if (!build.outfixes.empty()) {
+ /* TODO: check that they have non-eod reports */
DEBUG_PRINTF("has outfixes\n");
- return true;
- }
-
- const RoseGraph &g = build.g;
-
- for (auto v : vertices_range(g)) {
- if (g[v].suffix) {
- /* TODO: check that they have non-eod reports */
- DEBUG_PRINTF("vertex %zu has suffix\n", g[v].index);
- return true;
- }
- }
-
- DEBUG_PRINTF("no need for catch-up on report\n");
- return false;
-}
-
-static
-bool isPureFloating(const RoseResources &resources, const CompileContext &cc) {
- if (!resources.has_floating) {
- DEBUG_PRINTF("no floating table\n");
+ return true;
+ }
+
+ const RoseGraph &g = build.g;
+
+ for (auto v : vertices_range(g)) {
+ if (g[v].suffix) {
+ /* TODO: check that they have non-eod reports */
+ DEBUG_PRINTF("vertex %zu has suffix\n", g[v].index);
+ return true;
+ }
+ }
+
+ DEBUG_PRINTF("no need for catch-up on report\n");
+ return false;
+}
+
+static
+bool isPureFloating(const RoseResources &resources, const CompileContext &cc) {
+ if (!resources.has_floating) {
+ DEBUG_PRINTF("no floating table\n");
return false;
}
- if (resources.has_outfixes || resources.has_suffixes ||
- resources.has_leftfixes) {
- DEBUG_PRINTF("has engines\n");
- return false;
- }
+ if (resources.has_outfixes || resources.has_suffixes ||
+ resources.has_leftfixes) {
+ DEBUG_PRINTF("has engines\n");
+ return false;
+ }
- if (resources.has_anchored) {
- DEBUG_PRINTF("has anchored matcher\n");
+ if (resources.has_anchored) {
+ DEBUG_PRINTF("has anchored matcher\n");
return false;
}
- if (resources.has_eod) {
- DEBUG_PRINTF("has eod work to do\n");
- return false;
- }
+ if (resources.has_eod) {
+ DEBUG_PRINTF("has eod work to do\n");
+ return false;
+ }
+
+ if (resources.has_states) {
+ DEBUG_PRINTF("has states\n");
+ return false;
+ }
- if (resources.has_states) {
- DEBUG_PRINTF("has states\n");
- return false;
- }
+ if (resources.has_lit_delay) {
+ DEBUG_PRINTF("has delayed literals\n");
+ return false;
+ }
- if (resources.has_lit_delay) {
- DEBUG_PRINTF("has delayed literals\n");
- return false;
- }
+ if (cc.streaming && resources.has_lit_check) {
+ DEBUG_PRINTF("has long literals in streaming mode, which needs long "
+ "literal table support\n");
+ return false;
+ }
- if (cc.streaming && resources.has_lit_check) {
- DEBUG_PRINTF("has long literals in streaming mode, which needs long "
- "literal table support\n");
- return false;
+ if (resources.checks_groups) {
+ DEBUG_PRINTF("has group checks\n");
+ return false;
}
- if (resources.checks_groups) {
- DEBUG_PRINTF("has group checks\n");
- return false;
- }
-
DEBUG_PRINTF("pure floating literals\n");
return true;
}
static
-bool isSingleOutfix(const RoseBuildImpl &tbi) {
+bool isSingleOutfix(const RoseBuildImpl &tbi) {
for (auto v : vertices_range(tbi.g)) {
if (tbi.isAnyStart(v)) {
continue;
@@ -324,86 +324,86 @@ bool isSingleOutfix(const RoseBuildImpl &tbi) {
return false; /* streaming runtime makes liberal use of broken flag */
}
- return tbi.outfixes.size() == 1;
+ return tbi.outfixes.size() == 1;
}
static
-u8 pickRuntimeImpl(const RoseBuildImpl &build, const RoseResources &resources,
- UNUSED u32 outfixEndQueue) {
- DEBUG_PRINTF("has_outfixes=%d\n", resources.has_outfixes);
- DEBUG_PRINTF("has_suffixes=%d\n", resources.has_suffixes);
- DEBUG_PRINTF("has_leftfixes=%d\n", resources.has_leftfixes);
- DEBUG_PRINTF("has_literals=%d\n", resources.has_literals);
- DEBUG_PRINTF("has_states=%d\n", resources.has_states);
- DEBUG_PRINTF("checks_groups=%d\n", resources.checks_groups);
- DEBUG_PRINTF("has_lit_delay=%d\n", resources.has_lit_delay);
- DEBUG_PRINTF("has_lit_check=%d\n", resources.has_lit_check);
- DEBUG_PRINTF("has_anchored=%d\n", resources.has_anchored);
- DEBUG_PRINTF("has_floating=%d\n", resources.has_floating);
- DEBUG_PRINTF("has_eod=%d\n", resources.has_eod);
-
- if (isPureFloating(resources, build.cc)) {
+u8 pickRuntimeImpl(const RoseBuildImpl &build, const RoseResources &resources,
+ UNUSED u32 outfixEndQueue) {
+ DEBUG_PRINTF("has_outfixes=%d\n", resources.has_outfixes);
+ DEBUG_PRINTF("has_suffixes=%d\n", resources.has_suffixes);
+ DEBUG_PRINTF("has_leftfixes=%d\n", resources.has_leftfixes);
+ DEBUG_PRINTF("has_literals=%d\n", resources.has_literals);
+ DEBUG_PRINTF("has_states=%d\n", resources.has_states);
+ DEBUG_PRINTF("checks_groups=%d\n", resources.checks_groups);
+ DEBUG_PRINTF("has_lit_delay=%d\n", resources.has_lit_delay);
+ DEBUG_PRINTF("has_lit_check=%d\n", resources.has_lit_check);
+ DEBUG_PRINTF("has_anchored=%d\n", resources.has_anchored);
+ DEBUG_PRINTF("has_floating=%d\n", resources.has_floating);
+ DEBUG_PRINTF("has_eod=%d\n", resources.has_eod);
+
+ if (isPureFloating(resources, build.cc)) {
return ROSE_RUNTIME_PURE_LITERAL;
}
- if (isSingleOutfix(build)) {
+ if (isSingleOutfix(build)) {
return ROSE_RUNTIME_SINGLE_OUTFIX;
}
return ROSE_RUNTIME_FULL_ROSE;
}
-/**
- * \brief True if this Rose engine needs to run MPV catch up in front of
- * non-MPV reports.
- */
-static
-bool needsMpvCatchup(const RoseBuildImpl &build) {
- const auto &outfixes = build.outfixes;
- bool has_mpv =
- any_of(begin(outfixes), end(outfixes), [](const OutfixInfo &outfix) {
- return outfix.is_nonempty_mpv();
- });
-
- if (!has_mpv) {
- DEBUG_PRINTF("no mpv\n");
- return false;
- }
-
- if (isSingleOutfix(build)) {
- DEBUG_PRINTF("single outfix\n");
- return false;
- }
-
- return true;
-}
-
-static
-void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
- u32 anchorStateSize, u32 activeArrayCount,
- u32 activeLeftCount, u32 laggedRoseCount,
- u32 longLitStreamStateRequired, u32 historyRequired,
- RoseStateOffsets *so) {
- u32 curr_offset = 0;
-
- // First, runtime status (stores per-stream state, like whether we need a
- // delay rebuild or have been told to halt matching.)
- curr_offset += sizeof(u8);
-
- // Role state storage.
- curr_offset += mmbit_size(rolesWithStateCount);
-
+/**
+ * \brief True if this Rose engine needs to run MPV catch up in front of
+ * non-MPV reports.
+ */
+static
+bool needsMpvCatchup(const RoseBuildImpl &build) {
+ const auto &outfixes = build.outfixes;
+ bool has_mpv =
+ any_of(begin(outfixes), end(outfixes), [](const OutfixInfo &outfix) {
+ return outfix.is_nonempty_mpv();
+ });
+
+ if (!has_mpv) {
+ DEBUG_PRINTF("no mpv\n");
+ return false;
+ }
+
+ if (isSingleOutfix(build)) {
+ DEBUG_PRINTF("single outfix\n");
+ return false;
+ }
+
+ return true;
+}
+
+static
+void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
+ u32 anchorStateSize, u32 activeArrayCount,
+ u32 activeLeftCount, u32 laggedRoseCount,
+ u32 longLitStreamStateRequired, u32 historyRequired,
+ RoseStateOffsets *so) {
+ u32 curr_offset = 0;
+
+ // First, runtime status (stores per-stream state, like whether we need a
+ // delay rebuild or have been told to halt matching.)
+ curr_offset += sizeof(u8);
+
+ // Role state storage.
+ curr_offset += mmbit_size(rolesWithStateCount);
+
so->activeLeafArray = curr_offset; /* TODO: limit size of array */
curr_offset += mmbit_size(activeArrayCount);
- so->activeLeafArray_size = mmbit_size(activeArrayCount);
+ so->activeLeafArray_size = mmbit_size(activeArrayCount);
so->activeLeftArray = curr_offset; /* TODO: limit size of array */
- curr_offset += mmbit_size(activeLeftCount);
+ curr_offset += mmbit_size(activeLeftCount);
so->activeLeftArray_size = mmbit_size(activeLeftCount);
- so->longLitState = curr_offset;
- curr_offset += longLitStreamStateRequired;
- so->longLitState_size = longLitStreamStateRequired;
+ so->longLitState = curr_offset;
+ curr_offset += longLitStreamStateRequired;
+ so->longLitState_size = longLitStreamStateRequired;
// ONE WHOLE BYTE for each active leftfix with lag.
so->leftfixLagTable = curr_offset;
@@ -413,7 +413,7 @@ void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
curr_offset += anchorStateSize;
so->groups = curr_offset;
- so->groups_size = (build.group_end + 7) / 8;
+ so->groups_size = (build.group_end + 7) / 8;
assert(so->groups_size <= sizeof(u64a));
curr_offset += so->groups_size;
@@ -421,10 +421,10 @@ void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
so->history = curr_offset;
curr_offset += historyRequired;
- // Exhaustion multibit.
+ // Exhaustion multibit.
so->exhausted = curr_offset;
- curr_offset += mmbit_size(build.rm.numEkeys());
- so->exhausted_size = mmbit_size(build.rm.numEkeys());
+ curr_offset += mmbit_size(build.rm.numEkeys());
+ so->exhausted_size = mmbit_size(build.rm.numEkeys());
// Logical multibit.
so->logicalVec = curr_offset;
@@ -438,20 +438,20 @@ void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
curr_offset += so->combVec_size;
// SOM locations and valid/writeable multibit structures.
- if (build.ssm.numSomSlots()) {
- const u32 somWidth = build.ssm.somPrecision();
+ if (build.ssm.numSomSlots()) {
+ const u32 somWidth = build.ssm.somPrecision();
if (somWidth) { // somWidth is zero in block mode.
curr_offset = ROUNDUP_N(curr_offset, somWidth);
so->somLocation = curr_offset;
- curr_offset += build.ssm.numSomSlots() * somWidth;
+ curr_offset += build.ssm.numSomSlots() * somWidth;
} else {
so->somLocation = 0;
}
so->somValid = curr_offset;
- curr_offset += mmbit_size(build.ssm.numSomSlots());
+ curr_offset += mmbit_size(build.ssm.numSomSlots());
so->somWritable = curr_offset;
- curr_offset += mmbit_size(build.ssm.numSomSlots());
- so->somMultibit_size = mmbit_size(build.ssm.numSomSlots());
+ curr_offset += mmbit_size(build.ssm.numSomSlots());
+ so->somMultibit_size = mmbit_size(build.ssm.numSomSlots());
} else {
// No SOM handling, avoid growing the stream state any further.
so->somLocation = 0;
@@ -460,16 +460,16 @@ void fillStateOffsets(const RoseBuildImpl &build, u32 rolesWithStateCount,
}
// note: state space for mask nfas is allocated later
- so->nfaStateBegin = curr_offset;
+ so->nfaStateBegin = curr_offset;
so->end = curr_offset;
}
// Get the mask of initial vertices due to root and anchored_root.
rose_group RoseBuildImpl::getInitialGroups() const {
- rose_group groups = getSuccGroups(root)
- | getSuccGroups(anchored_root)
- | boundary_group_mask;
-
+ rose_group groups = getSuccGroups(root)
+ | getSuccGroups(anchored_root)
+ | boundary_group_mask;
+
DEBUG_PRINTF("initial groups = %016llx\n", groups);
return groups;
}
@@ -486,7 +486,7 @@ bool nfaStuckOn(const NGHolder &g) {
set<u32> done_tops;
for (const auto &e : out_edges_range(g.start, g)) {
- insert(&tops, g[e].tops);
+ insert(&tops, g[e].tops);
if (!g[target(e, g)].char_reach.all()) {
continue;
}
@@ -495,7 +495,7 @@ bool nfaStuckOn(const NGHolder &g) {
insert(&asucc, adjacent_vertices(target(e, g), g));
if (asucc == succ) {
- insert(&done_tops, g[e].tops);
+ insert(&done_tops, g[e].tops);
}
}
@@ -553,26 +553,26 @@ void findFixedDepthTops(const RoseGraph &g, const set<PredTopPair> &triggers,
* engine.
*/
static
-bytecode_ptr<NFA> pickImpl(bytecode_ptr<NFA> dfa_impl,
+bytecode_ptr<NFA> pickImpl(bytecode_ptr<NFA> dfa_impl,
bytecode_ptr<NFA> nfa_impl,
bool fast_nfa) {
assert(nfa_impl);
assert(dfa_impl);
- assert(isDfaType(dfa_impl->type));
+ assert(isDfaType(dfa_impl->type));
// If our NFA is an LBR, it always wins.
if (isLbrType(nfa_impl->type)) {
return nfa_impl;
}
- // if our DFA is an accelerated Sheng, it always wins.
- if (isShengType(dfa_impl->type) && has_accel(*dfa_impl)) {
- return dfa_impl;
- }
-
+ // if our DFA is an accelerated Sheng, it always wins.
+ if (isShengType(dfa_impl->type) && has_accel(*dfa_impl)) {
+ return dfa_impl;
+ }
+
bool d_accel = has_accel(*dfa_impl);
bool n_accel = has_accel(*nfa_impl);
- bool d_big = isBigDfaType(dfa_impl->type);
+ bool d_big = isBigDfaType(dfa_impl->type);
bool n_vsmall = nfa_impl->nPositions <= 32;
bool n_br = has_bounded_repeats(*nfa_impl);
DEBUG_PRINTF("da %d na %d db %d nvs %d nbr %d\n", (int)d_accel,
@@ -607,33 +607,33 @@ bytecode_ptr<NFA> pickImpl(bytecode_ptr<NFA> dfa_impl,
* otherwise a Castle.
*/
static
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
buildRepeatEngine(const CastleProto &proto,
const map<u32, vector<vector<CharReach>>> &triggers,
- const CompileContext &cc, const ReportManager &rm) {
+ const CompileContext &cc, const ReportManager &rm) {
// If we only have one repeat, the LBR should always be the best possible
// implementation.
if (proto.repeats.size() == 1 && cc.grey.allowLbr) {
- return constructLBR(proto, triggers.at(0), cc, rm);
+ return constructLBR(proto, triggers.at(0), cc, rm);
}
- auto castle_nfa = buildCastle(proto, triggers, cc, rm);
+ auto castle_nfa = buildCastle(proto, triggers, cc, rm);
assert(castle_nfa); // Should always be constructible.
return castle_nfa;
}
-static
-bytecode_ptr<NFA> getDfa(raw_dfa &rdfa, bool is_transient,
- const CompileContext &cc, const ReportManager &rm) {
- // Unleash the Sheng!!
- auto dfa = shengCompile(rdfa, cc, rm, false);
- if (!dfa && !is_transient) {
- // Sheng wasn't successful, so unleash McClellan!
- /* We don't try the hybrid for transient prefixes due to the extra
- * bytecode and that they are usually run on small blocks */
- dfa = mcshengCompile(rdfa, cc, rm);
- }
- if (!dfa) {
+static
+bytecode_ptr<NFA> getDfa(raw_dfa &rdfa, bool is_transient,
+ const CompileContext &cc, const ReportManager &rm) {
+ // Unleash the Sheng!!
+ auto dfa = shengCompile(rdfa, cc, rm, false);
+ if (!dfa && !is_transient) {
+ // Sheng wasn't successful, so unleash McClellan!
+ /* We don't try the hybrid for transient prefixes due to the extra
+ * bytecode and that they are usually run on small blocks */
+ dfa = mcshengCompile(rdfa, cc, rm);
+ }
+ if (!dfa) {
dfa = sheng32Compile(rdfa, cc, rm, false);
}
if (!dfa) {
@@ -643,33 +643,33 @@ bytecode_ptr<NFA> getDfa(raw_dfa &rdfa, bool is_transient,
dfa = mcshengCompile64(rdfa, cc, rm);
}
if (!dfa) {
- // Sheng wasn't successful, so unleash McClellan!
- dfa = mcclellanCompile(rdfa, cc, rm, false);
- }
- return dfa;
-}
-
+ // Sheng wasn't successful, so unleash McClellan!
+ dfa = mcclellanCompile(rdfa, cc, rm, false);
+ }
+ return dfa;
+}
+
/* builds suffix nfas */
static
-bytecode_ptr<NFA>
+bytecode_ptr<NFA>
buildSuffix(const ReportManager &rm, const SomSlotManager &ssm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
suffix_id suff, const CompileContext &cc) {
if (suff.castle()) {
- auto n = buildRepeatEngine(*suff.castle(), triggers, cc, rm);
+ auto n = buildRepeatEngine(*suff.castle(), triggers, cc, rm);
assert(n);
return n;
}
if (suff.haig()) {
- auto n = goughCompile(*suff.haig(), ssm.somPrecision(), cc, rm);
+ auto n = goughCompile(*suff.haig(), ssm.somPrecision(), cc, rm);
assert(n);
return n;
}
if (suff.dfa()) {
- auto d = getDfa(*suff.dfa(), false, cc, rm);
+ auto d = getDfa(*suff.dfa(), false, cc, rm);
assert(d);
return d;
}
@@ -682,7 +682,7 @@ buildSuffix(const ReportManager &rm, const SomSlotManager &ssm,
// Take a shot at the LBR engine.
if (oneTop) {
- auto lbr = constructLBR(holder, triggers.at(0), cc, rm);
+ auto lbr = constructLBR(holder, triggers.at(0), cc, rm);
if (lbr) {
return lbr;
}
@@ -699,7 +699,7 @@ buildSuffix(const ReportManager &rm, const SomSlotManager &ssm,
auto rdfa = buildMcClellan(holder, &rm, false, triggers.at(0),
cc.grey);
if (rdfa) {
- auto d = getDfa(*rdfa, false, cc, rm);
+ auto d = getDfa(*rdfa, false, cc, rm);
assert(d);
if (cc.grey.roseMcClellanSuffix != 2) {
n = pickImpl(move(d), move(n), fast_nfa);
@@ -774,29 +774,29 @@ void findTriggerSequences(const RoseBuildImpl &tbi,
const u32 top = e.first;
const set<u32> &lit_ids = e.second;
- for (u32 id : lit_ids) {
- const rose_literal_id &lit = tbi.literals.at(id);
+ for (u32 id : lit_ids) {
+ const rose_literal_id &lit = tbi.literals.at(id);
(*trigger_lits)[top].push_back(as_cr_seq(lit));
}
}
}
-static
-bytecode_ptr<NFA> makeLeftNfa(const RoseBuildImpl &tbi, left_id &left,
- const bool is_prefix, const bool is_transient,
- const map<left_id, set<PredTopPair>> &infixTriggers,
- const CompileContext &cc) {
- const ReportManager &rm = tbi.rm;
+static
+bytecode_ptr<NFA> makeLeftNfa(const RoseBuildImpl &tbi, left_id &left,
+ const bool is_prefix, const bool is_transient,
+ const map<left_id, set<PredTopPair>> &infixTriggers,
+ const CompileContext &cc) {
+ const ReportManager &rm = tbi.rm;
+
+ bytecode_ptr<NFA> n;
- bytecode_ptr<NFA> n;
-
// Should compress state if this rose is non-transient and we're in
// streaming mode.
const bool compress_state = !is_transient;
- assert(is_prefix || !left.graph() || left.graph()->kind == NFA_INFIX);
- assert(!is_prefix || !left.graph() || left.graph()->kind == NFA_PREFIX
- || left.graph()->kind == NFA_EAGER_PREFIX);
+ assert(is_prefix || !left.graph() || left.graph()->kind == NFA_INFIX);
+ assert(!is_prefix || !left.graph() || left.graph()->kind == NFA_PREFIX
+ || left.graph()->kind == NFA_EAGER_PREFIX);
// Holder should be implementable as an NFA at the very least.
if (!left.dfa() && left.graph()) {
@@ -813,19 +813,19 @@ bytecode_ptr<NFA> makeLeftNfa(const RoseBuildImpl &tbi, left_id &left,
assert(!is_prefix);
map<u32, vector<vector<CharReach> > > triggers;
findTriggerSequences(tbi, infixTriggers.at(left), &triggers);
- n = buildRepeatEngine(*left.castle(), triggers, cc, rm);
+ n = buildRepeatEngine(*left.castle(), triggers, cc, rm);
assert(n);
return n; // Castles/LBRs are always best!
}
if (left.dfa()) {
- n = getDfa(*left.dfa(), is_transient, cc, rm);
+ n = getDfa(*left.dfa(), is_transient, cc, rm);
} else if (left.graph() && cc.grey.roseMcClellanPrefix == 2 && is_prefix &&
!is_transient) {
auto rdfa = buildMcClellan(*left.graph(), nullptr, cc.grey);
if (rdfa) {
- n = getDfa(*rdfa, is_transient, cc, rm);
- assert(n);
+ n = getDfa(*rdfa, is_transient, cc, rm);
+ assert(n);
}
}
@@ -833,16 +833,16 @@ bytecode_ptr<NFA> makeLeftNfa(const RoseBuildImpl &tbi, left_id &left,
if (!n && !is_prefix && left.graph() && onlyOneTop(*left.graph())) {
map<u32, vector<vector<CharReach> > > triggers;
findTriggerSequences(tbi, infixTriggers.at(left), &triggers);
- assert(triggers.size() == 1); // single top
- n = constructLBR(*left.graph(), triggers.begin()->second, cc, rm);
+ assert(triggers.size() == 1); // single top
+ n = constructLBR(*left.graph(), triggers.begin()->second, cc, rm);
}
bool fast_nfa = false;
if (!n && left.graph()) {
map<u32, vector<vector<CharReach>>> triggers;
- if (left.graph()->kind == NFA_INFIX) {
- findTriggerSequences(tbi, infixTriggers.at(left), &triggers);
- }
+ if (left.graph()->kind == NFA_INFIX) {
+ findTriggerSequences(tbi, infixTriggers.at(left), &triggers);
+ }
n = constructNFA(*left.graph(), nullptr, fixed_depth_tops, triggers,
compress_state, fast_nfa, cc);
}
@@ -852,7 +852,7 @@ bytecode_ptr<NFA> makeLeftNfa(const RoseBuildImpl &tbi, left_id &left,
&& (!n || !has_bounded_repeats_other_than_firsts(*n) || !fast_nfa)) {
auto rdfa = buildMcClellan(*left.graph(), nullptr, cc.grey);
if (rdfa) {
- auto d = getDfa(*rdfa, is_transient, cc, rm);
+ auto d = getDfa(*rdfa, is_transient, cc, rm);
assert(d);
n = pickImpl(move(d), move(n), fast_nfa);
}
@@ -879,709 +879,709 @@ void setLeftNfaProperties(NFA &n, const left_id &left) {
}
static
-void appendTailToHolder(NGHolder &h, const flat_set<ReportID> &reports,
- const vector<NFAVertex> &starts,
- const vector<CharReach> &tail) {
- assert(!tail.empty());
- NFAVertex curr = add_vertex(h);
- for (NFAVertex v : starts) {
- assert(!edge(v, h.acceptEod, h).second);
- assert(h[v].reports == reports);
- h[v].reports.clear();
- remove_edge(v, h.accept, h);
- add_edge(v, curr, h);
- }
- auto it = tail.begin();
- h[curr].char_reach = *it;
- ++it;
- while (it != tail.end()) {
- NFAVertex old = curr;
- curr = add_vertex(h);
- add_edge(old, curr, h);
- assert(!it->none());
- h[curr].char_reach = *it;
- ++it;
- }
-
- h[curr].reports = reports;
- add_edge(curr, h.accept, h);
-}
-
-static
-void appendTailToHolder(NGHolder &h, const vector<CharReach> &tail) {
- assert(in_degree(h.acceptEod, h) == 1);
- assert(!tail.empty());
-
- map<flat_set<ReportID>, vector<NFAVertex> > reporters;
- for (auto v : inv_adjacent_vertices_range(h.accept, h)) {
- reporters[h[v].reports].push_back(v);
- }
-
- for (const auto &e : reporters) {
- appendTailToHolder(h, e.first, e.second, tail);
- }
-
- renumber_edges(h);
-}
-
-static
-u32 decreaseLag(const RoseBuildImpl &build, NGHolder &h,
- const vector<RoseVertex> &succs) {
- const RoseGraph &rg = build.g;
- static const size_t MAX_RESTORE_LEN = 5;
-
- vector<CharReach> restored(MAX_RESTORE_LEN);
- for (RoseVertex v : succs) {
- u32 lag = rg[v].left.lag;
- for (u32 lit_id : rg[v].literals) {
- u32 delay = build.literals.at(lit_id).delay;
- const ue2_literal &literal = build.literals.at(lit_id).s;
- assert(lag <= literal.length() + delay);
- size_t base = literal.length() + delay - lag;
- if (base >= literal.length()) {
- return 0;
- }
- size_t len = literal.length() - base;
- len = MIN(len, restored.size());
- restored.resize(len);
- auto lit_it = literal.begin() + base;
- for (u32 i = 0; i < len; i++) {
- assert(lit_it != literal.end());
- restored[i] |= *lit_it;
- ++lit_it;
- }
- }
- }
-
- assert(!restored.empty());
-
- appendTailToHolder(h, restored);
-
- return restored.size();
-}
-
-#define EAGER_DIE_BEFORE_LIMIT 10
-
-struct eager_info {
- shared_ptr<NGHolder> new_graph;
- u32 lag_adjust = 0;
-};
-
-static
-bool checkSuitableForEager(bool is_prefix, const left_id &left,
- const RoseBuildImpl &build,
- const vector<RoseVertex> &succs,
- rose_group squash_mask, rose_group initial_groups,
- eager_info &ei, const CompileContext &cc) {
- DEBUG_PRINTF("checking prefix --> %016llx...\n", squash_mask);
-
- const RoseGraph &rg = build.g;
-
- if (!is_prefix) {
- DEBUG_PRINTF("not prefix\n");
- return false; /* only prefixes (for now...) */
- }
-
- if ((initial_groups & squash_mask) == initial_groups) {
- DEBUG_PRINTF("no squash -- useless\n");
- return false;
- }
-
- for (RoseVertex s : succs) {
- if (build.isInETable(s)
- || contains(rg[s].literals, build.eod_event_literal_id)) {
- return false; /* Ignore EOD related prefixes */
- }
- }
-
- if (left.dfa()) {
- const raw_dfa &dfa = *left.dfa();
- if (dfa.start_floating != DEAD_STATE) {
- return false; /* not purely anchored */
- }
- if (!dfa.states[dfa.start_anchored].reports.empty()) {
- return false; /* vacuous (todo: handle?) */
- }
-
- if (!can_die_early(dfa, EAGER_DIE_BEFORE_LIMIT)) {
- return false;
- }
- ei.new_graph = rg[succs[0]].left.graph;
- } else if (left.graph()) {
- const NGHolder &g = *left.graph();
- if (proper_out_degree(g.startDs, g)) {
- return false; /* not purely anchored */
- }
-
- ei.new_graph = cloneHolder(*left.graph());
- auto gg = ei.new_graph;
- gg->kind = NFA_EAGER_PREFIX;
-
- ei.lag_adjust = decreaseLag(build, *gg, succs);
-
- if (is_match_vertex(gg->start, *gg)) {
- return false; /* should not still be vacuous as lag decreased */
- }
-
- if (!can_die_early(*gg, EAGER_DIE_BEFORE_LIMIT)) {
- DEBUG_PRINTF("not eager as stuck alive\n");
- return false;
- }
-
- /* We need to ensure that adding in the literals does not cause us to no
- * longer be able to build an nfa. */
- bool ok = isImplementableNFA(*gg, nullptr, cc);
- if (!ok) {
- return false;
- }
- } else {
- DEBUG_PRINTF("unable to determine if good for eager running\n");
- return false;
- }
-
- DEBUG_PRINTF("eager prefix\n");
- return true;
-}
-
-static
-left_id updateLeftfixWithEager(RoseGraph &g, const eager_info &ei,
- const vector<RoseVertex> &succs) {
- u32 lag_adjust = ei.lag_adjust;
- auto gg = ei.new_graph;
- for (RoseVertex v : succs) {
- g[v].left.graph = gg;
- assert(g[v].left.lag >= lag_adjust);
- g[v].left.lag -= lag_adjust;
- DEBUG_PRINTF("added %u literal chars back, new lag %u\n", lag_adjust,
- g[v].left.lag);
- }
- left_id leftfix = g[succs[0]].left;
-
- if (leftfix.graph()) {
- assert(leftfix.graph()->kind == NFA_PREFIX
- || leftfix.graph()->kind == NFA_EAGER_PREFIX);
- leftfix.graph()->kind = NFA_EAGER_PREFIX;
- }
- if (leftfix.dfa()) {
- assert(leftfix.dfa()->kind == NFA_PREFIX);
- leftfix.dfa()->kind = NFA_EAGER_PREFIX;
- }
-
- return leftfix;
-}
-
-static
-void enforceEngineSizeLimit(const NFA *n, const Grey &grey) {
- const size_t nfa_size = n->length;
- // Global limit.
- if (nfa_size > grey.limitEngineSize) {
- throw ResourceLimitError();
- }
-
- // Type-specific limit checks follow.
-
- if (isDfaType(n->type)) {
- if (nfa_size > grey.limitDFASize) {
- throw ResourceLimitError();
- }
- } else if (isNfaType(n->type)) {
- if (nfa_size > grey.limitNFASize) {
- throw ResourceLimitError();
- }
- } else if (isLbrType(n->type)) {
- if (nfa_size > grey.limitLBRSize) {
- throw ResourceLimitError();
- }
- }
-}
-
-static
-bool buildLeftfix(RoseBuildImpl &build, build_context &bc, bool prefix, u32 qi,
- const map<left_id, set<PredTopPair> > &infixTriggers,
- set<u32> *no_retrigger_queues, set<u32> *eager_queues,
- const map<left_id, eager_info> &eager,
- const vector<RoseVertex> &succs, left_id leftfix) {
- RoseGraph &g = build.g;
- const CompileContext &cc = build.cc;
- const ReportManager &rm = build.rm;
-
- bool is_transient = contains(build.transient, leftfix);
- rose_group squash_mask = build.rose_squash_masks.at(leftfix);
-
- DEBUG_PRINTF("making %sleftfix\n", is_transient ? "transient " : "");
-
- if (contains(eager, leftfix)) {
- eager_queues->insert(qi);
- leftfix = updateLeftfixWithEager(g, eager.at(leftfix), succs);
- }
-
- bytecode_ptr<NFA> nfa;
- // Need to build NFA, which is either predestined to be a Haig (in SOM mode)
- // or could be all manner of things.
- if (leftfix.haig()) {
- nfa = goughCompile(*leftfix.haig(), build.ssm.somPrecision(), cc, rm);
- } else {
- nfa = makeLeftNfa(build, leftfix, prefix, is_transient, infixTriggers,
- cc);
- }
-
- if (!nfa) {
- assert(!"failed to build leftfix");
- return false;
- }
-
- setLeftNfaProperties(*nfa, leftfix);
-
- nfa->queueIndex = qi;
- enforceEngineSizeLimit(nfa.get(), cc.grey);
- bc.engine_info_by_queue.emplace(nfa->queueIndex,
- engine_info(nfa.get(), is_transient));
-
- if (!prefix && !leftfix.haig() && leftfix.graph()
- && nfaStuckOn(*leftfix.graph())) {
- DEBUG_PRINTF("%u sticks on\n", qi);
- no_retrigger_queues->insert(qi);
- }
-
- DEBUG_PRINTF("built leftfix, qi=%u\n", qi);
- add_nfa_to_blob(bc, *nfa);
-
- // Leftfixes can have stop alphabets.
- vector<u8> stop(N_CHARS, 0);
- /* haigs track som information - need more care */
- som_type som = leftfix.haig() ? SOM_LEFT : SOM_NONE;
- if (leftfix.graph()) {
- stop = findLeftOffsetStopAlphabet(*leftfix.graph(), som);
- } else if (leftfix.castle()) {
- stop = findLeftOffsetStopAlphabet(*leftfix.castle(), som);
- }
-
- // Infix NFAs can have bounds on their queue lengths.
- u32 max_queuelen = UINT32_MAX;
- if (!prefix) {
- set<ue2_literal> lits;
- for (RoseVertex v : succs) {
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- for (u32 lit_id : g[u].literals) {
- lits.insert(build.literals.at(lit_id).s);
- }
+void appendTailToHolder(NGHolder &h, const flat_set<ReportID> &reports,
+ const vector<NFAVertex> &starts,
+ const vector<CharReach> &tail) {
+ assert(!tail.empty());
+ NFAVertex curr = add_vertex(h);
+ for (NFAVertex v : starts) {
+ assert(!edge(v, h.acceptEod, h).second);
+ assert(h[v].reports == reports);
+ h[v].reports.clear();
+ remove_edge(v, h.accept, h);
+ add_edge(v, curr, h);
+ }
+ auto it = tail.begin();
+ h[curr].char_reach = *it;
+ ++it;
+ while (it != tail.end()) {
+ NFAVertex old = curr;
+ curr = add_vertex(h);
+ add_edge(old, curr, h);
+ assert(!it->none());
+ h[curr].char_reach = *it;
+ ++it;
+ }
+
+ h[curr].reports = reports;
+ add_edge(curr, h.accept, h);
+}
+
+static
+void appendTailToHolder(NGHolder &h, const vector<CharReach> &tail) {
+ assert(in_degree(h.acceptEod, h) == 1);
+ assert(!tail.empty());
+
+ map<flat_set<ReportID>, vector<NFAVertex> > reporters;
+ for (auto v : inv_adjacent_vertices_range(h.accept, h)) {
+ reporters[h[v].reports].push_back(v);
+ }
+
+ for (const auto &e : reporters) {
+ appendTailToHolder(h, e.first, e.second, tail);
+ }
+
+ renumber_edges(h);
+}
+
+static
+u32 decreaseLag(const RoseBuildImpl &build, NGHolder &h,
+ const vector<RoseVertex> &succs) {
+ const RoseGraph &rg = build.g;
+ static const size_t MAX_RESTORE_LEN = 5;
+
+ vector<CharReach> restored(MAX_RESTORE_LEN);
+ for (RoseVertex v : succs) {
+ u32 lag = rg[v].left.lag;
+ for (u32 lit_id : rg[v].literals) {
+ u32 delay = build.literals.at(lit_id).delay;
+ const ue2_literal &literal = build.literals.at(lit_id).s;
+ assert(lag <= literal.length() + delay);
+ size_t base = literal.length() + delay - lag;
+ if (base >= literal.length()) {
+ return 0;
+ }
+ size_t len = literal.length() - base;
+ len = MIN(len, restored.size());
+ restored.resize(len);
+ auto lit_it = literal.begin() + base;
+ for (u32 i = 0; i < len; i++) {
+ assert(lit_it != literal.end());
+ restored[i] |= *lit_it;
+ ++lit_it;
+ }
+ }
+ }
+
+ assert(!restored.empty());
+
+ appendTailToHolder(h, restored);
+
+ return restored.size();
+}
+
+#define EAGER_DIE_BEFORE_LIMIT 10
+
+struct eager_info {
+ shared_ptr<NGHolder> new_graph;
+ u32 lag_adjust = 0;
+};
+
+static
+bool checkSuitableForEager(bool is_prefix, const left_id &left,
+ const RoseBuildImpl &build,
+ const vector<RoseVertex> &succs,
+ rose_group squash_mask, rose_group initial_groups,
+ eager_info &ei, const CompileContext &cc) {
+ DEBUG_PRINTF("checking prefix --> %016llx...\n", squash_mask);
+
+ const RoseGraph &rg = build.g;
+
+ if (!is_prefix) {
+ DEBUG_PRINTF("not prefix\n");
+ return false; /* only prefixes (for now...) */
+ }
+
+ if ((initial_groups & squash_mask) == initial_groups) {
+ DEBUG_PRINTF("no squash -- useless\n");
+ return false;
+ }
+
+ for (RoseVertex s : succs) {
+ if (build.isInETable(s)
+ || contains(rg[s].literals, build.eod_event_literal_id)) {
+ return false; /* Ignore EOD related prefixes */
+ }
+ }
+
+ if (left.dfa()) {
+ const raw_dfa &dfa = *left.dfa();
+ if (dfa.start_floating != DEAD_STATE) {
+ return false; /* not purely anchored */
+ }
+ if (!dfa.states[dfa.start_anchored].reports.empty()) {
+ return false; /* vacuous (todo: handle?) */
+ }
+
+ if (!can_die_early(dfa, EAGER_DIE_BEFORE_LIMIT)) {
+ return false;
+ }
+ ei.new_graph = rg[succs[0]].left.graph;
+ } else if (left.graph()) {
+ const NGHolder &g = *left.graph();
+ if (proper_out_degree(g.startDs, g)) {
+ return false; /* not purely anchored */
+ }
+
+ ei.new_graph = cloneHolder(*left.graph());
+ auto gg = ei.new_graph;
+ gg->kind = NFA_EAGER_PREFIX;
+
+ ei.lag_adjust = decreaseLag(build, *gg, succs);
+
+ if (is_match_vertex(gg->start, *gg)) {
+ return false; /* should not still be vacuous as lag decreased */
+ }
+
+ if (!can_die_early(*gg, EAGER_DIE_BEFORE_LIMIT)) {
+ DEBUG_PRINTF("not eager as stuck alive\n");
+ return false;
+ }
+
+ /* We need to ensure that adding in the literals does not cause us to no
+ * longer be able to build an nfa. */
+ bool ok = isImplementableNFA(*gg, nullptr, cc);
+ if (!ok) {
+ return false;
+ }
+ } else {
+ DEBUG_PRINTF("unable to determine if good for eager running\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("eager prefix\n");
+ return true;
+}
+
+static
+left_id updateLeftfixWithEager(RoseGraph &g, const eager_info &ei,
+ const vector<RoseVertex> &succs) {
+ u32 lag_adjust = ei.lag_adjust;
+ auto gg = ei.new_graph;
+ for (RoseVertex v : succs) {
+ g[v].left.graph = gg;
+ assert(g[v].left.lag >= lag_adjust);
+ g[v].left.lag -= lag_adjust;
+ DEBUG_PRINTF("added %u literal chars back, new lag %u\n", lag_adjust,
+ g[v].left.lag);
+ }
+ left_id leftfix = g[succs[0]].left;
+
+ if (leftfix.graph()) {
+ assert(leftfix.graph()->kind == NFA_PREFIX
+ || leftfix.graph()->kind == NFA_EAGER_PREFIX);
+ leftfix.graph()->kind = NFA_EAGER_PREFIX;
+ }
+ if (leftfix.dfa()) {
+ assert(leftfix.dfa()->kind == NFA_PREFIX);
+ leftfix.dfa()->kind = NFA_EAGER_PREFIX;
+ }
+
+ return leftfix;
+}
+
+static
+void enforceEngineSizeLimit(const NFA *n, const Grey &grey) {
+ const size_t nfa_size = n->length;
+ // Global limit.
+ if (nfa_size > grey.limitEngineSize) {
+ throw ResourceLimitError();
+ }
+
+ // Type-specific limit checks follow.
+
+ if (isDfaType(n->type)) {
+ if (nfa_size > grey.limitDFASize) {
+ throw ResourceLimitError();
+ }
+ } else if (isNfaType(n->type)) {
+ if (nfa_size > grey.limitNFASize) {
+ throw ResourceLimitError();
+ }
+ } else if (isLbrType(n->type)) {
+ if (nfa_size > grey.limitLBRSize) {
+ throw ResourceLimitError();
+ }
+ }
+}
+
+static
+bool buildLeftfix(RoseBuildImpl &build, build_context &bc, bool prefix, u32 qi,
+ const map<left_id, set<PredTopPair> > &infixTriggers,
+ set<u32> *no_retrigger_queues, set<u32> *eager_queues,
+ const map<left_id, eager_info> &eager,
+ const vector<RoseVertex> &succs, left_id leftfix) {
+ RoseGraph &g = build.g;
+ const CompileContext &cc = build.cc;
+ const ReportManager &rm = build.rm;
+
+ bool is_transient = contains(build.transient, leftfix);
+ rose_group squash_mask = build.rose_squash_masks.at(leftfix);
+
+ DEBUG_PRINTF("making %sleftfix\n", is_transient ? "transient " : "");
+
+ if (contains(eager, leftfix)) {
+ eager_queues->insert(qi);
+ leftfix = updateLeftfixWithEager(g, eager.at(leftfix), succs);
+ }
+
+ bytecode_ptr<NFA> nfa;
+ // Need to build NFA, which is either predestined to be a Haig (in SOM mode)
+ // or could be all manner of things.
+ if (leftfix.haig()) {
+ nfa = goughCompile(*leftfix.haig(), build.ssm.somPrecision(), cc, rm);
+ } else {
+ nfa = makeLeftNfa(build, leftfix, prefix, is_transient, infixTriggers,
+ cc);
+ }
+
+ if (!nfa) {
+ assert(!"failed to build leftfix");
+ return false;
+ }
+
+ setLeftNfaProperties(*nfa, leftfix);
+
+ nfa->queueIndex = qi;
+ enforceEngineSizeLimit(nfa.get(), cc.grey);
+ bc.engine_info_by_queue.emplace(nfa->queueIndex,
+ engine_info(nfa.get(), is_transient));
+
+ if (!prefix && !leftfix.haig() && leftfix.graph()
+ && nfaStuckOn(*leftfix.graph())) {
+ DEBUG_PRINTF("%u sticks on\n", qi);
+ no_retrigger_queues->insert(qi);
+ }
+
+ DEBUG_PRINTF("built leftfix, qi=%u\n", qi);
+ add_nfa_to_blob(bc, *nfa);
+
+ // Leftfixes can have stop alphabets.
+ vector<u8> stop(N_CHARS, 0);
+ /* haigs track som information - need more care */
+ som_type som = leftfix.haig() ? SOM_LEFT : SOM_NONE;
+ if (leftfix.graph()) {
+ stop = findLeftOffsetStopAlphabet(*leftfix.graph(), som);
+ } else if (leftfix.castle()) {
+ stop = findLeftOffsetStopAlphabet(*leftfix.castle(), som);
+ }
+
+ // Infix NFAs can have bounds on their queue lengths.
+ u32 max_queuelen = UINT32_MAX;
+ if (!prefix) {
+ set<ue2_literal> lits;
+ for (RoseVertex v : succs) {
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ for (u32 lit_id : g[u].literals) {
+ lits.insert(build.literals.at(lit_id).s);
+ }
}
}
- DEBUG_PRINTF("%zu literals\n", lits.size());
- max_queuelen = findMaxInfixMatches(leftfix, lits);
- if (max_queuelen < UINT32_MAX) {
- max_queuelen++;
- }
- }
-
- u32 max_width;
- if (is_transient) {
- depth d = findMaxWidth(leftfix);
- assert(d.is_finite());
- max_width = d;
- } else {
- max_width = 0;
- }
-
- u8 cm_count = 0;
- CharReach cm_cr;
- if (cc.grey.allowCountingMiracles) {
- findCountingMiracleInfo(leftfix, stop, &cm_count, &cm_cr);
- }
-
- for (RoseVertex v : succs) {
- bc.leftfix_info.emplace(v, left_build_info(qi, g[v].left.lag, max_width,
- squash_mask, stop,
- max_queuelen, cm_count,
- cm_cr));
- }
-
- return true;
-}
-
-static
-unique_ptr<TamaInfo> constructTamaInfo(const RoseGraph &g,
- const vector<ExclusiveSubengine> &subengines,
- const bool is_suffix) {
- unique_ptr<TamaInfo> tamaInfo = ue2::make_unique<TamaInfo>();
- for (const auto &sub : subengines) {
- const auto &rose_vertices = sub.vertices;
- NFA *nfa = sub.nfa.get();
- set<u32> tops;
- for (const auto &v : rose_vertices) {
- if (is_suffix) {
- tops.insert(g[v].suffix.top);
- } else {
- for (const auto &e : in_edges_range(v, g)) {
- tops.insert(g[e].rose_top);
- }
+ DEBUG_PRINTF("%zu literals\n", lits.size());
+ max_queuelen = findMaxInfixMatches(leftfix, lits);
+ if (max_queuelen < UINT32_MAX) {
+ max_queuelen++;
+ }
+ }
+
+ u32 max_width;
+ if (is_transient) {
+ depth d = findMaxWidth(leftfix);
+ assert(d.is_finite());
+ max_width = d;
+ } else {
+ max_width = 0;
+ }
+
+ u8 cm_count = 0;
+ CharReach cm_cr;
+ if (cc.grey.allowCountingMiracles) {
+ findCountingMiracleInfo(leftfix, stop, &cm_count, &cm_cr);
+ }
+
+ for (RoseVertex v : succs) {
+ bc.leftfix_info.emplace(v, left_build_info(qi, g[v].left.lag, max_width,
+ squash_mask, stop,
+ max_queuelen, cm_count,
+ cm_cr));
+ }
+
+ return true;
+}
+
+static
+unique_ptr<TamaInfo> constructTamaInfo(const RoseGraph &g,
+ const vector<ExclusiveSubengine> &subengines,
+ const bool is_suffix) {
+ unique_ptr<TamaInfo> tamaInfo = ue2::make_unique<TamaInfo>();
+ for (const auto &sub : subengines) {
+ const auto &rose_vertices = sub.vertices;
+ NFA *nfa = sub.nfa.get();
+ set<u32> tops;
+ for (const auto &v : rose_vertices) {
+ if (is_suffix) {
+ tops.insert(g[v].suffix.top);
+ } else {
+ for (const auto &e : in_edges_range(v, g)) {
+ tops.insert(g[e].rose_top);
+ }
+ }
+ }
+ tamaInfo->add(nfa, tops);
+ }
+
+ return tamaInfo;
+}
+
+static
+void updateTops(const RoseGraph &g, const TamaInfo &tamaInfo,
+ TamaProto &tamaProto,
+ const vector<ExclusiveSubengine> &subengines,
+ const map<pair<const NFA *, u32>, u32> &out_top_remap,
+ const bool is_suffix) {
+ u32 i = 0;
+ for (const auto &n : tamaInfo.subengines) {
+ for (const auto &v : subengines[i].vertices) {
+ if (is_suffix) {
+ tamaProto.add(n, g[v].index, g[v].suffix.top, out_top_remap);
+ } else {
+ for (const auto &e : in_edges_range(v, g)) {
+ tamaProto.add(n, g[v].index, g[e].rose_top, out_top_remap);
+ }
}
- }
- tamaInfo->add(nfa, tops);
- }
-
- return tamaInfo;
-}
-
-static
-void updateTops(const RoseGraph &g, const TamaInfo &tamaInfo,
- TamaProto &tamaProto,
- const vector<ExclusiveSubengine> &subengines,
- const map<pair<const NFA *, u32>, u32> &out_top_remap,
- const bool is_suffix) {
- u32 i = 0;
- for (const auto &n : tamaInfo.subengines) {
- for (const auto &v : subengines[i].vertices) {
- if (is_suffix) {
- tamaProto.add(n, g[v].index, g[v].suffix.top, out_top_remap);
- } else {
- for (const auto &e : in_edges_range(v, g)) {
- tamaProto.add(n, g[v].index, g[e].rose_top, out_top_remap);
- }
+ }
+ i++;
+ }
+}
+
+static
+shared_ptr<TamaProto> constructContainerEngine(const RoseGraph &g,
+ build_context &bc,
+ const ExclusiveInfo &info,
+ const u32 queue,
+ const bool is_suffix,
+ const Grey &grey) {
+ const auto &subengines = info.subengines;
+ auto tamaInfo = constructTamaInfo(g, subengines, is_suffix);
+
+ map<pair<const NFA *, u32>, u32> out_top_remap;
+ auto n = buildTamarama(*tamaInfo, queue, out_top_remap);
+ enforceEngineSizeLimit(n.get(), grey);
+ bc.engine_info_by_queue.emplace(n->queueIndex, engine_info(n.get(), false));
+ add_nfa_to_blob(bc, *n);
+
+ DEBUG_PRINTF("queue id:%u\n", queue);
+ shared_ptr<TamaProto> tamaProto = make_shared<TamaProto>();
+ tamaProto->reports = info.reports;
+ updateTops(g, *tamaInfo, *tamaProto, subengines, out_top_remap, is_suffix);
+ return tamaProto;
+}
+
+static
+void buildInfixContainer(RoseGraph &g, build_context &bc,
+ const vector<ExclusiveInfo> &exclusive_info,
+ const Grey &grey) {
+ // Build tamarama engine
+ for (const auto &info : exclusive_info) {
+ const u32 queue = info.queue;
+ const auto &subengines = info.subengines;
+ auto tamaProto =
+ constructContainerEngine(g, bc, info, queue, false, grey);
+
+ for (const auto &sub : subengines) {
+ const auto &verts = sub.vertices;
+ for (const auto &v : verts) {
+ DEBUG_PRINTF("vert id:%zu\n", g[v].index);
+ g[v].left.tamarama = tamaProto;
}
- }
- i++;
- }
-}
-
-static
-shared_ptr<TamaProto> constructContainerEngine(const RoseGraph &g,
- build_context &bc,
- const ExclusiveInfo &info,
- const u32 queue,
- const bool is_suffix,
- const Grey &grey) {
- const auto &subengines = info.subengines;
- auto tamaInfo = constructTamaInfo(g, subengines, is_suffix);
-
- map<pair<const NFA *, u32>, u32> out_top_remap;
- auto n = buildTamarama(*tamaInfo, queue, out_top_remap);
- enforceEngineSizeLimit(n.get(), grey);
- bc.engine_info_by_queue.emplace(n->queueIndex, engine_info(n.get(), false));
- add_nfa_to_blob(bc, *n);
-
- DEBUG_PRINTF("queue id:%u\n", queue);
- shared_ptr<TamaProto> tamaProto = make_shared<TamaProto>();
- tamaProto->reports = info.reports;
- updateTops(g, *tamaInfo, *tamaProto, subengines, out_top_remap, is_suffix);
- return tamaProto;
-}
-
-static
-void buildInfixContainer(RoseGraph &g, build_context &bc,
- const vector<ExclusiveInfo> &exclusive_info,
- const Grey &grey) {
- // Build tamarama engine
- for (const auto &info : exclusive_info) {
- const u32 queue = info.queue;
- const auto &subengines = info.subengines;
- auto tamaProto =
- constructContainerEngine(g, bc, info, queue, false, grey);
-
- for (const auto &sub : subengines) {
- const auto &verts = sub.vertices;
- for (const auto &v : verts) {
- DEBUG_PRINTF("vert id:%zu\n", g[v].index);
- g[v].left.tamarama = tamaProto;
+ }
+ }
+}
+
+static
+void buildSuffixContainer(RoseGraph &g, build_context &bc,
+ const vector<ExclusiveInfo> &exclusive_info,
+ const Grey &grey) {
+ // Build tamarama engine
+ for (const auto &info : exclusive_info) {
+ const u32 queue = info.queue;
+ const auto &subengines = info.subengines;
+ auto tamaProto = constructContainerEngine(g, bc, info, queue, true,
+ grey);
+ for (const auto &sub : subengines) {
+ const auto &verts = sub.vertices;
+ for (const auto &v : verts) {
+ DEBUG_PRINTF("vert id:%zu\n", g[v].index);
+ g[v].suffix.tamarama = tamaProto;
}
- }
- }
-}
-
-static
-void buildSuffixContainer(RoseGraph &g, build_context &bc,
- const vector<ExclusiveInfo> &exclusive_info,
- const Grey &grey) {
- // Build tamarama engine
- for (const auto &info : exclusive_info) {
- const u32 queue = info.queue;
- const auto &subengines = info.subengines;
- auto tamaProto = constructContainerEngine(g, bc, info, queue, true,
- grey);
- for (const auto &sub : subengines) {
- const auto &verts = sub.vertices;
- for (const auto &v : verts) {
- DEBUG_PRINTF("vert id:%zu\n", g[v].index);
- g[v].suffix.tamarama = tamaProto;
- }
- const auto &v = verts[0];
- suffix_id newSuffix(g[v].suffix);
- bc.suffixes.emplace(newSuffix, queue);
- }
- }
-}
-
-static
-void updateExclusiveInfixProperties(const RoseBuildImpl &build,
- const vector<ExclusiveInfo> &exclusive_info,
- map<RoseVertex, left_build_info> &leftfix_info,
- set<u32> *no_retrigger_queues) {
- const RoseGraph &g = build.g;
- for (const auto &info : exclusive_info) {
- // Set leftfix optimisations, disabled for tamarama subengines
- rose_group squash_mask = ~rose_group{0};
+ const auto &v = verts[0];
+ suffix_id newSuffix(g[v].suffix);
+ bc.suffixes.emplace(newSuffix, queue);
+ }
+ }
+}
+
+static
+void updateExclusiveInfixProperties(const RoseBuildImpl &build,
+ const vector<ExclusiveInfo> &exclusive_info,
+ map<RoseVertex, left_build_info> &leftfix_info,
+ set<u32> *no_retrigger_queues) {
+ const RoseGraph &g = build.g;
+ for (const auto &info : exclusive_info) {
+ // Set leftfix optimisations, disabled for tamarama subengines
+ rose_group squash_mask = ~rose_group{0};
// Leftfixes can have stop alphabets.
vector<u8> stop(N_CHARS, 0);
- // Infix NFAs can have bounds on their queue lengths.
- u32 max_queuelen = 0;
- u32 max_width = 0;
- u8 cm_count = 0;
- CharReach cm_cr;
-
- const auto &qi = info.queue;
- const auto &subengines = info.subengines;
- bool no_retrigger = true;
- for (const auto &sub : subengines) {
- const auto &verts = sub.vertices;
- const auto &v_first = verts[0];
- left_id leftfix(g[v_first].left);
- if (leftfix.haig() || !leftfix.graph() ||
- !nfaStuckOn(*leftfix.graph())) {
- no_retrigger = false;
- }
-
- for (const auto &v : verts) {
- set<ue2_literal> lits;
- for (auto u : inv_adjacent_vertices_range(v, build.g)) {
- for (u32 lit_id : build.g[u].literals) {
- lits.insert(build.literals.at(lit_id).s);
- }
+ // Infix NFAs can have bounds on their queue lengths.
+ u32 max_queuelen = 0;
+ u32 max_width = 0;
+ u8 cm_count = 0;
+ CharReach cm_cr;
+
+ const auto &qi = info.queue;
+ const auto &subengines = info.subengines;
+ bool no_retrigger = true;
+ for (const auto &sub : subengines) {
+ const auto &verts = sub.vertices;
+ const auto &v_first = verts[0];
+ left_id leftfix(g[v_first].left);
+ if (leftfix.haig() || !leftfix.graph() ||
+ !nfaStuckOn(*leftfix.graph())) {
+ no_retrigger = false;
+ }
+
+ for (const auto &v : verts) {
+ set<ue2_literal> lits;
+ for (auto u : inv_adjacent_vertices_range(v, build.g)) {
+ for (u32 lit_id : build.g[u].literals) {
+ lits.insert(build.literals.at(lit_id).s);
+ }
+ }
+ DEBUG_PRINTF("%zu literals\n", lits.size());
+
+ u32 queuelen = findMaxInfixMatches(leftfix, lits);
+ if (queuelen < UINT32_MAX) {
+ queuelen++;
}
- DEBUG_PRINTF("%zu literals\n", lits.size());
-
- u32 queuelen = findMaxInfixMatches(leftfix, lits);
- if (queuelen < UINT32_MAX) {
- queuelen++;
- }
- max_queuelen = max(max_queuelen, queuelen);
+ max_queuelen = max(max_queuelen, queuelen);
+ }
+ }
+
+ if (no_retrigger) {
+ no_retrigger_queues->insert(qi);
+ }
+
+ for (const auto &sub : subengines) {
+ const auto &verts = sub.vertices;
+ for (const auto &v : verts) {
+ u32 lag = g[v].left.lag;
+ leftfix_info.emplace(v, left_build_info(qi, lag, max_width,
+ squash_mask, stop,
+ max_queuelen, cm_count,
+ cm_cr));
+ }
+ }
+ }
+}
+
+static
+void updateExclusiveSuffixProperties(const RoseBuildImpl &build,
+ const vector<ExclusiveInfo> &exclusive_info,
+ set<u32> *no_retrigger_queues) {
+ const RoseGraph &g = build.g;
+ for (auto &info : exclusive_info) {
+ const auto &qi = info.queue;
+ const auto &subengines = info.subengines;
+ bool no_retrigger = true;
+ for (const auto &sub : subengines) {
+ const auto &v_first = sub.vertices[0];
+ suffix_id suffix(g[v_first].suffix);
+ if (!suffix.graph() || !nfaStuckOn(*suffix.graph())) {
+ no_retrigger = false;
+ break;
}
- }
-
- if (no_retrigger) {
- no_retrigger_queues->insert(qi);
- }
-
- for (const auto &sub : subengines) {
- const auto &verts = sub.vertices;
- for (const auto &v : verts) {
- u32 lag = g[v].left.lag;
- leftfix_info.emplace(v, left_build_info(qi, lag, max_width,
- squash_mask, stop,
- max_queuelen, cm_count,
- cm_cr));
+ }
+
+ if (no_retrigger) {
+ no_retrigger_queues->insert(qi);
+ }
+ }
+}
+
+static
+void buildExclusiveInfixes(RoseBuildImpl &build, build_context &bc,
+ QueueIndexFactory &qif,
+ const map<left_id, set<PredTopPair>> &infixTriggers,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ const vector<vector<u32>> &groups,
+ set<u32> *no_retrigger_queues) {
+ RoseGraph &g = build.g;
+ const CompileContext &cc = build.cc;
+
+ vector<ExclusiveInfo> exclusive_info;
+ for (const auto &gp : groups) {
+ ExclusiveInfo info;
+ for (const auto &id : gp) {
+ const auto &verts = vertex_map.at(id);
+ left_id leftfix(g[verts[0]].left);
+
+ bool is_transient = false;
+ auto n = makeLeftNfa(build, leftfix, false, is_transient,
+ infixTriggers, cc);
+ assert(n);
+
+ setLeftNfaProperties(*n, leftfix);
+
+ ExclusiveSubengine engine;
+ engine.nfa = move(n);
+ engine.vertices = verts;
+ info.subengines.push_back(move(engine));
+ }
+ info.queue = qif.get_queue();
+ exclusive_info.push_back(move(info));
+ }
+ updateExclusiveInfixProperties(build, exclusive_info, bc.leftfix_info,
+ no_retrigger_queues);
+ buildInfixContainer(g, bc, exclusive_info, build.cc.grey);
+}
+
+static
+void findExclusiveInfixes(RoseBuildImpl &build, build_context &bc,
+ QueueIndexFactory &qif,
+ const map<left_id, set<PredTopPair>> &infixTriggers,
+ set<u32> *no_retrigger_queues) {
+ const RoseGraph &g = build.g;
+
+ set<RoleInfo<left_id>> roleInfoSet;
+ map<u32, vector<RoseVertex>> vertex_map;
+
+ u32 role_id = 0;
+ map<left_id, u32> leftfixes;
+ for (auto v : vertices_range(g)) {
+ if (!g[v].left || build.isRootSuccessor(v)) {
+ continue;
+ }
+
+ left_id leftfix(g[v].left);
+
+ // Sanity check: our NFA should contain each of the tops mentioned on
+ // our in-edges.
+ assert(roseHasTops(build, v));
+
+ if (contains(leftfixes, leftfix)) {
+ // NFA already built.
+ u32 id = leftfixes[leftfix];
+ if (contains(vertex_map, id)) {
+ vertex_map[id].push_back(v);
+ }
+ DEBUG_PRINTF("sharing leftfix, id=%u\n", id);
+ continue;
+ }
+
+ if (leftfix.haig()) {
+ continue;
+ }
+
+ if (leftfix.graph() || leftfix.castle()) {
+ leftfixes.emplace(leftfix, role_id);
+ vertex_map[role_id].push_back(v);
+
+ map<u32, vector<vector<CharReach>>> triggers;
+ findTriggerSequences(build, infixTriggers.at(leftfix), &triggers);
+ RoleInfo<left_id> info(leftfix, role_id);
+ if (setTriggerLiteralsInfix(info, triggers)) {
+ roleInfoSet.insert(info);
+ }
+ role_id++;
+ }
+ }
+
+ if (leftfixes.size() > 1) {
+ DEBUG_PRINTF("leftfix size:%zu\n", leftfixes.size());
+ vector<vector<u32>> groups;
+ exclusiveAnalysisInfix(build, vertex_map, roleInfoSet, groups);
+ buildExclusiveInfixes(build, bc, qif, infixTriggers, vertex_map,
+ groups, no_retrigger_queues);
+ }
+}
+
+static
+bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
+ QueueIndexFactory &qif, set<u32> *no_retrigger_queues,
+ set<u32> *eager_queues, bool do_prefix) {
+ RoseGraph &g = tbi.g;
+ const CompileContext &cc = tbi.cc;
+
+ map<left_id, set<PredTopPair>> infixTriggers;
+ findInfixTriggers(tbi, &infixTriggers);
+
+ insertion_ordered_map<left_id, vector<RoseVertex>> succs;
+
+ if (cc.grey.allowTamarama && cc.streaming && !do_prefix) {
+ findExclusiveInfixes(tbi, bc, qif, infixTriggers, no_retrigger_queues);
+ }
+
+ for (auto v : vertices_range(g)) {
+ if (!g[v].left || g[v].left.tamarama) {
+ continue;
+ }
+
+ assert(tbi.isNonRootSuccessor(v) != tbi.isRootSuccessor(v));
+ bool is_prefix = tbi.isRootSuccessor(v);
+
+ if (do_prefix != is_prefix) {
+ /* we require prefixes and then infixes */
+ continue;
+ }
+
+ left_id leftfix(g[v].left);
+
+ // Sanity check: our NFA should contain each of the tops mentioned on
+ // our in-edges.
+ assert(roseHasTops(tbi, v));
+
+ bool is_transient = contains(tbi.transient, leftfix);
+
+ // Transient leftfixes can sometimes be implemented solely with
+ // lookarounds, in which case we don't need to build an engine.
+ // TODO: Handle SOM-tracking cases as well.
+ if (cc.grey.roseLookaroundMasks && is_transient &&
+ !g[v].left.tracksSom()) {
+ vector<vector<LookEntry>> lookaround;
+ if (makeLeftfixLookaround(tbi, v, lookaround)) {
+ DEBUG_PRINTF("implementing as lookaround!\n");
+ bc.leftfix_info.emplace(v, left_build_info(lookaround));
+ continue;
}
}
- }
-}
-
-static
-void updateExclusiveSuffixProperties(const RoseBuildImpl &build,
- const vector<ExclusiveInfo> &exclusive_info,
- set<u32> *no_retrigger_queues) {
- const RoseGraph &g = build.g;
- for (auto &info : exclusive_info) {
- const auto &qi = info.queue;
- const auto &subengines = info.subengines;
- bool no_retrigger = true;
- for (const auto &sub : subengines) {
- const auto &v_first = sub.vertices[0];
- suffix_id suffix(g[v_first].suffix);
- if (!suffix.graph() || !nfaStuckOn(*suffix.graph())) {
- no_retrigger = false;
- break;
- }
- }
-
- if (no_retrigger) {
- no_retrigger_queues->insert(qi);
- }
- }
-}
-
-static
-void buildExclusiveInfixes(RoseBuildImpl &build, build_context &bc,
- QueueIndexFactory &qif,
- const map<left_id, set<PredTopPair>> &infixTriggers,
- const map<u32, vector<RoseVertex>> &vertex_map,
- const vector<vector<u32>> &groups,
- set<u32> *no_retrigger_queues) {
- RoseGraph &g = build.g;
- const CompileContext &cc = build.cc;
-
- vector<ExclusiveInfo> exclusive_info;
- for (const auto &gp : groups) {
- ExclusiveInfo info;
- for (const auto &id : gp) {
- const auto &verts = vertex_map.at(id);
- left_id leftfix(g[verts[0]].left);
-
- bool is_transient = false;
- auto n = makeLeftNfa(build, leftfix, false, is_transient,
- infixTriggers, cc);
- assert(n);
-
- setLeftNfaProperties(*n, leftfix);
-
- ExclusiveSubengine engine;
- engine.nfa = move(n);
- engine.vertices = verts;
- info.subengines.push_back(move(engine));
- }
- info.queue = qif.get_queue();
- exclusive_info.push_back(move(info));
- }
- updateExclusiveInfixProperties(build, exclusive_info, bc.leftfix_info,
- no_retrigger_queues);
- buildInfixContainer(g, bc, exclusive_info, build.cc.grey);
-}
-
-static
-void findExclusiveInfixes(RoseBuildImpl &build, build_context &bc,
- QueueIndexFactory &qif,
- const map<left_id, set<PredTopPair>> &infixTriggers,
- set<u32> *no_retrigger_queues) {
- const RoseGraph &g = build.g;
-
- set<RoleInfo<left_id>> roleInfoSet;
- map<u32, vector<RoseVertex>> vertex_map;
-
- u32 role_id = 0;
- map<left_id, u32> leftfixes;
- for (auto v : vertices_range(g)) {
- if (!g[v].left || build.isRootSuccessor(v)) {
- continue;
- }
-
- left_id leftfix(g[v].left);
-
- // Sanity check: our NFA should contain each of the tops mentioned on
- // our in-edges.
- assert(roseHasTops(build, v));
-
- if (contains(leftfixes, leftfix)) {
- // NFA already built.
- u32 id = leftfixes[leftfix];
- if (contains(vertex_map, id)) {
- vertex_map[id].push_back(v);
- }
- DEBUG_PRINTF("sharing leftfix, id=%u\n", id);
- continue;
- }
-
- if (leftfix.haig()) {
- continue;
- }
-
- if (leftfix.graph() || leftfix.castle()) {
- leftfixes.emplace(leftfix, role_id);
- vertex_map[role_id].push_back(v);
-
- map<u32, vector<vector<CharReach>>> triggers;
- findTriggerSequences(build, infixTriggers.at(leftfix), &triggers);
- RoleInfo<left_id> info(leftfix, role_id);
- if (setTriggerLiteralsInfix(info, triggers)) {
- roleInfoSet.insert(info);
- }
- role_id++;
- }
- }
-
- if (leftfixes.size() > 1) {
- DEBUG_PRINTF("leftfix size:%zu\n", leftfixes.size());
- vector<vector<u32>> groups;
- exclusiveAnalysisInfix(build, vertex_map, roleInfoSet, groups);
- buildExclusiveInfixes(build, bc, qif, infixTriggers, vertex_map,
- groups, no_retrigger_queues);
- }
-}
-
-static
-bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
- QueueIndexFactory &qif, set<u32> *no_retrigger_queues,
- set<u32> *eager_queues, bool do_prefix) {
- RoseGraph &g = tbi.g;
- const CompileContext &cc = tbi.cc;
-
- map<left_id, set<PredTopPair>> infixTriggers;
- findInfixTriggers(tbi, &infixTriggers);
-
- insertion_ordered_map<left_id, vector<RoseVertex>> succs;
-
- if (cc.grey.allowTamarama && cc.streaming && !do_prefix) {
- findExclusiveInfixes(tbi, bc, qif, infixTriggers, no_retrigger_queues);
- }
-
- for (auto v : vertices_range(g)) {
- if (!g[v].left || g[v].left.tamarama) {
- continue;
- }
-
- assert(tbi.isNonRootSuccessor(v) != tbi.isRootSuccessor(v));
- bool is_prefix = tbi.isRootSuccessor(v);
-
- if (do_prefix != is_prefix) {
- /* we require prefixes and then infixes */
- continue;
- }
-
- left_id leftfix(g[v].left);
-
- // Sanity check: our NFA should contain each of the tops mentioned on
- // our in-edges.
- assert(roseHasTops(tbi, v));
-
- bool is_transient = contains(tbi.transient, leftfix);
-
- // Transient leftfixes can sometimes be implemented solely with
- // lookarounds, in which case we don't need to build an engine.
- // TODO: Handle SOM-tracking cases as well.
- if (cc.grey.roseLookaroundMasks && is_transient &&
- !g[v].left.tracksSom()) {
- vector<vector<LookEntry>> lookaround;
- if (makeLeftfixLookaround(tbi, v, lookaround)) {
- DEBUG_PRINTF("implementing as lookaround!\n");
- bc.leftfix_info.emplace(v, left_build_info(lookaround));
- continue;
- }
- }
-
- succs[leftfix].push_back(v);
- }
-
- rose_group initial_groups = tbi.getInitialGroups();
- rose_group combined_eager_squashed_mask = ~0ULL;
-
- map<left_id, eager_info> eager;
-
- for (const auto &m : succs) {
- const left_id &leftfix = m.first;
- const auto &left_succs = m.second;
-
- rose_group squash_mask = tbi.rose_squash_masks.at(leftfix);
- eager_info ei;
-
- if (checkSuitableForEager(do_prefix, leftfix, tbi, left_succs,
- squash_mask, initial_groups, ei, cc)) {
- eager[leftfix] = ei;
- combined_eager_squashed_mask &= squash_mask;
- DEBUG_PRINTF("combo %016llx...\n", combined_eager_squashed_mask);
- }
- }
-
- if (do_prefix && combined_eager_squashed_mask & initial_groups) {
- DEBUG_PRINTF("eager groups won't squash everyone - be lazy\n");
- eager_queues->clear();
- eager.clear();
- }
-
- for (const auto &m : succs) {
- const left_id &leftfix = m.first;
- const auto &left_succs = m.second;
- buildLeftfix(tbi, bc, do_prefix, qif.get_queue(), infixTriggers,
- no_retrigger_queues, eager_queues, eager, left_succs,
- leftfix);
- }
-
+
+ succs[leftfix].push_back(v);
+ }
+
+ rose_group initial_groups = tbi.getInitialGroups();
+ rose_group combined_eager_squashed_mask = ~0ULL;
+
+ map<left_id, eager_info> eager;
+
+ for (const auto &m : succs) {
+ const left_id &leftfix = m.first;
+ const auto &left_succs = m.second;
+
+ rose_group squash_mask = tbi.rose_squash_masks.at(leftfix);
+ eager_info ei;
+
+ if (checkSuitableForEager(do_prefix, leftfix, tbi, left_succs,
+ squash_mask, initial_groups, ei, cc)) {
+ eager[leftfix] = ei;
+ combined_eager_squashed_mask &= squash_mask;
+ DEBUG_PRINTF("combo %016llx...\n", combined_eager_squashed_mask);
+ }
+ }
+
+ if (do_prefix && combined_eager_squashed_mask & initial_groups) {
+ DEBUG_PRINTF("eager groups won't squash everyone - be lazy\n");
+ eager_queues->clear();
+ eager.clear();
+ }
+
+ for (const auto &m : succs) {
+ const left_id &leftfix = m.first;
+ const auto &left_succs = m.second;
+ buildLeftfix(tbi, bc, do_prefix, qif.get_queue(), infixTriggers,
+ no_retrigger_queues, eager_queues, eager, left_succs,
+ leftfix);
+ }
+
return true;
}
@@ -1608,73 +1608,73 @@ bool hasNonSmallBlockOutfix(const vector<OutfixInfo> &outfixes) {
return false;
}
-namespace {
-class OutfixBuilder : public boost::static_visitor<bytecode_ptr<NFA>> {
-public:
- explicit OutfixBuilder(const RoseBuildImpl &build_in) : build(build_in) {}
+namespace {
+class OutfixBuilder : public boost::static_visitor<bytecode_ptr<NFA>> {
+public:
+ explicit OutfixBuilder(const RoseBuildImpl &build_in) : build(build_in) {}
+
+ bytecode_ptr<NFA> operator()(boost::blank&) const {
+ return nullptr;
+ };
- bytecode_ptr<NFA> operator()(boost::blank&) const {
- return nullptr;
- };
+ bytecode_ptr<NFA> operator()(unique_ptr<raw_dfa> &rdfa) const {
+ // Unleash the mighty DFA!
+ return getDfa(*rdfa, false, build.cc, build.rm);
+ }
- bytecode_ptr<NFA> operator()(unique_ptr<raw_dfa> &rdfa) const {
- // Unleash the mighty DFA!
- return getDfa(*rdfa, false, build.cc, build.rm);
- }
-
- bytecode_ptr<NFA> operator()(unique_ptr<raw_som_dfa> &haig) const {
+ bytecode_ptr<NFA> operator()(unique_ptr<raw_som_dfa> &haig) const {
// Unleash the Goughfish!
- return goughCompile(*haig, build.ssm.somPrecision(), build.cc,
- build.rm);
- }
-
- bytecode_ptr<NFA> operator()(unique_ptr<NGHolder> &holder) const {
- const CompileContext &cc = build.cc;
- const ReportManager &rm = build.rm;
-
- NGHolder &h = *holder;
+ return goughCompile(*haig, build.ssm.somPrecision(), build.cc,
+ build.rm);
+ }
+
+ bytecode_ptr<NFA> operator()(unique_ptr<NGHolder> &holder) const {
+ const CompileContext &cc = build.cc;
+ const ReportManager &rm = build.rm;
+
+ NGHolder &h = *holder;
assert(h.kind == NFA_OUTFIX);
// Build NFA.
- const map<u32, u32> fixed_depth_tops; /* no tops */
- const map<u32, vector<vector<CharReach>>> triggers; /* no tops */
- bool compress_state = cc.streaming;
+ const map<u32, u32> fixed_depth_tops; /* no tops */
+ const map<u32, vector<vector<CharReach>>> triggers; /* no tops */
+ bool compress_state = cc.streaming;
bool fast_nfa = false;
- auto n = constructNFA(h, &rm, fixed_depth_tops, triggers,
+ auto n = constructNFA(h, &rm, fixed_depth_tops, triggers,
compress_state, fast_nfa, cc);
// Try for a DFA upgrade.
- if (n && cc.grey.roseMcClellanOutfix &&
+ if (n && cc.grey.roseMcClellanOutfix &&
(!has_bounded_repeats_other_than_firsts(*n) || !fast_nfa)) {
auto rdfa = buildMcClellan(h, &rm, cc.grey);
if (rdfa) {
- auto d = getDfa(*rdfa, false, cc, rm);
+ auto d = getDfa(*rdfa, false, cc, rm);
if (d) {
n = pickImpl(move(d), move(n), fast_nfa);
}
}
}
-
- return n;
- }
-
- bytecode_ptr<NFA> operator()(UNUSED MpvProto &mpv) const {
- // MPV construction handled separately.
- assert(mpv.puffettes.empty());
- return nullptr;
- }
-
-private:
- const RoseBuildImpl &build;
-};
-}
-
-static
-bytecode_ptr<NFA> buildOutfix(const RoseBuildImpl &build, OutfixInfo &outfix) {
- assert(!outfix.is_dead()); // should not be marked dead.
-
- auto n = boost::apply_visitor(OutfixBuilder(build), outfix.proto);
- if (n && build.cc.grey.reverseAccelerate) {
+
+ return n;
+ }
+
+ bytecode_ptr<NFA> operator()(UNUSED MpvProto &mpv) const {
+ // MPV construction handled separately.
+ assert(mpv.puffettes.empty());
+ return nullptr;
+ }
+
+private:
+ const RoseBuildImpl &build;
+};
+}
+
+static
+bytecode_ptr<NFA> buildOutfix(const RoseBuildImpl &build, OutfixInfo &outfix) {
+ assert(!outfix.is_dead()); // should not be marked dead.
+
+ auto n = boost::apply_visitor(OutfixBuilder(build), outfix.proto);
+ if (n && build.cc.grey.reverseAccelerate) {
buildReverseAcceleration(n.get(), outfix.rev_info, outfix.minWidth);
}
@@ -1682,43 +1682,43 @@ bytecode_ptr<NFA> buildOutfix(const RoseBuildImpl &build, OutfixInfo &outfix) {
}
static
-void prepMpv(RoseBuildImpl &tbi, build_context &bc, size_t *historyRequired,
- bool *mpv_as_outfix) {
- assert(bc.engineOffsets.empty()); // MPV should be first
+void prepMpv(RoseBuildImpl &tbi, build_context &bc, size_t *historyRequired,
+ bool *mpv_as_outfix) {
+ assert(bc.engineOffsets.empty()); // MPV should be first
*mpv_as_outfix = false;
- OutfixInfo *mpv_outfix = nullptr;
+ OutfixInfo *mpv_outfix = nullptr;
/* assume outfixes are just above chain tails in queue indices */
for (auto &out : tbi.outfixes) {
if (out.is_nonempty_mpv()) {
- assert(!mpv_outfix);
- mpv_outfix = &out;
+ assert(!mpv_outfix);
+ mpv_outfix = &out;
} else {
- assert(!out.mpv());
+ assert(!out.mpv());
}
}
- if (!mpv_outfix) {
+ if (!mpv_outfix) {
return;
}
- auto *mpv = mpv_outfix->mpv();
- auto nfa = mpvCompile(mpv->puffettes, mpv->triggered_puffettes, tbi.rm);
+ auto *mpv = mpv_outfix->mpv();
+ auto nfa = mpvCompile(mpv->puffettes, mpv->triggered_puffettes, tbi.rm);
assert(nfa);
if (!nfa) {
throw CompileError("Unable to generate bytecode.");
}
if (tbi.cc.grey.reverseAccelerate) {
- buildReverseAcceleration(nfa.get(), mpv_outfix->rev_info,
- mpv_outfix->minWidth);
+ buildReverseAcceleration(nfa.get(), mpv_outfix->rev_info,
+ mpv_outfix->minWidth);
}
- u32 qi = mpv_outfix->get_queue(tbi.qif);
+ u32 qi = mpv_outfix->get_queue(tbi.qif);
nfa->queueIndex = qi;
- enforceEngineSizeLimit(nfa.get(), tbi.cc.grey);
- bc.engine_info_by_queue.emplace(nfa->queueIndex,
- engine_info(nfa.get(), false));
+ enforceEngineSizeLimit(nfa.get(), tbi.cc.grey);
+ bc.engine_info_by_queue.emplace(nfa->queueIndex,
+ engine_info(nfa.get(), false));
DEBUG_PRINTF("built mpv\n");
@@ -1726,7 +1726,7 @@ void prepMpv(RoseBuildImpl &tbi, build_context &bc, size_t *historyRequired,
*historyRequired = 1;
}
- add_nfa_to_blob(bc, *nfa);
+ add_nfa_to_blob(bc, *nfa);
*mpv_as_outfix = !mpv->puffettes.empty();
}
@@ -1753,7 +1753,7 @@ void setOutfixProperties(NFA &n, const OutfixInfo &outfix) {
}
static
-bool prepOutfixes(RoseBuildImpl &tbi, build_context &bc,
+bool prepOutfixes(RoseBuildImpl &tbi, build_context &bc,
size_t *historyRequired) {
if (tbi.cc.grey.onlyOneOutfix && tbi.outfixes.size() > 1) {
DEBUG_PRINTF("we have %zu outfixes, but Grey::onlyOneOutfix is set\n",
@@ -1761,13 +1761,13 @@ bool prepOutfixes(RoseBuildImpl &tbi, build_context &bc,
throw ResourceLimitError();
}
- assert(tbi.qif.allocated_count() == bc.engineOffsets.size());
+ assert(tbi.qif.allocated_count() == bc.engineOffsets.size());
for (auto &out : tbi.outfixes) {
- if (out.mpv()) {
+ if (out.mpv()) {
continue; /* already done */
}
- DEBUG_PRINTF("building outfix %zd\n", &out - &tbi.outfixes[0]);
+ DEBUG_PRINTF("building outfix %zd\n", &out - &tbi.outfixes[0]);
auto n = buildOutfix(tbi, out);
if (!n) {
assert(0);
@@ -1776,24 +1776,24 @@ bool prepOutfixes(RoseBuildImpl &tbi, build_context &bc,
setOutfixProperties(*n, out);
- n->queueIndex = out.get_queue(tbi.qif);
- enforceEngineSizeLimit(n.get(), tbi.cc.grey);
- bc.engine_info_by_queue.emplace(n->queueIndex,
- engine_info(n.get(), false));
+ n->queueIndex = out.get_queue(tbi.qif);
+ enforceEngineSizeLimit(n.get(), tbi.cc.grey);
+ bc.engine_info_by_queue.emplace(n->queueIndex,
+ engine_info(n.get(), false));
if (!*historyRequired && requires_decompress_key(*n)) {
*historyRequired = 1;
}
- add_nfa_to_blob(bc, *n);
+ add_nfa_to_blob(bc, *n);
}
return true;
}
static
-void assignSuffixQueues(RoseBuildImpl &build, map<suffix_id, u32> &suffixes) {
- const RoseGraph &g = build.g;
+void assignSuffixQueues(RoseBuildImpl &build, map<suffix_id, u32> &suffixes) {
+ const RoseGraph &g = build.g;
for (auto v : vertices_range(g)) {
if (!g[v].suffix) {
@@ -1802,16 +1802,16 @@ void assignSuffixQueues(RoseBuildImpl &build, map<suffix_id, u32> &suffixes) {
const suffix_id s(g[v].suffix);
- DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph());
+ DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph());
// We may have already built this NFA.
- if (contains(suffixes, s)) {
+ if (contains(suffixes, s)) {
continue;
}
- u32 queue = build.qif.get_queue();
+ u32 queue = build.qif.get_queue();
DEBUG_PRINTF("assigning %p to queue %u\n", s.graph(), queue);
- suffixes.emplace(s, queue);
+ suffixes.emplace(s, queue);
}
}
@@ -1835,173 +1835,173 @@ void setSuffixProperties(NFA &n, const suffix_id &suff,
}
static
-void buildExclusiveSuffixes(RoseBuildImpl &build, build_context &bc,
- QueueIndexFactory &qif,
- map<suffix_id, set<PredTopPair>> &suffixTriggers,
- const map<u32, vector<RoseVertex>> &vertex_map,
- const vector<vector<u32>> &groups,
- set<u32> *no_retrigger_queues) {
- RoseGraph &g = build.g;
-
- vector<ExclusiveInfo> exclusive_info;
- for (const auto &gp : groups) {
- ExclusiveInfo info;
- for (const auto &id : gp) {
- const auto &verts = vertex_map.at(id);
- suffix_id s(g[verts[0]].suffix);
-
- const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
-
- map<u32, u32> fixed_depth_tops;
- findFixedDepthTops(g, s_triggers, &fixed_depth_tops);
-
- map<u32, vector<vector<CharReach>>> triggers;
- findTriggerSequences(build, s_triggers, &triggers);
-
- auto n = buildSuffix(build.rm, build.ssm, fixed_depth_tops,
- triggers, s, build.cc);
- assert(n);
-
- setSuffixProperties(*n, s, build.rm);
-
- ExclusiveSubengine engine;
- engine.nfa = move(n);
- engine.vertices = verts;
- info.subengines.push_back(move(engine));
-
- const auto &reports = all_reports(s);
- info.reports.insert(reports.begin(), reports.end());
- }
- info.queue = qif.get_queue();
- exclusive_info.push_back(move(info));
- }
- updateExclusiveSuffixProperties(build, exclusive_info,
- no_retrigger_queues);
- buildSuffixContainer(g, bc, exclusive_info, build.cc.grey);
-}
-
-static
-void findExclusiveSuffixes(RoseBuildImpl &tbi, build_context &bc,
- QueueIndexFactory &qif,
- map<suffix_id, set<PredTopPair>> &suffixTriggers,
- set<u32> *no_retrigger_queues) {
- const RoseGraph &g = tbi.g;
-
- map<suffix_id, u32> suffixes;
- set<RoleInfo<suffix_id>> roleInfoSet;
- map<u32, vector<RoseVertex>> vertex_map;
- u32 role_id = 0;
- for (auto v : vertices_range(g)) {
- if (!g[v].suffix) {
- continue;
- }
-
- const suffix_id s(g[v].suffix);
-
- DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph());
-
- // We may have already built this NFA.
- if (contains(suffixes, s)) {
- u32 id = suffixes[s];
- if (!tbi.isInETable(v)) {
- vertex_map[id].push_back(v);
- }
- continue;
- }
-
- if (s.haig()) {
- continue;
- }
-
- // Currently disable eod suffixes for exclusive analysis
- if (!tbi.isInETable(v) && (s.graph() || s.castle())) {
- DEBUG_PRINTF("assigning %p to id %u\n", s.graph(), role_id);
- suffixes.emplace(s, role_id);
-
- vertex_map[role_id].push_back(v);
- const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
- map<u32, vector<vector<CharReach>>> triggers;
- findTriggerSequences(tbi, s_triggers, &triggers);
-
- RoleInfo<suffix_id> info(s, role_id);
- if (setTriggerLiteralsSuffix(info, triggers)) {
- roleInfoSet.insert(info);
- }
- role_id++;
- }
- }
-
- if (suffixes.size() > 1) {
- DEBUG_PRINTF("suffix size:%zu\n", suffixes.size());
- vector<vector<u32>> groups;
- exclusiveAnalysisSuffix(tbi, vertex_map, roleInfoSet, groups);
- buildExclusiveSuffixes(tbi, bc, qif, suffixTriggers, vertex_map,
- groups, no_retrigger_queues);
- }
-}
-
-static
-bool buildSuffixes(const RoseBuildImpl &tbi, build_context &bc,
- set<u32> *no_retrigger_queues,
- const map<suffix_id, set<PredTopPair>> &suffixTriggers) {
- // To ensure compile determinism, build suffix engines in order of their
- // (unique) queue indices, so that we call add_nfa_to_blob in the same
- // order.
- vector<pair<u32, suffix_id>> ordered;
- for (const auto &e : bc.suffixes) {
- ordered.emplace_back(e.second, e.first);
- }
- sort(begin(ordered), end(ordered));
-
- for (const auto &e : ordered) {
- const u32 queue = e.first;
- const suffix_id &s = e.second;
-
- if (s.tamarama()) {
- continue;
- }
-
- const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
-
- map<u32, u32> fixed_depth_tops;
- findFixedDepthTops(tbi.g, s_triggers, &fixed_depth_tops);
-
- map<u32, vector<vector<CharReach>>> triggers;
- findTriggerSequences(tbi, s_triggers, &triggers);
-
- auto n = buildSuffix(tbi.rm, tbi.ssm, fixed_depth_tops, triggers,
- s, tbi.cc);
- if (!n) {
- return false;
- }
-
- setSuffixProperties(*n, s, tbi.rm);
-
- n->queueIndex = queue;
- enforceEngineSizeLimit(n.get(), tbi.cc.grey);
- bc.engine_info_by_queue.emplace(n->queueIndex,
- engine_info(n.get(), false));
-
- if (s.graph() && nfaStuckOn(*s.graph())) { /* todo: have corresponding
- * haig analysis */
- assert(!s.haig());
- DEBUG_PRINTF("%u sticks on\n", queue);
- no_retrigger_queues->insert(queue);
- }
-
- add_nfa_to_blob(bc, *n);
- }
-
- return true;
-}
+void buildExclusiveSuffixes(RoseBuildImpl &build, build_context &bc,
+ QueueIndexFactory &qif,
+ map<suffix_id, set<PredTopPair>> &suffixTriggers,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ const vector<vector<u32>> &groups,
+ set<u32> *no_retrigger_queues) {
+ RoseGraph &g = build.g;
+
+ vector<ExclusiveInfo> exclusive_info;
+ for (const auto &gp : groups) {
+ ExclusiveInfo info;
+ for (const auto &id : gp) {
+ const auto &verts = vertex_map.at(id);
+ suffix_id s(g[verts[0]].suffix);
+
+ const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
+
+ map<u32, u32> fixed_depth_tops;
+ findFixedDepthTops(g, s_triggers, &fixed_depth_tops);
+
+ map<u32, vector<vector<CharReach>>> triggers;
+ findTriggerSequences(build, s_triggers, &triggers);
+
+ auto n = buildSuffix(build.rm, build.ssm, fixed_depth_tops,
+ triggers, s, build.cc);
+ assert(n);
+
+ setSuffixProperties(*n, s, build.rm);
+
+ ExclusiveSubengine engine;
+ engine.nfa = move(n);
+ engine.vertices = verts;
+ info.subengines.push_back(move(engine));
+
+ const auto &reports = all_reports(s);
+ info.reports.insert(reports.begin(), reports.end());
+ }
+ info.queue = qif.get_queue();
+ exclusive_info.push_back(move(info));
+ }
+ updateExclusiveSuffixProperties(build, exclusive_info,
+ no_retrigger_queues);
+ buildSuffixContainer(g, bc, exclusive_info, build.cc.grey);
+}
+
+static
+void findExclusiveSuffixes(RoseBuildImpl &tbi, build_context &bc,
+ QueueIndexFactory &qif,
+ map<suffix_id, set<PredTopPair>> &suffixTriggers,
+ set<u32> *no_retrigger_queues) {
+ const RoseGraph &g = tbi.g;
+
+ map<suffix_id, u32> suffixes;
+ set<RoleInfo<suffix_id>> roleInfoSet;
+ map<u32, vector<RoseVertex>> vertex_map;
+ u32 role_id = 0;
+ for (auto v : vertices_range(g)) {
+ if (!g[v].suffix) {
+ continue;
+ }
+
+ const suffix_id s(g[v].suffix);
+
+ DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph());
+
+ // We may have already built this NFA.
+ if (contains(suffixes, s)) {
+ u32 id = suffixes[s];
+ if (!tbi.isInETable(v)) {
+ vertex_map[id].push_back(v);
+ }
+ continue;
+ }
+
+ if (s.haig()) {
+ continue;
+ }
+
+ // Currently disable eod suffixes for exclusive analysis
+ if (!tbi.isInETable(v) && (s.graph() || s.castle())) {
+ DEBUG_PRINTF("assigning %p to id %u\n", s.graph(), role_id);
+ suffixes.emplace(s, role_id);
+
+ vertex_map[role_id].push_back(v);
+ const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
+ map<u32, vector<vector<CharReach>>> triggers;
+ findTriggerSequences(tbi, s_triggers, &triggers);
+
+ RoleInfo<suffix_id> info(s, role_id);
+ if (setTriggerLiteralsSuffix(info, triggers)) {
+ roleInfoSet.insert(info);
+ }
+ role_id++;
+ }
+ }
+
+ if (suffixes.size() > 1) {
+ DEBUG_PRINTF("suffix size:%zu\n", suffixes.size());
+ vector<vector<u32>> groups;
+ exclusiveAnalysisSuffix(tbi, vertex_map, roleInfoSet, groups);
+ buildExclusiveSuffixes(tbi, bc, qif, suffixTriggers, vertex_map,
+ groups, no_retrigger_queues);
+ }
+}
+
+static
+bool buildSuffixes(const RoseBuildImpl &tbi, build_context &bc,
+ set<u32> *no_retrigger_queues,
+ const map<suffix_id, set<PredTopPair>> &suffixTriggers) {
+ // To ensure compile determinism, build suffix engines in order of their
+ // (unique) queue indices, so that we call add_nfa_to_blob in the same
+ // order.
+ vector<pair<u32, suffix_id>> ordered;
+ for (const auto &e : bc.suffixes) {
+ ordered.emplace_back(e.second, e.first);
+ }
+ sort(begin(ordered), end(ordered));
+
+ for (const auto &e : ordered) {
+ const u32 queue = e.first;
+ const suffix_id &s = e.second;
-static
-void buildCountingMiracles(build_context &bc) {
+ if (s.tamarama()) {
+ continue;
+ }
+
+ const set<PredTopPair> &s_triggers = suffixTriggers.at(s);
+
+ map<u32, u32> fixed_depth_tops;
+ findFixedDepthTops(tbi.g, s_triggers, &fixed_depth_tops);
+
+ map<u32, vector<vector<CharReach>>> triggers;
+ findTriggerSequences(tbi, s_triggers, &triggers);
+
+ auto n = buildSuffix(tbi.rm, tbi.ssm, fixed_depth_tops, triggers,
+ s, tbi.cc);
+ if (!n) {
+ return false;
+ }
+
+ setSuffixProperties(*n, s, tbi.rm);
+
+ n->queueIndex = queue;
+ enforceEngineSizeLimit(n.get(), tbi.cc.grey);
+ bc.engine_info_by_queue.emplace(n->queueIndex,
+ engine_info(n.get(), false));
+
+ if (s.graph() && nfaStuckOn(*s.graph())) { /* todo: have corresponding
+ * haig analysis */
+ assert(!s.haig());
+ DEBUG_PRINTF("%u sticks on\n", queue);
+ no_retrigger_queues->insert(queue);
+ }
+
+ add_nfa_to_blob(bc, *n);
+ }
+
+ return true;
+}
+
+static
+void buildCountingMiracles(build_context &bc) {
map<pair<CharReach, u8>, u32> pre_built;
- for (left_build_info &lbi : bc.leftfix_info | map_values) {
- if (!lbi.countingMiracleCount) {
- continue;
+ for (left_build_info &lbi : bc.leftfix_info | map_values) {
+ if (!lbi.countingMiracleCount) {
+ continue;
}
const CharReach &cr = lbi.countingMiracleReach;
@@ -2020,7 +2020,7 @@ void buildCountingMiracles(build_context &bc) {
rcm.c = cr.find_first();
} else {
rcm.shufti = 1;
- int rv = shuftiBuildMasks(cr, (u8 *)&rcm.lo, (u8 *)&rcm.hi);
+ int rv = shuftiBuildMasks(cr, (u8 *)&rcm.lo, (u8 *)&rcm.hi);
if (rv == -1) {
DEBUG_PRINTF("failed to build shufti\n");
lbi.countingMiracleCount = 0; /* remove counting miracle */
@@ -2032,41 +2032,41 @@ void buildCountingMiracles(build_context &bc) {
rcm.count = lbi.countingMiracleCount;
- lbi.countingMiracleOffset = bc.engine_blob.add(rcm);
+ lbi.countingMiracleOffset = bc.engine_blob.add(rcm);
pre_built[key] = lbi.countingMiracleOffset;
DEBUG_PRINTF("built cm for count of %u @ %u\n", rcm.count,
lbi.countingMiracleOffset);
}
}
-/* Note: buildNfas may reduce the lag for vertices that have prefixes */
+/* Note: buildNfas may reduce the lag for vertices that have prefixes */
static
-bool buildNfas(RoseBuildImpl &tbi, build_context &bc, QueueIndexFactory &qif,
- set<u32> *no_retrigger_queues, set<u32> *eager_queues,
- u32 *leftfixBeginQueue) {
- map<suffix_id, set<PredTopPair>> suffixTriggers;
- findSuffixTriggers(tbi, &suffixTriggers);
+bool buildNfas(RoseBuildImpl &tbi, build_context &bc, QueueIndexFactory &qif,
+ set<u32> *no_retrigger_queues, set<u32> *eager_queues,
+ u32 *leftfixBeginQueue) {
+ map<suffix_id, set<PredTopPair>> suffixTriggers;
+ findSuffixTriggers(tbi, &suffixTriggers);
+
+ if (tbi.cc.grey.allowTamarama && tbi.cc.streaming) {
+ findExclusiveSuffixes(tbi, bc, qif, suffixTriggers,
+ no_retrigger_queues);
+ }
- if (tbi.cc.grey.allowTamarama && tbi.cc.streaming) {
- findExclusiveSuffixes(tbi, bc, qif, suffixTriggers,
- no_retrigger_queues);
- }
-
- assignSuffixQueues(tbi, bc.suffixes);
-
- if (!buildSuffixes(tbi, bc, no_retrigger_queues, suffixTriggers)) {
+ assignSuffixQueues(tbi, bc.suffixes);
+
+ if (!buildSuffixes(tbi, bc, no_retrigger_queues, suffixTriggers)) {
return false;
}
- suffixTriggers.clear();
+ suffixTriggers.clear();
*leftfixBeginQueue = qif.allocated_count();
- if (!buildLeftfixes(tbi, bc, qif, no_retrigger_queues, eager_queues,
+ if (!buildLeftfixes(tbi, bc, qif, no_retrigger_queues, eager_queues,
true)) {
return false;
}
- if (!buildLeftfixes(tbi, bc, qif, no_retrigger_queues, eager_queues,
+ if (!buildLeftfixes(tbi, bc, qif, no_retrigger_queues, eager_queues,
false)) {
return false;
}
@@ -2075,45 +2075,45 @@ bool buildNfas(RoseBuildImpl &tbi, build_context &bc, QueueIndexFactory &qif,
}
static
-void allocateStateSpace(const engine_info &eng_info, NfaInfo &nfa_info,
- RoseStateOffsets *so, u32 *scratchStateSize,
- u32 *transientStateSize) {
+void allocateStateSpace(const engine_info &eng_info, NfaInfo &nfa_info,
+ RoseStateOffsets *so, u32 *scratchStateSize,
+ u32 *transientStateSize) {
u32 state_offset;
- if (eng_info.transient) {
- // Transient engines do not use stream state, but must have room in
- // transient state (stored in scratch).
- state_offset = *transientStateSize;
- *transientStateSize += eng_info.stream_size;
+ if (eng_info.transient) {
+ // Transient engines do not use stream state, but must have room in
+ // transient state (stored in scratch).
+ state_offset = *transientStateSize;
+ *transientStateSize += eng_info.stream_size;
} else {
- // Pack NFA stream state on to the end of the Rose stream state.
+ // Pack NFA stream state on to the end of the Rose stream state.
state_offset = so->end;
- so->end += eng_info.stream_size;
+ so->end += eng_info.stream_size;
}
- nfa_info.stateOffset = state_offset;
+ nfa_info.stateOffset = state_offset;
- // Uncompressed state in scratch must be aligned.
- *scratchStateSize = ROUNDUP_N(*scratchStateSize, eng_info.scratch_align);
- nfa_info.fullStateOffset = *scratchStateSize;
- *scratchStateSize += eng_info.scratch_size;
+ // Uncompressed state in scratch must be aligned.
+ *scratchStateSize = ROUNDUP_N(*scratchStateSize, eng_info.scratch_align);
+ nfa_info.fullStateOffset = *scratchStateSize;
+ *scratchStateSize += eng_info.scratch_size;
}
static
-void updateNfaState(const build_context &bc, vector<NfaInfo> &nfa_infos,
- RoseStateOffsets *so, u32 *scratchStateSize,
- u32 *transientStateSize) {
- if (nfa_infos.empty()) {
- return;
+void updateNfaState(const build_context &bc, vector<NfaInfo> &nfa_infos,
+ RoseStateOffsets *so, u32 *scratchStateSize,
+ u32 *transientStateSize) {
+ if (nfa_infos.empty()) {
+ return;
}
- *transientStateSize = 0;
- *scratchStateSize = 0;
+ *transientStateSize = 0;
+ *scratchStateSize = 0;
- for (u32 qi = 0; qi < nfa_infos.size(); qi++) {
- NfaInfo &nfa_info = nfa_infos[qi];
- const auto &eng_info = bc.engine_info_by_queue.at(qi);
- allocateStateSpace(eng_info, nfa_info, so, scratchStateSize,
- transientStateSize);
+ for (u32 qi = 0; qi < nfa_infos.size(); qi++) {
+ NfaInfo &nfa_info = nfa_infos[qi];
+ const auto &eng_info = bc.engine_info_by_queue.at(qi);
+ allocateStateSpace(eng_info, nfa_info, so, scratchStateSize,
+ transientStateSize);
}
}
@@ -2152,8 +2152,8 @@ u32 RoseBuildImpl::calcHistoryRequired() const {
}
// Delayed literals contribute to history requirement as well.
- for (u32 id = 0; id < literals.size(); id++) {
- const auto &lit = literals.at(id);
+ for (u32 id = 0; id < literals.size(); id++) {
+ const auto &lit = literals.at(id);
if (lit.delay) {
// If the literal is delayed _and_ has a mask that is longer than
// the literal, we need enough history to match the whole mask as
@@ -2181,122 +2181,122 @@ u32 RoseBuildImpl::calcHistoryRequired() const {
}
static
-u32 buildLastByteIter(const RoseGraph &g, build_context &bc) {
- vector<u32> lb_roles;
+u32 buildLastByteIter(const RoseGraph &g, build_context &bc) {
+ vector<u32> lb_roles;
- for (auto v : vertices_range(g)) {
- if (!hasLastByteHistorySucc(g, v)) {
- continue;
+ for (auto v : vertices_range(g)) {
+ if (!hasLastByteHistorySucc(g, v)) {
+ continue;
}
- // Eager EOD reporters won't have state indices.
- auto it = bc.roleStateIndices.find(v);
- if (it != end(bc.roleStateIndices)) {
- lb_roles.push_back(it->second);
- DEBUG_PRINTF("last byte %u\n", it->second);
+ // Eager EOD reporters won't have state indices.
+ auto it = bc.roleStateIndices.find(v);
+ if (it != end(bc.roleStateIndices)) {
+ lb_roles.push_back(it->second);
+ DEBUG_PRINTF("last byte %u\n", it->second);
}
}
- if (lb_roles.empty()) {
- return 0; /* invalid offset */
+ if (lb_roles.empty()) {
+ return 0; /* invalid offset */
}
-
- auto iter = mmbBuildSparseIterator(lb_roles, bc.roleStateIndices.size());
- return bc.engine_blob.add_iterator(iter);
+
+ auto iter = mmbBuildSparseIterator(lb_roles, bc.roleStateIndices.size());
+ return bc.engine_blob.add_iterator(iter);
}
static
-u32 findMinFloatingLiteralMatch(const RoseBuildImpl &build,
- const vector<raw_dfa> &anchored_dfas) {
- if (anchored_dfas.size() > 1) {
- DEBUG_PRINTF("multiple anchored dfas\n");
- /* We must regard matches from other anchored tables as unordered, as
- * we do for floating matches. */
- return 1;
+u32 findMinFloatingLiteralMatch(const RoseBuildImpl &build,
+ const vector<raw_dfa> &anchored_dfas) {
+ if (anchored_dfas.size() > 1) {
+ DEBUG_PRINTF("multiple anchored dfas\n");
+ /* We must regard matches from other anchored tables as unordered, as
+ * we do for floating matches. */
+ return 1;
}
- const RoseGraph &g = build.g;
- u32 minWidth = ROSE_BOUND_INF;
- for (auto v : vertices_range(g)) {
- if (build.isAnchored(v) || build.isVirtualVertex(v)) {
- DEBUG_PRINTF("skipping %zu anchored or root\n", g[v].index);
- continue;
- }
+ const RoseGraph &g = build.g;
+ u32 minWidth = ROSE_BOUND_INF;
+ for (auto v : vertices_range(g)) {
+ if (build.isAnchored(v) || build.isVirtualVertex(v)) {
+ DEBUG_PRINTF("skipping %zu anchored or root\n", g[v].index);
+ continue;
+ }
- u32 w = g[v].min_offset;
- DEBUG_PRINTF("%zu m_o = %u\n", g[v].index, w);
+ u32 w = g[v].min_offset;
+ DEBUG_PRINTF("%zu m_o = %u\n", g[v].index, w);
- if (w < minWidth) {
- minWidth = w;
+ if (w < minWidth) {
+ minWidth = w;
}
}
- return minWidth;
+ return minWidth;
}
static
-vector<u32> buildSuffixEkeyLists(const RoseBuildImpl &build, build_context &bc,
- const QueueIndexFactory &qif) {
- vector<u32> out(qif.allocated_count());
+vector<u32> buildSuffixEkeyLists(const RoseBuildImpl &build, build_context &bc,
+ const QueueIndexFactory &qif) {
+ vector<u32> out(qif.allocated_count());
- map<u32, vector<u32>> qi_to_ekeys; /* for determinism */
+ map<u32, vector<u32>> qi_to_ekeys; /* for determinism */
- for (const auto &e : bc.suffixes) {
- const suffix_id &s = e.first;
- u32 qi = e.second;
- set<u32> ekeys = reportsToEkeys(all_reports(s), build.rm);
+ for (const auto &e : bc.suffixes) {
+ const suffix_id &s = e.first;
+ u32 qi = e.second;
+ set<u32> ekeys = reportsToEkeys(all_reports(s), build.rm);
- if (!ekeys.empty()) {
- qi_to_ekeys[qi] = {ekeys.begin(), ekeys.end()};
+ if (!ekeys.empty()) {
+ qi_to_ekeys[qi] = {ekeys.begin(), ekeys.end()};
}
}
- /* for each outfix also build elists */
- for (const auto &outfix : build.outfixes) {
- u32 qi = outfix.get_queue();
- set<u32> ekeys = reportsToEkeys(all_reports(outfix), build.rm);
+ /* for each outfix also build elists */
+ for (const auto &outfix : build.outfixes) {
+ u32 qi = outfix.get_queue();
+ set<u32> ekeys = reportsToEkeys(all_reports(outfix), build.rm);
- if (!ekeys.empty()) {
- qi_to_ekeys[qi] = {ekeys.begin(), ekeys.end()};
- }
+ if (!ekeys.empty()) {
+ qi_to_ekeys[qi] = {ekeys.begin(), ekeys.end()};
+ }
}
- for (auto &e : qi_to_ekeys) {
- u32 qi = e.first;
- auto &ekeys = e.second;
- assert(!ekeys.empty());
- ekeys.push_back(INVALID_EKEY); /* terminator */
- out[qi] = bc.engine_blob.add_range(ekeys);
+ for (auto &e : qi_to_ekeys) {
+ u32 qi = e.first;
+ auto &ekeys = e.second;
+ assert(!ekeys.empty());
+ ekeys.push_back(INVALID_EKEY); /* terminator */
+ out[qi] = bc.engine_blob.add_range(ekeys);
}
- return out;
+ return out;
}
-/** Returns sparse iter offset in engine blob. */
+/** Returns sparse iter offset in engine blob. */
static
-u32 buildEodNfaIterator(build_context &bc, const u32 activeQueueCount) {
- vector<u32> keys;
- for (u32 qi = 0; qi < activeQueueCount; ++qi) {
- const auto &eng_info = bc.engine_info_by_queue.at(qi);
- if (eng_info.accepts_eod) {
- DEBUG_PRINTF("nfa qi=%u accepts eod\n", qi);
- keys.push_back(qi);
- }
+u32 buildEodNfaIterator(build_context &bc, const u32 activeQueueCount) {
+ vector<u32> keys;
+ for (u32 qi = 0; qi < activeQueueCount; ++qi) {
+ const auto &eng_info = bc.engine_info_by_queue.at(qi);
+ if (eng_info.accepts_eod) {
+ DEBUG_PRINTF("nfa qi=%u accepts eod\n", qi);
+ keys.push_back(qi);
+ }
}
- if (keys.empty()) {
- return 0;
+ if (keys.empty()) {
+ return 0;
}
- DEBUG_PRINTF("building iter for %zu nfas\n", keys.size());
+ DEBUG_PRINTF("building iter for %zu nfas\n", keys.size());
- auto iter = mmbBuildSparseIterator(keys, activeQueueCount);
- return bc.engine_blob.add_iterator(iter);
+ auto iter = mmbBuildSparseIterator(keys, activeQueueCount);
+ return bc.engine_blob.add_iterator(iter);
}
static
-bool hasMpvTrigger(const set<u32> &reports, const ReportManager &rm) {
- for (u32 r : reports) {
- if (rm.getReport(r).type == INTERNAL_ROSE_CHAIN) {
+bool hasMpvTrigger(const set<u32> &reports, const ReportManager &rm) {
+ for (u32 r : reports) {
+ if (rm.getReport(r).type == INTERNAL_ROSE_CHAIN) {
return true;
}
}
@@ -2305,28 +2305,28 @@ bool hasMpvTrigger(const set<u32> &reports, const ReportManager &rm) {
}
static
-bool anyEndfixMpvTriggers(const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
- unordered_set<suffix_id> done;
+bool anyEndfixMpvTriggers(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+ unordered_set<suffix_id> done;
- /* suffixes */
- for (auto v : vertices_range(g)) {
- if (!g[v].suffix) {
- continue;
+ /* suffixes */
+ for (auto v : vertices_range(g)) {
+ if (!g[v].suffix) {
+ continue;
+ }
+ if (contains(done, g[v].suffix)) {
+ continue; /* already done */
}
- if (contains(done, g[v].suffix)) {
- continue; /* already done */
- }
- done.insert(g[v].suffix);
+ done.insert(g[v].suffix);
- if (hasMpvTrigger(all_reports(g[v].suffix), build.rm)) {
- return true;
+ if (hasMpvTrigger(all_reports(g[v].suffix), build.rm)) {
+ return true;
}
}
- /* outfixes */
- for (const auto &out : build.outfixes) {
- if (hasMpvTrigger(all_reports(out), build.rm)) {
+ /* outfixes */
+ for (const auto &out : build.outfixes) {
+ if (hasMpvTrigger(all_reports(out), build.rm)) {
return true;
}
}
@@ -2334,163 +2334,163 @@ bool anyEndfixMpvTriggers(const RoseBuildImpl &build) {
return false;
}
-struct DerivedBoundaryReports {
- explicit DerivedBoundaryReports(const BoundaryReports &boundary) {
- insert(&report_at_0_eod_full, boundary.report_at_0_eod);
- insert(&report_at_0_eod_full, boundary.report_at_eod);
- insert(&report_at_0_eod_full, boundary.report_at_0);
+struct DerivedBoundaryReports {
+ explicit DerivedBoundaryReports(const BoundaryReports &boundary) {
+ insert(&report_at_0_eod_full, boundary.report_at_0_eod);
+ insert(&report_at_0_eod_full, boundary.report_at_eod);
+ insert(&report_at_0_eod_full, boundary.report_at_0);
}
- set<ReportID> report_at_0_eod_full;
-};
+ set<ReportID> report_at_0_eod_full;
+};
-static
-void addSomRevNfas(build_context &bc, RoseEngine &proto,
- const SomSlotManager &ssm) {
- const auto &nfas = ssm.getRevNfas();
- vector<u32> nfa_offsets;
- nfa_offsets.reserve(nfas.size());
- for (const auto &nfa : nfas) {
- assert(nfa);
- u32 offset = bc.engine_blob.add(*nfa, nfa->length);
- DEBUG_PRINTF("wrote SOM rev NFA %zu (len %u) to offset %u\n",
- nfa_offsets.size(), nfa->length, offset);
- nfa_offsets.push_back(offset);
- /* note: som rev nfas don't need a queue assigned as only run in block
- * mode reverse */
+static
+void addSomRevNfas(build_context &bc, RoseEngine &proto,
+ const SomSlotManager &ssm) {
+ const auto &nfas = ssm.getRevNfas();
+ vector<u32> nfa_offsets;
+ nfa_offsets.reserve(nfas.size());
+ for (const auto &nfa : nfas) {
+ assert(nfa);
+ u32 offset = bc.engine_blob.add(*nfa, nfa->length);
+ DEBUG_PRINTF("wrote SOM rev NFA %zu (len %u) to offset %u\n",
+ nfa_offsets.size(), nfa->length, offset);
+ nfa_offsets.push_back(offset);
+ /* note: som rev nfas don't need a queue assigned as only run in block
+ * mode reverse */
}
- proto.somRevCount = verify_u32(nfas.size());
- proto.somRevOffsetOffset = bc.engine_blob.add_range(nfa_offsets);
+ proto.somRevCount = verify_u32(nfas.size());
+ proto.somRevOffsetOffset = bc.engine_blob.add_range(nfa_offsets);
}
static
-void recordResources(RoseResources &resources, const RoseBuildImpl &build,
- const vector<raw_dfa> &anchored_dfas,
- const vector<LitFragment> &fragments) {
- if (!build.outfixes.empty()) {
- resources.has_outfixes = true;
+void recordResources(RoseResources &resources, const RoseBuildImpl &build,
+ const vector<raw_dfa> &anchored_dfas,
+ const vector<LitFragment> &fragments) {
+ if (!build.outfixes.empty()) {
+ resources.has_outfixes = true;
}
- resources.has_literals = !fragments.empty();
+ resources.has_literals = !fragments.empty();
- const auto &g = build.g;
- for (const auto &v : vertices_range(g)) {
- if (g[v].eod_accept) {
- resources.has_eod = true;
- break;
+ const auto &g = build.g;
+ for (const auto &v : vertices_range(g)) {
+ if (g[v].eod_accept) {
+ resources.has_eod = true;
+ break;
}
- if (g[v].suffix && has_eod_accepts(g[v].suffix)) {
- resources.has_eod = true;
- break;
+ if (g[v].suffix && has_eod_accepts(g[v].suffix)) {
+ resources.has_eod = true;
+ break;
}
}
- resources.has_anchored = !anchored_dfas.empty();
- resources.has_anchored_multiple = anchored_dfas.size() > 1;
- for (const auto &rdfa : anchored_dfas) {
- if (rdfa.states.size() > 256) {
- resources.has_anchored_large = true;
+ resources.has_anchored = !anchored_dfas.empty();
+ resources.has_anchored_multiple = anchored_dfas.size() > 1;
+ for (const auto &rdfa : anchored_dfas) {
+ if (rdfa.states.size() > 256) {
+ resources.has_anchored_large = true;
}
}
}
static
-u32 writeProgram(build_context &bc, RoseProgram &&program) {
- if (program.empty()) {
- DEBUG_PRINTF("no program\n");
- return 0;
+u32 writeProgram(build_context &bc, RoseProgram &&program) {
+ if (program.empty()) {
+ DEBUG_PRINTF("no program\n");
+ return 0;
}
- applyFinalSpecialisation(program);
+ applyFinalSpecialisation(program);
- auto it = bc.program_cache.find(program);
- if (it != end(bc.program_cache)) {
- DEBUG_PRINTF("reusing cached program at %u\n", it->second);
- return it->second;
+ auto it = bc.program_cache.find(program);
+ if (it != end(bc.program_cache)) {
+ DEBUG_PRINTF("reusing cached program at %u\n", it->second);
+ return it->second;
}
- recordResources(bc.resources, program);
- recordLongLiterals(bc.longLiterals, program);
+ recordResources(bc.resources, program);
+ recordLongLiterals(bc.longLiterals, program);
- auto prog_bytecode = writeProgram(bc.engine_blob, program);
- u32 offset = bc.engine_blob.add(prog_bytecode);
- DEBUG_PRINTF("prog len %zu written at offset %u\n", prog_bytecode.size(),
- offset);
- bc.program_cache.emplace(move(program), offset);
- return offset;
+ auto prog_bytecode = writeProgram(bc.engine_blob, program);
+ u32 offset = bc.engine_blob.add(prog_bytecode);
+ DEBUG_PRINTF("prog len %zu written at offset %u\n", prog_bytecode.size(),
+ offset);
+ bc.program_cache.emplace(move(program), offset);
+ return offset;
}
static
-u32 writeActiveLeftIter(RoseEngineBlob &engine_blob,
- const vector<LeftNfaInfo> &leftInfoTable) {
- vector<u32> keys;
- for (size_t i = 0; i < leftInfoTable.size(); i++) {
- if (!leftInfoTable[i].transient) {
- DEBUG_PRINTF("leftfix %zu is active\n", i);
- keys.push_back(verify_u32(i));
- }
+u32 writeActiveLeftIter(RoseEngineBlob &engine_blob,
+ const vector<LeftNfaInfo> &leftInfoTable) {
+ vector<u32> keys;
+ for (size_t i = 0; i < leftInfoTable.size(); i++) {
+ if (!leftInfoTable[i].transient) {
+ DEBUG_PRINTF("leftfix %zu is active\n", i);
+ keys.push_back(verify_u32(i));
+ }
}
- DEBUG_PRINTF("%zu active leftfixes\n", keys.size());
+ DEBUG_PRINTF("%zu active leftfixes\n", keys.size());
- if (keys.empty()) {
- return 0;
+ if (keys.empty()) {
+ return 0;
}
- auto iter = mmbBuildSparseIterator(keys, verify_u32(leftInfoTable.size()));
- return engine_blob.add_iterator(iter);
+ auto iter = mmbBuildSparseIterator(keys, verify_u32(leftInfoTable.size()));
+ return engine_blob.add_iterator(iter);
}
static
-bool hasEodAnchors(const RoseBuildImpl &build, const build_context &bc,
- u32 outfixEndQueue) {
- for (u32 i = 0; i < outfixEndQueue; i++) {
- const auto &eng_info = bc.engine_info_by_queue.at(i);
- if (eng_info.accepts_eod) {
- DEBUG_PRINTF("outfix has eod\n");
- return true;
- }
+bool hasEodAnchors(const RoseBuildImpl &build, const build_context &bc,
+ u32 outfixEndQueue) {
+ for (u32 i = 0; i < outfixEndQueue; i++) {
+ const auto &eng_info = bc.engine_info_by_queue.at(i);
+ if (eng_info.accepts_eod) {
+ DEBUG_PRINTF("outfix has eod\n");
+ return true;
+ }
}
- if (build.eod_event_literal_id != MO_INVALID_IDX) {
- DEBUG_PRINTF("eod is an event to be celebrated\n");
- return true;
+ if (build.eod_event_literal_id != MO_INVALID_IDX) {
+ DEBUG_PRINTF("eod is an event to be celebrated\n");
+ return true;
}
- const RoseGraph &g = build.g;
- for (auto v : vertices_range(g)) {
- if (g[v].eod_accept) {
- DEBUG_PRINTF("literally report eod\n");
+ const RoseGraph &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (g[v].eod_accept) {
+ DEBUG_PRINTF("literally report eod\n");
+ return true;
+ }
+ if (g[v].suffix && has_eod_accepts(g[v].suffix)) {
+ DEBUG_PRINTF("eod suffix\n");
return true;
}
- if (g[v].suffix && has_eod_accepts(g[v].suffix)) {
- DEBUG_PRINTF("eod suffix\n");
- return true;
- }
}
- DEBUG_PRINTF("yawn\n");
+ DEBUG_PRINTF("yawn\n");
return false;
}
static
-void writeDkeyInfo(const ReportManager &rm, RoseEngineBlob &engine_blob,
- RoseEngine &proto) {
- const auto inv_dkeys = rm.getDkeyToReportTable();
- proto.invDkeyOffset = engine_blob.add_range(inv_dkeys);
- proto.dkeyCount = rm.numDkeys();
- proto.dkeyLogSize = fatbit_size(proto.dkeyCount);
+void writeDkeyInfo(const ReportManager &rm, RoseEngineBlob &engine_blob,
+ RoseEngine &proto) {
+ const auto inv_dkeys = rm.getDkeyToReportTable();
+ proto.invDkeyOffset = engine_blob.add_range(inv_dkeys);
+ proto.dkeyCount = rm.numDkeys();
+ proto.dkeyLogSize = fatbit_size(proto.dkeyCount);
}
static
-void writeLeftInfo(RoseEngineBlob &engine_blob, RoseEngine &proto,
- const vector<LeftNfaInfo> &leftInfoTable) {
- proto.leftOffset = engine_blob.add_range(leftInfoTable);
- proto.activeLeftIterOffset
- = writeActiveLeftIter(engine_blob, leftInfoTable);
- proto.roseCount = verify_u32(leftInfoTable.size());
- proto.activeLeftCount = verify_u32(leftInfoTable.size());
- proto.rosePrefixCount = countRosePrefixes(leftInfoTable);
+void writeLeftInfo(RoseEngineBlob &engine_blob, RoseEngine &proto,
+ const vector<LeftNfaInfo> &leftInfoTable) {
+ proto.leftOffset = engine_blob.add_range(leftInfoTable);
+ proto.activeLeftIterOffset
+ = writeActiveLeftIter(engine_blob, leftInfoTable);
+ proto.roseCount = verify_u32(leftInfoTable.size());
+ proto.activeLeftCount = verify_u32(leftInfoTable.size());
+ proto.rosePrefixCount = countRosePrefixes(leftInfoTable);
}
static
@@ -2506,132 +2506,132 @@ void writeLogicalInfo(const ReportManager &rm, RoseEngineBlob &engine_blob,
}
static
-void writeNfaInfo(const RoseBuildImpl &build, build_context &bc,
- RoseEngine &proto, const set<u32> &no_retrigger_queues) {
- const u32 queue_count = build.qif.allocated_count();
- if (!queue_count) {
- return;
+void writeNfaInfo(const RoseBuildImpl &build, build_context &bc,
+ RoseEngine &proto, const set<u32> &no_retrigger_queues) {
+ const u32 queue_count = build.qif.allocated_count();
+ if (!queue_count) {
+ return;
}
- auto ekey_lists = buildSuffixEkeyLists(build, bc, build.qif);
+ auto ekey_lists = buildSuffixEkeyLists(build, bc, build.qif);
- vector<NfaInfo> infos(queue_count);
- memset(infos.data(), 0, sizeof(NfaInfo) * queue_count);
+ vector<NfaInfo> infos(queue_count);
+ memset(infos.data(), 0, sizeof(NfaInfo) * queue_count);
- for (u32 qi = 0; qi < queue_count; qi++) {
- NfaInfo &info = infos[qi];
- info.nfaOffset = bc.engineOffsets.at(qi);
- assert(qi < ekey_lists.size());
- info.ekeyListOffset = ekey_lists.at(qi);
- info.no_retrigger = contains(no_retrigger_queues, qi) ? 1 : 0;
+ for (u32 qi = 0; qi < queue_count; qi++) {
+ NfaInfo &info = infos[qi];
+ info.nfaOffset = bc.engineOffsets.at(qi);
+ assert(qi < ekey_lists.size());
+ info.ekeyListOffset = ekey_lists.at(qi);
+ info.no_retrigger = contains(no_retrigger_queues, qi) ? 1 : 0;
}
- // Mark outfixes that are in the small block matcher.
- for (const auto &out : build.outfixes) {
- const u32 qi = out.get_queue();
- assert(qi < infos.size());
- infos.at(qi).in_sbmatcher = out.in_sbmatcher;
+ // Mark outfixes that are in the small block matcher.
+ for (const auto &out : build.outfixes) {
+ const u32 qi = out.get_queue();
+ assert(qi < infos.size());
+ infos.at(qi).in_sbmatcher = out.in_sbmatcher;
}
- // Mark suffixes triggered by EOD table literals.
- const RoseGraph &g = build.g;
+ // Mark suffixes triggered by EOD table literals.
+ const RoseGraph &g = build.g;
for (auto v : vertices_range(g)) {
if (!g[v].suffix) {
continue;
}
- u32 qi = bc.suffixes.at(g[v].suffix);
- assert(qi < infos.size());
- if (build.isInETable(v)) {
- infos.at(qi).eod = 1;
+ u32 qi = bc.suffixes.at(g[v].suffix);
+ assert(qi < infos.size());
+ if (build.isInETable(v)) {
+ infos.at(qi).eod = 1;
}
}
- // Update state offsets to do with NFAs in proto and in the NfaInfo
- // structures.
- updateNfaState(bc, infos, &proto.stateOffsets, &proto.scratchStateSize,
- &proto.tStateSize);
+ // Update state offsets to do with NFAs in proto and in the NfaInfo
+ // structures.
+ updateNfaState(bc, infos, &proto.stateOffsets, &proto.scratchStateSize,
+ &proto.tStateSize);
- proto.nfaInfoOffset = bc.engine_blob.add_range(infos);
+ proto.nfaInfoOffset = bc.engine_blob.add_range(infos);
}
static
-bool hasBoundaryReports(const BoundaryReports &boundary) {
- if (!boundary.report_at_0.empty()) {
- DEBUG_PRINTF("has boundary reports at 0\n");
- return true;
+bool hasBoundaryReports(const BoundaryReports &boundary) {
+ if (!boundary.report_at_0.empty()) {
+ DEBUG_PRINTF("has boundary reports at 0\n");
+ return true;
}
- if (!boundary.report_at_0_eod.empty()) {
- DEBUG_PRINTF("has boundary reports at 0 eod\n");
- return true;
+ if (!boundary.report_at_0_eod.empty()) {
+ DEBUG_PRINTF("has boundary reports at 0 eod\n");
+ return true;
}
- if (!boundary.report_at_eod.empty()) {
- DEBUG_PRINTF("has boundary reports at eod\n");
- return true;
+ if (!boundary.report_at_eod.empty()) {
+ DEBUG_PRINTF("has boundary reports at eod\n");
+ return true;
}
- DEBUG_PRINTF("no boundary reports\n");
- return false;
+ DEBUG_PRINTF("no boundary reports\n");
+ return false;
}
static
-void makeBoundaryPrograms(const RoseBuildImpl &build, build_context &bc,
- const BoundaryReports &boundary,
- const DerivedBoundaryReports &dboundary,
- RoseBoundaryReports &out) {
- DEBUG_PRINTF("report ^: %zu\n", boundary.report_at_0.size());
- DEBUG_PRINTF("report $: %zu\n", boundary.report_at_eod.size());
- DEBUG_PRINTF("report ^$: %zu\n", dboundary.report_at_0_eod_full.size());
+void makeBoundaryPrograms(const RoseBuildImpl &build, build_context &bc,
+ const BoundaryReports &boundary,
+ const DerivedBoundaryReports &dboundary,
+ RoseBoundaryReports &out) {
+ DEBUG_PRINTF("report ^: %zu\n", boundary.report_at_0.size());
+ DEBUG_PRINTF("report $: %zu\n", boundary.report_at_eod.size());
+ DEBUG_PRINTF("report ^$: %zu\n", dboundary.report_at_0_eod_full.size());
- auto eod_prog = makeBoundaryProgram(build, boundary.report_at_eod);
- out.reportEodOffset = writeProgram(bc, move(eod_prog));
+ auto eod_prog = makeBoundaryProgram(build, boundary.report_at_eod);
+ out.reportEodOffset = writeProgram(bc, move(eod_prog));
- auto zero_prog = makeBoundaryProgram(build, boundary.report_at_0);
- out.reportZeroOffset = writeProgram(bc, move(zero_prog));
+ auto zero_prog = makeBoundaryProgram(build, boundary.report_at_0);
+ out.reportZeroOffset = writeProgram(bc, move(zero_prog));
- auto zeod_prog = makeBoundaryProgram(build, dboundary.report_at_0_eod_full);
- out.reportZeroEodOffset = writeProgram(bc, move(zeod_prog));
+ auto zeod_prog = makeBoundaryProgram(build, dboundary.report_at_0_eod_full);
+ out.reportZeroEodOffset = writeProgram(bc, move(zeod_prog));
}
static
-unordered_map<RoseVertex, u32> assignStateIndices(const RoseBuildImpl &build) {
- const auto &g = build.g;
+unordered_map<RoseVertex, u32> assignStateIndices(const RoseBuildImpl &build) {
+ const auto &g = build.g;
- u32 state = 0;
- unordered_map<RoseVertex, u32> roleStateIndices;
+ u32 state = 0;
+ unordered_map<RoseVertex, u32> roleStateIndices;
for (auto v : vertices_range(g)) {
- // Virtual vertices (starts, EOD accept vertices) never need state
- // indices.
- if (build.isVirtualVertex(v)) {
+ // Virtual vertices (starts, EOD accept vertices) never need state
+ // indices.
+ if (build.isVirtualVertex(v)) {
continue;
}
-
- // We only need a state index if we have successors that are not
- // eagerly-reported EOD vertices.
- bool needs_state_index = false;
- for (const auto &e : out_edges_range(v, g)) {
- if (!canEagerlyReportAtEod(build, e)) {
- needs_state_index = true;
- break;
- }
+
+ // We only need a state index if we have successors that are not
+ // eagerly-reported EOD vertices.
+ bool needs_state_index = false;
+ for (const auto &e : out_edges_range(v, g)) {
+ if (!canEagerlyReportAtEod(build, e)) {
+ needs_state_index = true;
+ break;
+ }
}
- if (!needs_state_index) {
- continue;
+ if (!needs_state_index) {
+ continue;
}
- /* TODO: also don't need a state index if all edges are nfa based */
- roleStateIndices.emplace(v, state++);
+ /* TODO: also don't need a state index if all edges are nfa based */
+ roleStateIndices.emplace(v, state++);
}
- DEBUG_PRINTF("assigned %u states (from %zu vertices)\n", state,
- num_vertices(g));
-
- return roleStateIndices;
+ DEBUG_PRINTF("assigned %u states (from %zu vertices)\n", state,
+ num_vertices(g));
+
+ return roleStateIndices;
}
static
-bool hasUsefulStops(const left_build_info &build) {
- for (u32 i = 0; i < N_CHARS; i++) {
- if (build.stopAlphabet[i]) {
+bool hasUsefulStops(const left_build_info &build) {
+ for (u32 i = 0; i < N_CHARS; i++) {
+ if (build.stopAlphabet[i]) {
return true;
}
}
@@ -2639,609 +2639,609 @@ bool hasUsefulStops(const left_build_info &build) {
}
static
-void buildLeftInfoTable(const RoseBuildImpl &tbi, build_context &bc,
- const set<u32> &eager_queues, u32 leftfixBeginQueue,
- u32 leftfixCount, vector<LeftNfaInfo> &leftTable,
- u32 *laggedRoseCount, size_t *history) {
- const RoseGraph &g = tbi.g;
- const CompileContext &cc = tbi.cc;
+void buildLeftInfoTable(const RoseBuildImpl &tbi, build_context &bc,
+ const set<u32> &eager_queues, u32 leftfixBeginQueue,
+ u32 leftfixCount, vector<LeftNfaInfo> &leftTable,
+ u32 *laggedRoseCount, size_t *history) {
+ const RoseGraph &g = tbi.g;
+ const CompileContext &cc = tbi.cc;
- unordered_set<u32> done_core;
+ unordered_set<u32> done_core;
- leftTable.resize(leftfixCount);
+ leftTable.resize(leftfixCount);
- u32 lagIndex = 0;
+ u32 lagIndex = 0;
- for (RoseVertex v : vertices_range(g)) {
- if (!g[v].left) {
- continue;
+ for (RoseVertex v : vertices_range(g)) {
+ if (!g[v].left) {
+ continue;
+ }
+ assert(contains(bc.leftfix_info, v));
+ const left_build_info &lbi = bc.leftfix_info.at(v);
+ if (lbi.has_lookaround) {
+ continue;
}
- assert(contains(bc.leftfix_info, v));
- const left_build_info &lbi = bc.leftfix_info.at(v);
- if (lbi.has_lookaround) {
- continue;
- }
- assert(lbi.queue >= leftfixBeginQueue);
- u32 left_index = lbi.queue - leftfixBeginQueue;
- assert(left_index < leftfixCount);
+ assert(lbi.queue >= leftfixBeginQueue);
+ u32 left_index = lbi.queue - leftfixBeginQueue;
+ assert(left_index < leftfixCount);
- /* seedy hack to make miracles more effective.
- *
- * TODO: make miracle seeking not depend on history length and have
- * runt scans */
- if (hasUsefulStops(lbi)) {
- ENSURE_AT_LEAST(history,
- (size_t)MIN(cc.grey.maxHistoryAvailable,
- g[v].left.lag + 1
- + cc.grey.miracleHistoryBonus));
- }
+ /* seedy hack to make miracles more effective.
+ *
+ * TODO: make miracle seeking not depend on history length and have
+ * runt scans */
+ if (hasUsefulStops(lbi)) {
+ ENSURE_AT_LEAST(history,
+ (size_t)MIN(cc.grey.maxHistoryAvailable,
+ g[v].left.lag + 1
+ + cc.grey.miracleHistoryBonus));
+ }
- LeftNfaInfo &left = leftTable[left_index];
- if (!contains(done_core, left_index)) {
- done_core.insert(left_index);
- memset(&left, 0, sizeof(left));
- left.squash_mask = ~0ULL;
+ LeftNfaInfo &left = leftTable[left_index];
+ if (!contains(done_core, left_index)) {
+ done_core.insert(left_index);
+ memset(&left, 0, sizeof(left));
+ left.squash_mask = ~0ULL;
- DEBUG_PRINTF("populating info for %u\n", left_index);
+ DEBUG_PRINTF("populating info for %u\n", left_index);
- left.maxQueueLen = lbi.max_queuelen;
+ left.maxQueueLen = lbi.max_queuelen;
- if (hasUsefulStops(lbi)) {
- assert(lbi.stopAlphabet.size() == N_CHARS);
- left.stopTable = bc.engine_blob.add_range(lbi.stopAlphabet);
- }
+ if (hasUsefulStops(lbi)) {
+ assert(lbi.stopAlphabet.size() == N_CHARS);
+ left.stopTable = bc.engine_blob.add_range(lbi.stopAlphabet);
+ }
- assert(lbi.countingMiracleOffset || !lbi.countingMiracleCount);
- left.countingMiracleOffset = lbi.countingMiracleOffset;
+ assert(lbi.countingMiracleOffset || !lbi.countingMiracleCount);
+ left.countingMiracleOffset = lbi.countingMiracleOffset;
- DEBUG_PRINTF("mw = %u\n", lbi.transient);
- left.transient = verify_u8(lbi.transient);
- left.infix = tbi.isNonRootSuccessor(v);
- left.eager = contains(eager_queues, lbi.queue);
+ DEBUG_PRINTF("mw = %u\n", lbi.transient);
+ left.transient = verify_u8(lbi.transient);
+ left.infix = tbi.isNonRootSuccessor(v);
+ left.eager = contains(eager_queues, lbi.queue);
- // A rose has a lagIndex if it's non-transient and we are
- // streaming.
- if (!lbi.transient && cc.streaming) {
- assert(lagIndex < ROSE_OFFSET_INVALID);
- left.lagIndex = lagIndex++;
- } else {
- left.lagIndex = ROSE_OFFSET_INVALID;
- }
- }
+ // A rose has a lagIndex if it's non-transient and we are
+ // streaming.
+ if (!lbi.transient && cc.streaming) {
+ assert(lagIndex < ROSE_OFFSET_INVALID);
+ left.lagIndex = lagIndex++;
+ } else {
+ left.lagIndex = ROSE_OFFSET_INVALID;
+ }
+ }
- DEBUG_PRINTF("rose %u is %s\n", left_index,
- left.infix ? "infix" : "prefix");
+ DEBUG_PRINTF("rose %u is %s\n", left_index,
+ left.infix ? "infix" : "prefix");
- // Update squash mask.
- left.squash_mask &= lbi.squash_mask;
+ // Update squash mask.
+ left.squash_mask &= lbi.squash_mask;
- // Update the max delay.
- ENSURE_AT_LEAST(&left.maxLag, lbi.lag);
+ // Update the max delay.
+ ENSURE_AT_LEAST(&left.maxLag, lbi.lag);
- if (contains(g[v].literals, tbi.eod_event_literal_id)) {
- left.eod_check = 1;
- }
+ if (contains(g[v].literals, tbi.eod_event_literal_id)) {
+ left.eod_check = 1;
+ }
}
- DEBUG_PRINTF("built %u roses with lag indices\n", lagIndex);
- *laggedRoseCount = lagIndex;
+ DEBUG_PRINTF("built %u roses with lag indices\n", lagIndex);
+ *laggedRoseCount = lagIndex;
}
static
-RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc,
- ProgramBuild &prog_build, u32 lit_id,
- const vector<vector<RoseEdge>> &lit_edge_map,
- bool is_anchored_replay_program) {
- DEBUG_PRINTF("lit_id=%u\n", lit_id);
- assert(lit_id < lit_edge_map.size());
+RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc,
+ ProgramBuild &prog_build, u32 lit_id,
+ const vector<vector<RoseEdge>> &lit_edge_map,
+ bool is_anchored_replay_program) {
+ DEBUG_PRINTF("lit_id=%u\n", lit_id);
+ assert(lit_id < lit_edge_map.size());
- return makeLiteralProgram(build, bc.leftfix_info, bc.suffixes,
- bc.engine_info_by_queue, bc.roleStateIndices,
- prog_build, lit_id, lit_edge_map.at(lit_id),
- is_anchored_replay_program);
+ return makeLiteralProgram(build, bc.leftfix_info, bc.suffixes,
+ bc.engine_info_by_queue, bc.roleStateIndices,
+ prog_build, lit_id, lit_edge_map.at(lit_id),
+ is_anchored_replay_program);
}
static
-RoseProgram makeFragmentProgram(const RoseBuildImpl &build, build_context &bc,
- ProgramBuild &prog_build,
- const vector<u32> &lit_ids,
- const vector<vector<RoseEdge>> &lit_edge_map) {
- assert(!lit_ids.empty());
+RoseProgram makeFragmentProgram(const RoseBuildImpl &build, build_context &bc,
+ ProgramBuild &prog_build,
+ const vector<u32> &lit_ids,
+ const vector<vector<RoseEdge>> &lit_edge_map) {
+ assert(!lit_ids.empty());
- vector<RoseProgram> blocks;
- for (const auto &lit_id : lit_ids) {
- auto prog = makeLiteralProgram(build, bc, prog_build, lit_id,
- lit_edge_map, false);
- blocks.push_back(move(prog));
+ vector<RoseProgram> blocks;
+ for (const auto &lit_id : lit_ids) {
+ auto prog = makeLiteralProgram(build, bc, prog_build, lit_id,
+ lit_edge_map, false);
+ blocks.push_back(move(prog));
}
- return assembleProgramBlocks(move(blocks));
+ return assembleProgramBlocks(move(blocks));
}
-/**
- * \brief Returns a map from literal ID to a list of edges leading into
- * vertices with that literal ID.
- */
+/**
+ * \brief Returns a map from literal ID to a list of edges leading into
+ * vertices with that literal ID.
+ */
static
-vector<vector<RoseEdge>> findEdgesByLiteral(const RoseBuildImpl &build) {
- vector<vector<RoseEdge>> lit_edge_map(build.literals.size());
+vector<vector<RoseEdge>> findEdgesByLiteral(const RoseBuildImpl &build) {
+ vector<vector<RoseEdge>> lit_edge_map(build.literals.size());
- const auto &g = build.g;
- for (const auto &v : vertices_range(g)) {
- for (const auto &lit_id : g[v].literals) {
- assert(lit_id < lit_edge_map.size());
- auto &edge_list = lit_edge_map.at(lit_id);
- insert(&edge_list, edge_list.end(), in_edges(v, g));
- }
- }
+ const auto &g = build.g;
+ for (const auto &v : vertices_range(g)) {
+ for (const auto &lit_id : g[v].literals) {
+ assert(lit_id < lit_edge_map.size());
+ auto &edge_list = lit_edge_map.at(lit_id);
+ insert(&edge_list, edge_list.end(), in_edges(v, g));
+ }
+ }
- // Sort edges in each edge list by (source, target) indices. This gives us
- // less surprising ordering in program generation for a literal with many
- // edges.
- for (auto &edge_list : lit_edge_map) {
- sort(begin(edge_list), end(edge_list), [&g](const RoseEdge &a,
- const RoseEdge &b) {
- return tie(g[source(a, g)].index, g[target(a, g)].index) <
- tie(g[source(b, g)].index, g[target(b, g)].index);
- });
+ // Sort edges in each edge list by (source, target) indices. This gives us
+ // less surprising ordering in program generation for a literal with many
+ // edges.
+ for (auto &edge_list : lit_edge_map) {
+ sort(begin(edge_list), end(edge_list), [&g](const RoseEdge &a,
+ const RoseEdge &b) {
+ return tie(g[source(a, g)].index, g[target(a, g)].index) <
+ tie(g[source(b, g)].index, g[target(b, g)].index);
+ });
}
- return lit_edge_map;
+ return lit_edge_map;
}
static
-bool isUsedLiteral(const RoseBuildImpl &build, u32 lit_id) {
- assert(lit_id < build.literal_info.size());
- const auto &info = build.literal_info[lit_id];
- if (!info.vertices.empty()) {
- return true;
- }
+bool isUsedLiteral(const RoseBuildImpl &build, u32 lit_id) {
+ assert(lit_id < build.literal_info.size());
+ const auto &info = build.literal_info[lit_id];
+ if (!info.vertices.empty()) {
+ return true;
+ }
- for (const u32 &delayed_id : info.delayed_ids) {
- assert(delayed_id < build.literal_info.size());
- const rose_literal_info &delayed_info = build.literal_info[delayed_id];
- if (!delayed_info.vertices.empty()) {
- return true;
- }
+ for (const u32 &delayed_id : info.delayed_ids) {
+ assert(delayed_id < build.literal_info.size());
+ const rose_literal_info &delayed_info = build.literal_info[delayed_id];
+ if (!delayed_info.vertices.empty()) {
+ return true;
+ }
}
- DEBUG_PRINTF("literal %u has no refs\n", lit_id);
- return false;
+ DEBUG_PRINTF("literal %u has no refs\n", lit_id);
+ return false;
}
static
-rose_literal_id getFragment(rose_literal_id lit) {
- if (lit.s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
- // Trim to last ROSE_SHORT_LITERAL_LEN_MAX bytes.
- lit.s.erase(0, lit.s.length() - ROSE_SHORT_LITERAL_LEN_MAX);
+rose_literal_id getFragment(rose_literal_id lit) {
+ if (lit.s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
+ // Trim to last ROSE_SHORT_LITERAL_LEN_MAX bytes.
+ lit.s.erase(0, lit.s.length() - ROSE_SHORT_LITERAL_LEN_MAX);
}
- DEBUG_PRINTF("fragment: %s\n", dumpString(lit.s).c_str());
- return lit;
+ DEBUG_PRINTF("fragment: %s\n", dumpString(lit.s).c_str());
+ return lit;
}
static
-vector<LitFragment> groupByFragment(const RoseBuildImpl &build) {
- vector<LitFragment> fragments;
- u32 frag_id = 0;
+vector<LitFragment> groupByFragment(const RoseBuildImpl &build) {
+ vector<LitFragment> fragments;
+ u32 frag_id = 0;
- struct FragmentInfo {
- vector<u32> lit_ids;
- rose_group groups = 0;
- };
+ struct FragmentInfo {
+ vector<u32> lit_ids;
+ rose_group groups = 0;
+ };
- map<rose_literal_id, FragmentInfo> frag_info;
+ map<rose_literal_id, FragmentInfo> frag_info;
- for (u32 lit_id = 0; lit_id < build.literals.size(); lit_id++) {
- const auto &lit = build.literals.at(lit_id);
- const auto &info = build.literal_info.at(lit_id);
+ for (u32 lit_id = 0; lit_id < build.literals.size(); lit_id++) {
+ const auto &lit = build.literals.at(lit_id);
+ const auto &info = build.literal_info.at(lit_id);
- if (!isUsedLiteral(build, lit_id)) {
- DEBUG_PRINTF("lit %u is unused\n", lit_id);
- continue;
+ if (!isUsedLiteral(build, lit_id)) {
+ DEBUG_PRINTF("lit %u is unused\n", lit_id);
+ continue;
}
- if (lit.table == ROSE_EVENT) {
- DEBUG_PRINTF("lit %u is an event\n", lit_id);
+ if (lit.table == ROSE_EVENT) {
+ DEBUG_PRINTF("lit %u is an event\n", lit_id);
continue;
}
- auto groups = info.group_mask;
+ auto groups = info.group_mask;
- if (lit.s.length() < ROSE_SHORT_LITERAL_LEN_MAX) {
- fragments.emplace_back(frag_id, lit.s, groups, lit_id);
- frag_id++;
- continue;
+ if (lit.s.length() < ROSE_SHORT_LITERAL_LEN_MAX) {
+ fragments.emplace_back(frag_id, lit.s, groups, lit_id);
+ frag_id++;
+ continue;
}
- DEBUG_PRINTF("fragment candidate: lit_id=%u %s\n", lit_id,
- dumpString(lit.s).c_str());
- auto &fi = frag_info[getFragment(lit)];
- fi.lit_ids.push_back(lit_id);
- fi.groups |= groups;
- }
-
- for (auto &m : frag_info) {
- auto &lit = m.first;
- auto &fi = m.second;
- DEBUG_PRINTF("frag %s -> ids: %s\n", dumpString(m.first.s).c_str(),
- as_string_list(fi.lit_ids).c_str());
- fragments.emplace_back(frag_id, lit.s, fi.groups, move(fi.lit_ids));
- frag_id++;
- assert(frag_id == fragments.size());
- }
-
- return fragments;
-}
-
-static
-void buildIncludedIdMap(unordered_map<u32, pair<u32, u8>> &includedIdMap,
- const LitProto *litProto) {
- if (!litProto) {
- return;
- }
- const auto &proto = *litProto->hwlmProto;
- for (const auto &lit : proto.lits) {
- if (contains(includedIdMap, lit.id)) {
- const auto &included_id = includedIdMap[lit.id].first;
- const auto &squash = includedIdMap[lit.id].second;
- // The squash behavior should be the same for the same literal
- // in different literal matchers.
- if (lit.included_id != included_id ||
- lit.squash != squash) {
- includedIdMap[lit.id] = make_pair(INVALID_LIT_ID, 0);
- DEBUG_PRINTF("find different included info for the"
- " same literal\n");
- }
- } else if (lit.included_id != INVALID_LIT_ID) {
- includedIdMap[lit.id] = make_pair(lit.included_id, lit.squash);
- } else {
- includedIdMap[lit.id] = make_pair(INVALID_LIT_ID, 0);
- }
- }
-}
-
-static
-void findInclusionGroups(vector<LitFragment> &fragments,
- LitProto *fproto, LitProto *drproto,
- LitProto *eproto, LitProto *sbproto) {
- unordered_map<u32, pair<u32, u8>> includedIdMap;
- unordered_map<u32, pair<u32, u8>> includedDelayIdMap;
- buildIncludedIdMap(includedIdMap, fproto);
- buildIncludedIdMap(includedDelayIdMap, drproto);
- buildIncludedIdMap(includedIdMap, eproto);
- buildIncludedIdMap(includedIdMap, sbproto);
-
- size_t fragNum = fragments.size();
- vector<u32> candidates;
- for (size_t j = 0; j < fragNum; j++) {
- DEBUG_PRINTF("frag id %lu\n", j);
- u32 id = j;
- if (contains(includedIdMap, id) ||
- contains(includedDelayIdMap, id)) {
- candidates.push_back(j);
- DEBUG_PRINTF("find candidate\n");
- }
- }
-
- for (const auto &c : candidates) {
- auto &frag = fragments[c];
- u32 id = c;
- if (contains(includedIdMap, id) &&
- includedIdMap[id].first != INVALID_LIT_ID) {
- const auto &childId = includedIdMap[id];
- frag.included_frag_id = childId.first;
- frag.squash = childId.second;
- DEBUG_PRINTF("frag id %u child frag id %u\n", c,
- frag.included_frag_id);
- }
-
- if (contains(includedDelayIdMap, id) &&
- includedDelayIdMap[id].first != INVALID_LIT_ID) {
- const auto &childId = includedDelayIdMap[id];
- frag.included_delay_frag_id = childId.first;
- frag.delay_squash = childId.second;
-
- DEBUG_PRINTF("delay frag id %u child frag id %u\n", c,
- frag.included_delay_frag_id);
- }
- }
-}
-
-static
-void buildFragmentPrograms(const RoseBuildImpl &build,
- vector<LitFragment> &fragments,
- build_context &bc, ProgramBuild &prog_build,
- const vector<vector<RoseEdge>> &lit_edge_map) {
- // Sort fragments based on literal length and case info to build
- // included literal programs before their parent programs.
- vector<LitFragment> ordered_fragments(fragments);
- stable_sort(begin(ordered_fragments), end(ordered_fragments),
- [](const LitFragment &a, const LitFragment &b) {
- auto len1 = a.s.length();
- auto caseful1 = !a.s.any_nocase();
- auto len2 = b.s.length();
- auto caseful2 = !b.s.any_nocase();
- return tie(len1, caseful1) < tie(len2, caseful2);
- });
-
- for (auto &frag : ordered_fragments) {
- auto &pfrag = fragments[frag.fragment_id];
- DEBUG_PRINTF("frag_id=%u, lit_ids=[%s]\n", pfrag.fragment_id,
- as_string_list(pfrag.lit_ids).c_str());
-
- auto lit_prog = makeFragmentProgram(build, bc, prog_build,
- pfrag.lit_ids, lit_edge_map);
- if (pfrag.included_frag_id != INVALID_FRAG_ID &&
- !lit_prog.empty()) {
- auto &cfrag = fragments[pfrag.included_frag_id];
- assert(pfrag.s.length() >= cfrag.s.length() &&
- !pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
- u32 child_offset = cfrag.lit_program_offset;
- DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
- child_offset);
- addIncludedJumpProgram(lit_prog, child_offset, pfrag.squash);
- }
- pfrag.lit_program_offset = writeProgram(bc, move(lit_prog));
-
- // We only do delayed rebuild in streaming mode.
- if (!build.cc.streaming) {
+ DEBUG_PRINTF("fragment candidate: lit_id=%u %s\n", lit_id,
+ dumpString(lit.s).c_str());
+ auto &fi = frag_info[getFragment(lit)];
+ fi.lit_ids.push_back(lit_id);
+ fi.groups |= groups;
+ }
+
+ for (auto &m : frag_info) {
+ auto &lit = m.first;
+ auto &fi = m.second;
+ DEBUG_PRINTF("frag %s -> ids: %s\n", dumpString(m.first.s).c_str(),
+ as_string_list(fi.lit_ids).c_str());
+ fragments.emplace_back(frag_id, lit.s, fi.groups, move(fi.lit_ids));
+ frag_id++;
+ assert(frag_id == fragments.size());
+ }
+
+ return fragments;
+}
+
+static
+void buildIncludedIdMap(unordered_map<u32, pair<u32, u8>> &includedIdMap,
+ const LitProto *litProto) {
+ if (!litProto) {
+ return;
+ }
+ const auto &proto = *litProto->hwlmProto;
+ for (const auto &lit : proto.lits) {
+ if (contains(includedIdMap, lit.id)) {
+ const auto &included_id = includedIdMap[lit.id].first;
+ const auto &squash = includedIdMap[lit.id].second;
+ // The squash behavior should be the same for the same literal
+ // in different literal matchers.
+ if (lit.included_id != included_id ||
+ lit.squash != squash) {
+ includedIdMap[lit.id] = make_pair(INVALID_LIT_ID, 0);
+ DEBUG_PRINTF("find different included info for the"
+ " same literal\n");
+ }
+ } else if (lit.included_id != INVALID_LIT_ID) {
+ includedIdMap[lit.id] = make_pair(lit.included_id, lit.squash);
+ } else {
+ includedIdMap[lit.id] = make_pair(INVALID_LIT_ID, 0);
+ }
+ }
+}
+
+static
+void findInclusionGroups(vector<LitFragment> &fragments,
+ LitProto *fproto, LitProto *drproto,
+ LitProto *eproto, LitProto *sbproto) {
+ unordered_map<u32, pair<u32, u8>> includedIdMap;
+ unordered_map<u32, pair<u32, u8>> includedDelayIdMap;
+ buildIncludedIdMap(includedIdMap, fproto);
+ buildIncludedIdMap(includedDelayIdMap, drproto);
+ buildIncludedIdMap(includedIdMap, eproto);
+ buildIncludedIdMap(includedIdMap, sbproto);
+
+ size_t fragNum = fragments.size();
+ vector<u32> candidates;
+ for (size_t j = 0; j < fragNum; j++) {
+ DEBUG_PRINTF("frag id %lu\n", j);
+ u32 id = j;
+ if (contains(includedIdMap, id) ||
+ contains(includedDelayIdMap, id)) {
+ candidates.push_back(j);
+ DEBUG_PRINTF("find candidate\n");
+ }
+ }
+
+ for (const auto &c : candidates) {
+ auto &frag = fragments[c];
+ u32 id = c;
+ if (contains(includedIdMap, id) &&
+ includedIdMap[id].first != INVALID_LIT_ID) {
+ const auto &childId = includedIdMap[id];
+ frag.included_frag_id = childId.first;
+ frag.squash = childId.second;
+ DEBUG_PRINTF("frag id %u child frag id %u\n", c,
+ frag.included_frag_id);
+ }
+
+ if (contains(includedDelayIdMap, id) &&
+ includedDelayIdMap[id].first != INVALID_LIT_ID) {
+ const auto &childId = includedDelayIdMap[id];
+ frag.included_delay_frag_id = childId.first;
+ frag.delay_squash = childId.second;
+
+ DEBUG_PRINTF("delay frag id %u child frag id %u\n", c,
+ frag.included_delay_frag_id);
+ }
+ }
+}
+
+static
+void buildFragmentPrograms(const RoseBuildImpl &build,
+ vector<LitFragment> &fragments,
+ build_context &bc, ProgramBuild &prog_build,
+ const vector<vector<RoseEdge>> &lit_edge_map) {
+ // Sort fragments based on literal length and case info to build
+ // included literal programs before their parent programs.
+ vector<LitFragment> ordered_fragments(fragments);
+ stable_sort(begin(ordered_fragments), end(ordered_fragments),
+ [](const LitFragment &a, const LitFragment &b) {
+ auto len1 = a.s.length();
+ auto caseful1 = !a.s.any_nocase();
+ auto len2 = b.s.length();
+ auto caseful2 = !b.s.any_nocase();
+ return tie(len1, caseful1) < tie(len2, caseful2);
+ });
+
+ for (auto &frag : ordered_fragments) {
+ auto &pfrag = fragments[frag.fragment_id];
+ DEBUG_PRINTF("frag_id=%u, lit_ids=[%s]\n", pfrag.fragment_id,
+ as_string_list(pfrag.lit_ids).c_str());
+
+ auto lit_prog = makeFragmentProgram(build, bc, prog_build,
+ pfrag.lit_ids, lit_edge_map);
+ if (pfrag.included_frag_id != INVALID_FRAG_ID &&
+ !lit_prog.empty()) {
+ auto &cfrag = fragments[pfrag.included_frag_id];
+ assert(pfrag.s.length() >= cfrag.s.length() &&
+ !pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
+ u32 child_offset = cfrag.lit_program_offset;
+ DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
+ child_offset);
+ addIncludedJumpProgram(lit_prog, child_offset, pfrag.squash);
+ }
+ pfrag.lit_program_offset = writeProgram(bc, move(lit_prog));
+
+ // We only do delayed rebuild in streaming mode.
+ if (!build.cc.streaming) {
continue;
}
- auto rebuild_prog = makeDelayRebuildProgram(build, prog_build,
- pfrag.lit_ids);
- if (pfrag.included_delay_frag_id != INVALID_FRAG_ID &&
- !rebuild_prog.empty()) {
- auto &cfrag = fragments[pfrag.included_delay_frag_id];
- assert(pfrag.s.length() >= cfrag.s.length() &&
- !pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
- u32 child_offset = cfrag.delay_program_offset;
- DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
- child_offset);
- addIncludedJumpProgram(rebuild_prog, child_offset,
- pfrag.delay_squash);
+ auto rebuild_prog = makeDelayRebuildProgram(build, prog_build,
+ pfrag.lit_ids);
+ if (pfrag.included_delay_frag_id != INVALID_FRAG_ID &&
+ !rebuild_prog.empty()) {
+ auto &cfrag = fragments[pfrag.included_delay_frag_id];
+ assert(pfrag.s.length() >= cfrag.s.length() &&
+ !pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
+ u32 child_offset = cfrag.delay_program_offset;
+ DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
+ child_offset);
+ addIncludedJumpProgram(rebuild_prog, child_offset,
+ pfrag.delay_squash);
}
- pfrag.delay_program_offset = writeProgram(bc, move(rebuild_prog));
+ pfrag.delay_program_offset = writeProgram(bc, move(rebuild_prog));
}
}
-static
-void updateLitProtoProgramOffset(vector<LitFragment> &fragments,
- LitProto &litProto, bool delay) {
- auto &proto = *litProto.hwlmProto;
- for (auto &lit : proto.lits) {
- auto fragId = lit.id;
- auto &frag = fragments[fragId];
- if (delay) {
- DEBUG_PRINTF("delay_program_offset:%u\n",
- frag.delay_program_offset);
- lit.id = frag.delay_program_offset;
- } else {
- DEBUG_PRINTF("lit_program_offset:%u\n",
- frag.lit_program_offset);
- lit.id = frag.lit_program_offset;
- }
+static
+void updateLitProtoProgramOffset(vector<LitFragment> &fragments,
+ LitProto &litProto, bool delay) {
+ auto &proto = *litProto.hwlmProto;
+ for (auto &lit : proto.lits) {
+ auto fragId = lit.id;
+ auto &frag = fragments[fragId];
+ if (delay) {
+ DEBUG_PRINTF("delay_program_offset:%u\n",
+ frag.delay_program_offset);
+ lit.id = frag.delay_program_offset;
+ } else {
+ DEBUG_PRINTF("lit_program_offset:%u\n",
+ frag.lit_program_offset);
+ lit.id = frag.lit_program_offset;
+ }
}
}
static
-void updateLitProgramOffset(vector<LitFragment> &fragments,
- LitProto *fproto, LitProto *drproto,
- LitProto *eproto, LitProto *sbproto) {
- if (fproto) {
- updateLitProtoProgramOffset(fragments, *fproto, false);
- }
+void updateLitProgramOffset(vector<LitFragment> &fragments,
+ LitProto *fproto, LitProto *drproto,
+ LitProto *eproto, LitProto *sbproto) {
+ if (fproto) {
+ updateLitProtoProgramOffset(fragments, *fproto, false);
+ }
- if (drproto) {
- updateLitProtoProgramOffset(fragments, *drproto, true);
- }
+ if (drproto) {
+ updateLitProtoProgramOffset(fragments, *drproto, true);
+ }
- if (eproto) {
- updateLitProtoProgramOffset(fragments, *eproto, false);
+ if (eproto) {
+ updateLitProtoProgramOffset(fragments, *eproto, false);
}
- if (sbproto) {
- updateLitProtoProgramOffset(fragments, *sbproto, false);
+ if (sbproto) {
+ updateLitProtoProgramOffset(fragments, *sbproto, false);
}
}
-/**
- * \brief Build the interpreter programs for each literal.
- */
+/**
+ * \brief Build the interpreter programs for each literal.
+ */
static
-void buildLiteralPrograms(const RoseBuildImpl &build,
- vector<LitFragment> &fragments, build_context &bc,
- ProgramBuild &prog_build, LitProto *fproto,
- LitProto *drproto, LitProto *eproto,
- LitProto *sbproto) {
- DEBUG_PRINTF("%zu fragments\n", fragments.size());
- auto lit_edge_map = findEdgesByLiteral(build);
-
- findInclusionGroups(fragments, fproto, drproto, eproto, sbproto);
-
- buildFragmentPrograms(build, fragments, bc, prog_build, lit_edge_map);
-
- // update literal program offsets for literal matcher prototypes
- updateLitProgramOffset(fragments, fproto, drproto, eproto, sbproto);
-}
-
-/**
- * \brief Write delay replay programs to the bytecode.
- *
- * Returns the offset of the beginning of the program array, and the number of
- * programs.
- */
-static
-pair<u32, u32> writeDelayPrograms(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments,
- build_context &bc,
- ProgramBuild &prog_build) {
- auto lit_edge_map = findEdgesByLiteral(build);
-
- vector<u32> programs; // program offsets indexed by (delayed) lit id
- unordered_map<u32, u32> cache; // program offsets we have already seen
-
- for (const auto &frag : fragments) {
- for (const u32 lit_id : frag.lit_ids) {
- const auto &info = build.literal_info.at(lit_id);
-
- for (const auto &delayed_lit_id : info.delayed_ids) {
- DEBUG_PRINTF("lit id %u delay id %u\n", lit_id, delayed_lit_id);
- auto prog = makeLiteralProgram(build, bc, prog_build,
- delayed_lit_id, lit_edge_map,
- false);
- u32 offset = writeProgram(bc, move(prog));
-
- u32 delay_id;
- auto it = cache.find(offset);
- if (it != end(cache)) {
- delay_id = it->second;
- DEBUG_PRINTF("reusing delay_id %u for offset %u\n",
- delay_id, offset);
- } else {
- delay_id = verify_u32(programs.size());
- programs.push_back(offset);
- cache.emplace(offset, delay_id);
- DEBUG_PRINTF("assigned new delay_id %u for offset %u\n",
- delay_id, offset);
- }
- prog_build.delay_programs.emplace(delayed_lit_id, delay_id);
- }
- }
- }
-
- DEBUG_PRINTF("%zu delay programs\n", programs.size());
- return {bc.engine_blob.add_range(programs), verify_u32(programs.size())};
-}
-
-/**
- * \brief Write anchored replay programs to the bytecode.
- *
- * Returns the offset of the beginning of the program array, and the number of
- * programs.
- */
+void buildLiteralPrograms(const RoseBuildImpl &build,
+ vector<LitFragment> &fragments, build_context &bc,
+ ProgramBuild &prog_build, LitProto *fproto,
+ LitProto *drproto, LitProto *eproto,
+ LitProto *sbproto) {
+ DEBUG_PRINTF("%zu fragments\n", fragments.size());
+ auto lit_edge_map = findEdgesByLiteral(build);
+
+ findInclusionGroups(fragments, fproto, drproto, eproto, sbproto);
+
+ buildFragmentPrograms(build, fragments, bc, prog_build, lit_edge_map);
+
+ // update literal program offsets for literal matcher prototypes
+ updateLitProgramOffset(fragments, fproto, drproto, eproto, sbproto);
+}
+
+/**
+ * \brief Write delay replay programs to the bytecode.
+ *
+ * Returns the offset of the beginning of the program array, and the number of
+ * programs.
+ */
static
-pair<u32, u32> writeAnchoredPrograms(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments,
- build_context &bc,
- ProgramBuild &prog_build) {
- auto lit_edge_map = findEdgesByLiteral(build);
+pair<u32, u32> writeDelayPrograms(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments,
+ build_context &bc,
+ ProgramBuild &prog_build) {
+ auto lit_edge_map = findEdgesByLiteral(build);
+
+ vector<u32> programs; // program offsets indexed by (delayed) lit id
+ unordered_map<u32, u32> cache; // program offsets we have already seen
+
+ for (const auto &frag : fragments) {
+ for (const u32 lit_id : frag.lit_ids) {
+ const auto &info = build.literal_info.at(lit_id);
+
+ for (const auto &delayed_lit_id : info.delayed_ids) {
+ DEBUG_PRINTF("lit id %u delay id %u\n", lit_id, delayed_lit_id);
+ auto prog = makeLiteralProgram(build, bc, prog_build,
+ delayed_lit_id, lit_edge_map,
+ false);
+ u32 offset = writeProgram(bc, move(prog));
+
+ u32 delay_id;
+ auto it = cache.find(offset);
+ if (it != end(cache)) {
+ delay_id = it->second;
+ DEBUG_PRINTF("reusing delay_id %u for offset %u\n",
+ delay_id, offset);
+ } else {
+ delay_id = verify_u32(programs.size());
+ programs.push_back(offset);
+ cache.emplace(offset, delay_id);
+ DEBUG_PRINTF("assigned new delay_id %u for offset %u\n",
+ delay_id, offset);
+ }
+ prog_build.delay_programs.emplace(delayed_lit_id, delay_id);
+ }
+ }
+ }
- vector<u32> programs; // program offsets indexed by anchored id
- unordered_map<u32, u32> cache; // program offsets we have already seen
+ DEBUG_PRINTF("%zu delay programs\n", programs.size());
+ return {bc.engine_blob.add_range(programs), verify_u32(programs.size())};
+}
- for (const auto &frag : fragments) {
- for (const u32 lit_id : frag.lit_ids) {
- const auto &lit = build.literals.at(lit_id);
+/**
+ * \brief Write anchored replay programs to the bytecode.
+ *
+ * Returns the offset of the beginning of the program array, and the number of
+ * programs.
+ */
+static
+pair<u32, u32> writeAnchoredPrograms(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments,
+ build_context &bc,
+ ProgramBuild &prog_build) {
+ auto lit_edge_map = findEdgesByLiteral(build);
- if (lit.table != ROSE_ANCHORED) {
- continue;
- }
+ vector<u32> programs; // program offsets indexed by anchored id
+ unordered_map<u32, u32> cache; // program offsets we have already seen
- // If this anchored literal can never match past
- // floatingMinLiteralMatchOffset, we will never have to record it.
- if (findMaxOffset(build, lit_id)
- <= prog_build.floatingMinLiteralMatchOffset) {
- DEBUG_PRINTF("can never match after "
- "floatingMinLiteralMatchOffset=%u\n",
- prog_build.floatingMinLiteralMatchOffset);
- continue;
- }
+ for (const auto &frag : fragments) {
+ for (const u32 lit_id : frag.lit_ids) {
+ const auto &lit = build.literals.at(lit_id);
- auto prog = makeLiteralProgram(build, bc, prog_build, lit_id,
- lit_edge_map, true);
- u32 offset = writeProgram(bc, move(prog));
- DEBUG_PRINTF("lit_id=%u -> anch prog at %u\n", lit_id, offset);
+ if (lit.table != ROSE_ANCHORED) {
+ continue;
+ }
- u32 anch_id;
- auto it = cache.find(offset);
- if (it != end(cache)) {
- anch_id = it->second;
- DEBUG_PRINTF("reusing anch_id %u for offset %u\n", anch_id,
- offset);
- } else {
- anch_id = verify_u32(programs.size());
- programs.push_back(offset);
- cache.emplace(offset, anch_id);
- DEBUG_PRINTF("assigned new anch_id %u for offset %u\n", anch_id,
- offset);
- }
- prog_build.anchored_programs.emplace(lit_id, anch_id);
- }
- }
-
- DEBUG_PRINTF("%zu anchored programs\n", programs.size());
- return {bc.engine_blob.add_range(programs), verify_u32(programs.size())};
-}
-
-/**
- * \brief Returns all reports used by output-exposed engines, for which we need
- * to generate programs.
- */
-static
-set<ReportID> findEngineReports(const RoseBuildImpl &build) {
- set<ReportID> reports;
-
- // The small write engine uses these engine report programs.
- insert(&reports, build.smwr.all_reports());
+ // If this anchored literal can never match past
+ // floatingMinLiteralMatchOffset, we will never have to record it.
+ if (findMaxOffset(build, lit_id)
+ <= prog_build.floatingMinLiteralMatchOffset) {
+ DEBUG_PRINTF("can never match after "
+ "floatingMinLiteralMatchOffset=%u\n",
+ prog_build.floatingMinLiteralMatchOffset);
+ continue;
+ }
- for (const auto &outfix : build.outfixes) {
- insert(&reports, all_reports(outfix));
+ auto prog = makeLiteralProgram(build, bc, prog_build, lit_id,
+ lit_edge_map, true);
+ u32 offset = writeProgram(bc, move(prog));
+ DEBUG_PRINTF("lit_id=%u -> anch prog at %u\n", lit_id, offset);
+
+ u32 anch_id;
+ auto it = cache.find(offset);
+ if (it != end(cache)) {
+ anch_id = it->second;
+ DEBUG_PRINTF("reusing anch_id %u for offset %u\n", anch_id,
+ offset);
+ } else {
+ anch_id = verify_u32(programs.size());
+ programs.push_back(offset);
+ cache.emplace(offset, anch_id);
+ DEBUG_PRINTF("assigned new anch_id %u for offset %u\n", anch_id,
+ offset);
+ }
+ prog_build.anchored_programs.emplace(lit_id, anch_id);
+ }
}
- const auto &g = build.g;
- for (auto v : vertices_range(g)) {
- if (g[v].suffix) {
- insert(&reports, all_reports(g[v].suffix));
+ DEBUG_PRINTF("%zu anchored programs\n", programs.size());
+ return {bc.engine_blob.add_range(programs), verify_u32(programs.size())};
+}
+
+/**
+ * \brief Returns all reports used by output-exposed engines, for which we need
+ * to generate programs.
+ */
+static
+set<ReportID> findEngineReports(const RoseBuildImpl &build) {
+ set<ReportID> reports;
+
+ // The small write engine uses these engine report programs.
+ insert(&reports, build.smwr.all_reports());
+
+ for (const auto &outfix : build.outfixes) {
+ insert(&reports, all_reports(outfix));
+ }
+
+ const auto &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (g[v].suffix) {
+ insert(&reports, all_reports(g[v].suffix));
}
}
- DEBUG_PRINTF("%zu engine reports (of %zu)\n", reports.size(),
- build.rm.numReports());
- return reports;
+ DEBUG_PRINTF("%zu engine reports (of %zu)\n", reports.size(),
+ build.rm.numReports());
+ return reports;
}
static
-pair<u32, u32> buildReportPrograms(const RoseBuildImpl &build,
- build_context &bc) {
- const auto reports = findEngineReports(build);
- vector<u32> programs;
- programs.reserve(reports.size());
+pair<u32, u32> buildReportPrograms(const RoseBuildImpl &build,
+ build_context &bc) {
+ const auto reports = findEngineReports(build);
+ vector<u32> programs;
+ programs.reserve(reports.size());
- for (ReportID id : reports) {
- auto program = makeReportProgram(build, bc.needs_mpv_catchup, id);
- u32 offset = writeProgram(bc, move(program));
- programs.push_back(offset);
- build.rm.setProgramOffset(id, offset);
- DEBUG_PRINTF("program for report %u @ %u (%zu instructions)\n", id,
- programs.back(), program.size());
+ for (ReportID id : reports) {
+ auto program = makeReportProgram(build, bc.needs_mpv_catchup, id);
+ u32 offset = writeProgram(bc, move(program));
+ programs.push_back(offset);
+ build.rm.setProgramOffset(id, offset);
+ DEBUG_PRINTF("program for report %u @ %u (%zu instructions)\n", id,
+ programs.back(), program.size());
}
- u32 offset = bc.engine_blob.add_range(programs);
- u32 count = verify_u32(programs.size());
- return {offset, count};
+ u32 offset = bc.engine_blob.add_range(programs);
+ u32 count = verify_u32(programs.size());
+ return {offset, count};
}
static
-bool hasEodAnchoredSuffix(const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
- for (auto v : vertices_range(g)) {
- if (g[v].suffix && build.isInETable(v)) {
- DEBUG_PRINTF("vertex %zu is in eod table and has a suffix\n",
- g[v].index);
- return true;
+bool hasEodAnchoredSuffix(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (g[v].suffix && build.isInETable(v)) {
+ DEBUG_PRINTF("vertex %zu is in eod table and has a suffix\n",
+ g[v].index);
+ return true;
}
}
- return false;
+ return false;
}
static
-bool hasEodMatcher(const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
- for (auto v : vertices_range(g)) {
- if (build.isInETable(v)) {
- DEBUG_PRINTF("vertex %zu is in eod table\n", g[v].index);
+bool hasEodMatcher(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (build.isInETable(v)) {
+ DEBUG_PRINTF("vertex %zu is in eod table\n", g[v].index);
return true;
}
}
@@ -3249,104 +3249,104 @@ bool hasEodMatcher(const RoseBuildImpl &build) {
}
static
-void addEodAnchorProgram(const RoseBuildImpl &build, const build_context &bc,
- ProgramBuild &prog_build, bool in_etable,
- RoseProgram &program) {
- const RoseGraph &g = build.g;
+void addEodAnchorProgram(const RoseBuildImpl &build, const build_context &bc,
+ ProgramBuild &prog_build, bool in_etable,
+ RoseProgram &program) {
+ const RoseGraph &g = build.g;
- // Predecessor state id -> program block.
- map<u32, RoseProgram> pred_blocks;
+ // Predecessor state id -> program block.
+ map<u32, RoseProgram> pred_blocks;
- for (auto v : vertices_range(g)) {
- if (!g[v].eod_accept) {
+ for (auto v : vertices_range(g)) {
+ if (!g[v].eod_accept) {
continue;
}
- DEBUG_PRINTF("vertex %zu (with %zu preds) fires on EOD\n", g[v].index,
- in_degree(v, g));
+ DEBUG_PRINTF("vertex %zu (with %zu preds) fires on EOD\n", g[v].index,
+ in_degree(v, g));
- vector<RoseEdge> edge_list;
- for (const auto &e : in_edges_range(v, g)) {
- RoseVertex u = source(e, g);
- if (build.isInETable(u) != in_etable) {
- DEBUG_PRINTF("pred %zu %s in etable\n", g[u].index,
- in_etable ? "is not" : "is");
- continue;
+ vector<RoseEdge> edge_list;
+ for (const auto &e : in_edges_range(v, g)) {
+ RoseVertex u = source(e, g);
+ if (build.isInETable(u) != in_etable) {
+ DEBUG_PRINTF("pred %zu %s in etable\n", g[u].index,
+ in_etable ? "is not" : "is");
+ continue;
}
- if (canEagerlyReportAtEod(build, e)) {
- DEBUG_PRINTF("already done report for vertex %zu\n",
- g[u].index);
- continue;
+ if (canEagerlyReportAtEod(build, e)) {
+ DEBUG_PRINTF("already done report for vertex %zu\n",
+ g[u].index);
+ continue;
}
- edge_list.push_back(e);
+ edge_list.push_back(e);
}
- const bool multiple_preds = edge_list.size() > 1;
- for (const auto &e : edge_list) {
- RoseVertex u = source(e, g);
- assert(contains(bc.roleStateIndices, u));
- u32 pred_state = bc.roleStateIndices.at(u);
- pred_blocks[pred_state].add_block(
- makeEodAnchorProgram(build, prog_build, e, multiple_preds));
+ const bool multiple_preds = edge_list.size() > 1;
+ for (const auto &e : edge_list) {
+ RoseVertex u = source(e, g);
+ assert(contains(bc.roleStateIndices, u));
+ u32 pred_state = bc.roleStateIndices.at(u);
+ pred_blocks[pred_state].add_block(
+ makeEodAnchorProgram(build, prog_build, e, multiple_preds));
}
}
- addPredBlocks(pred_blocks, bc.roleStateIndices.size(), program);
+ addPredBlocks(pred_blocks, bc.roleStateIndices.size(), program);
}
static
-void addEodEventProgram(const RoseBuildImpl &build, build_context &bc,
- ProgramBuild &prog_build, RoseProgram &program) {
- if (build.eod_event_literal_id == MO_INVALID_IDX) {
- return;
- }
+void addEodEventProgram(const RoseBuildImpl &build, build_context &bc,
+ ProgramBuild &prog_build, RoseProgram &program) {
+ if (build.eod_event_literal_id == MO_INVALID_IDX) {
+ return;
+ }
- const RoseGraph &g = build.g;
- const auto &lit_info = build.literal_info.at(build.eod_event_literal_id);
- assert(lit_info.delayed_ids.empty());
- assert(!lit_info.squash_group);
- assert(!lit_info.requires_benefits);
-
- // Collect all edges leading into EOD event literal vertices.
- vector<RoseEdge> edge_list;
- for (const auto &v : lit_info.vertices) {
- for (const auto &e : in_edges_range(v, g)) {
- edge_list.push_back(e);
+ const RoseGraph &g = build.g;
+ const auto &lit_info = build.literal_info.at(build.eod_event_literal_id);
+ assert(lit_info.delayed_ids.empty());
+ assert(!lit_info.squash_group);
+ assert(!lit_info.requires_benefits);
+
+ // Collect all edges leading into EOD event literal vertices.
+ vector<RoseEdge> edge_list;
+ for (const auto &v : lit_info.vertices) {
+ for (const auto &e : in_edges_range(v, g)) {
+ edge_list.push_back(e);
}
- }
+ }
- // Sort edge list for determinism, prettiness.
- sort(begin(edge_list), end(edge_list),
- [&g](const RoseEdge &a, const RoseEdge &b) {
- return tie(g[source(a, g)].index, g[target(a, g)].index) <
- tie(g[source(b, g)].index, g[target(b, g)].index);
- });
+ // Sort edge list for determinism, prettiness.
+ sort(begin(edge_list), end(edge_list),
+ [&g](const RoseEdge &a, const RoseEdge &b) {
+ return tie(g[source(a, g)].index, g[target(a, g)].index) <
+ tie(g[source(b, g)].index, g[target(b, g)].index);
+ });
- auto block = makeLiteralProgram(build, bc.leftfix_info, bc.suffixes,
- bc.engine_info_by_queue,
- bc.roleStateIndices, prog_build,
- build.eod_event_literal_id, edge_list,
- false);
- program.add_block(move(block));
+ auto block = makeLiteralProgram(build, bc.leftfix_info, bc.suffixes,
+ bc.engine_info_by_queue,
+ bc.roleStateIndices, prog_build,
+ build.eod_event_literal_id, edge_list,
+ false);
+ program.add_block(move(block));
}
static
-RoseProgram makeEodProgram(const RoseBuildImpl &build, build_context &bc,
- ProgramBuild &prog_build, u32 eodNfaIterOffset) {
- RoseProgram program;
+RoseProgram makeEodProgram(const RoseBuildImpl &build, build_context &bc,
+ ProgramBuild &prog_build, u32 eodNfaIterOffset) {
+ RoseProgram program;
- addEodEventProgram(build, bc, prog_build, program);
- addEnginesEodProgram(eodNfaIterOffset, program);
- addEodAnchorProgram(build, bc, prog_build, false, program);
- if (hasEodMatcher(build)) {
- addMatcherEodProgram(program);
+ addEodEventProgram(build, bc, prog_build, program);
+ addEnginesEodProgram(eodNfaIterOffset, program);
+ addEodAnchorProgram(build, bc, prog_build, false, program);
+ if (hasEodMatcher(build)) {
+ addMatcherEodProgram(program);
+ }
+ addEodAnchorProgram(build, bc, prog_build, true, program);
+ if (hasEodAnchoredSuffix(build)) {
+ addSuffixesEodProgram(program);
}
- addEodAnchorProgram(build, bc, prog_build, true, program);
- if (hasEodAnchoredSuffix(build)) {
- addSuffixesEodProgram(program);
- }
- return program;
+ return program;
}
static
@@ -3396,13 +3396,13 @@ void fillMatcherDistances(const RoseBuildImpl &build, RoseEngine *engine) {
assert(g[v].min_offset <= g[v].max_offset);
for (u32 lit_id : g[v].literals) {
- const rose_literal_id &key = build.literals.at(lit_id);
+ const rose_literal_id &key = build.literals.at(lit_id);
u32 max_d = g[v].max_offset;
u32 min_d = g[v].min_offset;
- DEBUG_PRINTF("checking %u: elen %zu min/max %u/%u\n", lit_id,
- key.elength_including_mask(), min_d, max_d);
-
+ DEBUG_PRINTF("checking %u: elen %zu min/max %u/%u\n", lit_id,
+ key.elength_including_mask(), min_d, max_d);
+
if (build.literal_info[lit_id].undelayed_id != lit_id) {
/* this is a delayed match; need to update delay properties */
/* TODO: can delayed literals ever be in another table ? */
@@ -3422,9 +3422,9 @@ void fillMatcherDistances(const RoseBuildImpl &build, RoseEngine *engine) {
switch (key.table) {
case ROSE_FLOATING:
ENSURE_AT_LEAST(&engine->floatingDistance, max_d);
- if (min_d >= key.elength_including_mask()) {
+ if (min_d >= key.elength_including_mask()) {
LIMIT_TO_AT_MOST(&engine->floatingMinDistance,
- min_d - (u32)key.elength_including_mask());
+ min_d - (u32)key.elength_including_mask());
} else {
/* overlapped literals from rose + anchored table can
* cause us to underflow due to sloppiness in
@@ -3466,272 +3466,272 @@ void fillMatcherDistances(const RoseBuildImpl &build, RoseEngine *engine) {
if (!engine->anchoredDistance) {
return;
}
-}
+}
-static
-u32 writeEagerQueueIter(const set<u32> &eager, u32 leftfixBeginQueue,
- u32 queue_count, RoseEngineBlob &engine_blob) {
- if (eager.empty()) {
- return 0;
- }
-
- vector<u32> vec;
- for (u32 q : eager) {
- assert(q >= leftfixBeginQueue);
- vec.push_back(q - leftfixBeginQueue);
- }
-
- auto iter = mmbBuildSparseIterator(vec, queue_count - leftfixBeginQueue);
- return engine_blob.add_iterator(iter);
-}
-
-static
-bytecode_ptr<RoseEngine> addSmallWriteEngine(const RoseBuildImpl &build,
- const RoseResources &res,
- bytecode_ptr<RoseEngine> rose) {
- assert(rose);
-
- if (roseIsPureLiteral(rose.get())) {
- DEBUG_PRINTF("pure literal case, not adding smwr\n");
- return rose;
- }
-
- u32 qual = roseQuality(res, rose.get());
- auto smwr_engine = build.smwr.build(qual);
- if (!smwr_engine) {
- DEBUG_PRINTF("no smwr built\n");
- return rose;
- }
-
- const size_t mainSize = rose.size();
- const size_t smallWriteSize = smwr_engine.size();
- DEBUG_PRINTF("adding smwr engine, size=%zu\n", smallWriteSize);
-
- const size_t smwrOffset = ROUNDUP_CL(mainSize);
- const size_t newSize = smwrOffset + smallWriteSize;
-
- auto rose2 = make_zeroed_bytecode_ptr<RoseEngine>(newSize, 64);
- char *ptr = (char *)rose2.get();
- memcpy(ptr, rose.get(), mainSize);
- memcpy(ptr + smwrOffset, smwr_engine.get(), smallWriteSize);
-
- rose2->smallWriteOffset = verify_u32(smwrOffset);
- rose2->size = verify_u32(newSize);
-
- return rose2;
-}
-
-/**
- * \brief Returns the pair (number of literals, max length) for all real
- * literals in the floating table that are in-use.
- */
-static
-pair<size_t, size_t> floatingCountAndMaxLen(const RoseBuildImpl &build) {
- size_t num = 0;
- size_t max_len = 0;
-
- for (u32 id = 0; id < build.literals.size(); id++) {
- const rose_literal_id &lit = build.literals.at(id);
-
- if (lit.table != ROSE_FLOATING) {
- continue;
- }
- if (lit.delay) {
- // Skip delayed literals, so that we only count the undelayed
- // version that ends up in the HWLM table.
- continue;
- }
- if (!isUsedLiteral(build, id)) {
- continue;
- }
-
- num++;
- max_len = max(max_len, lit.s.length());
- }
- DEBUG_PRINTF("%zu floating literals with max_len=%zu\n", num, max_len);
- return {num, max_len};
-}
-
-size_t calcLongLitThreshold(const RoseBuildImpl &build,
- const size_t historyRequired) {
- const auto &cc = build.cc;
-
- // In block mode, we don't have history, so we don't need long literal
- // support and can just use "medium-length" literal confirm. TODO: we could
- // specialize further and have a block mode literal confirm instruction.
- if (!cc.streaming) {
- return SIZE_MAX;
- }
-
- size_t longLitLengthThreshold = ROSE_LONG_LITERAL_THRESHOLD_MIN;
-
- // Expand to size of history we've already allocated. Note that we need N-1
- // bytes of history to match a literal of length N.
- longLitLengthThreshold = max(longLitLengthThreshold, historyRequired + 1);
-
- // If we only have one literal, allow for a larger value in order to avoid
- // building a long literal table for a trivial Noodle case that we could
- // fit in history.
- const auto num_len = floatingCountAndMaxLen(build);
- if (num_len.first == 1) {
- if (num_len.second > longLitLengthThreshold) {
- DEBUG_PRINTF("expanding for single literal of length %zu\n",
- num_len.second);
- longLitLengthThreshold = num_len.second;
- }
- }
-
- // Clamp to max history available.
- longLitLengthThreshold =
- min(longLitLengthThreshold, size_t{cc.grey.maxHistoryAvailable} + 1);
-
- return longLitLengthThreshold;
-}
-
-static
-map<left_id, u32> makeLeftQueueMap(const RoseGraph &g,
- const map<RoseVertex, left_build_info> &leftfix_info) {
- map<left_id, u32> lqm;
- for (const auto &e : leftfix_info) {
- if (e.second.has_lookaround) {
- continue;
- }
- DEBUG_PRINTF("%zu: using queue %u\n", g[e.first].index, e.second.queue);
- assert(e.second.queue != INVALID_QUEUE);
- left_id left(g[e.first].left);
- assert(!contains(lqm, left) || lqm[left] == e.second.queue);
- lqm[left] = e.second.queue;
- }
-
- return lqm;
-}
-
-bytecode_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
- // We keep all our offsets, counts etc. in a prototype RoseEngine which we
- // will copy into the real one once it is allocated: we can't do this
- // until we know how big it will be.
- RoseEngine proto;
- memset(&proto, 0, sizeof(proto));
-
- // Set scanning mode.
- if (!cc.streaming) {
- proto.mode = HS_MODE_BLOCK;
- } else if (cc.vectored) {
- proto.mode = HS_MODE_VECTORED;
- } else {
- proto.mode = HS_MODE_STREAM;
- }
-
- DerivedBoundaryReports dboundary(boundary);
-
- size_t historyRequired = calcHistoryRequired(); // Updated by HWLM.
- size_t longLitLengthThreshold = calcLongLitThreshold(*this,
- historyRequired);
- DEBUG_PRINTF("longLitLengthThreshold=%zu\n", longLitLengthThreshold);
-
- vector<LitFragment> fragments = groupByFragment(*this);
-
- auto anchored_dfas = buildAnchoredDfas(*this, fragments);
-
- build_context bc;
- u32 floatingMinLiteralMatchOffset
- = findMinFloatingLiteralMatch(*this, anchored_dfas);
- recordResources(bc.resources, *this, anchored_dfas, fragments);
- bc.needs_mpv_catchup = needsMpvCatchup(*this);
-
- makeBoundaryPrograms(*this, bc, boundary, dboundary, proto.boundary);
-
- tie(proto.reportProgramOffset, proto.reportProgramCount) =
- buildReportPrograms(*this, bc);
-
- // Build NFAs
- bool mpv_as_outfix;
- prepMpv(*this, bc, &historyRequired, &mpv_as_outfix);
- proto.outfixBeginQueue = qif.allocated_count();
- if (!prepOutfixes(*this, bc, &historyRequired)) {
- return nullptr;
- }
- proto.outfixEndQueue = qif.allocated_count();
- proto.leftfixBeginQueue = proto.outfixEndQueue;
-
- set<u32> no_retrigger_queues;
- set<u32> eager_queues;
-
- /* Note: buildNfas may reduce the lag for vertices that have prefixes */
- if (!buildNfas(*this, bc, qif, &no_retrigger_queues, &eager_queues,
- &proto.leftfixBeginQueue)) {
- return nullptr;
- }
- u32 eodNfaIterOffset = buildEodNfaIterator(bc, proto.leftfixBeginQueue);
- buildCountingMiracles(bc);
-
- u32 queue_count = qif.allocated_count(); /* excludes anchored matcher q;
- * som rev nfas */
- if (queue_count > cc.grey.limitRoseEngineCount) {
- throw ResourceLimitError();
- }
-
- // Enforce role table resource limit.
- if (num_vertices(g) > cc.grey.limitRoseRoleCount) {
- throw ResourceLimitError();
- }
-
- bc.roleStateIndices = assignStateIndices(*this);
-
- u32 laggedRoseCount = 0;
- vector<LeftNfaInfo> leftInfoTable;
- buildLeftInfoTable(*this, bc, eager_queues, proto.leftfixBeginQueue,
- queue_count - proto.leftfixBeginQueue, leftInfoTable,
- &laggedRoseCount, &historyRequired);
-
- // Information only needed for program construction.
- ProgramBuild prog_build(floatingMinLiteralMatchOffset,
- longLitLengthThreshold, needsCatchup(*this));
- prog_build.vertex_group_map = getVertexGroupMap(*this);
- prog_build.squashable_groups = getSquashableGroups(*this);
-
- tie(proto.anchoredProgramOffset, proto.anchored_count) =
- writeAnchoredPrograms(*this, fragments, bc, prog_build);
-
- tie(proto.delayProgramOffset, proto.delay_count) =
- writeDelayPrograms(*this, fragments, bc, prog_build);
-
- // Build floating HWLM matcher prototype.
- rose_group fgroups = 0;
- auto fproto = buildFloatingMatcherProto(*this, fragments,
- longLitLengthThreshold,
- &fgroups, &historyRequired);
-
- // Build delay rebuild HWLM matcher prototype.
- auto drproto = buildDelayRebuildMatcherProto(*this, fragments,
- longLitLengthThreshold);
-
- // Build EOD-anchored HWLM matcher prototype.
- auto eproto = buildEodAnchoredMatcherProto(*this, fragments);
-
- // Build small-block HWLM matcher prototype.
- auto sbproto = buildSmallBlockMatcherProto(*this, fragments);
-
- buildLiteralPrograms(*this, fragments, bc, prog_build, fproto.get(),
- drproto.get(), eproto.get(), sbproto.get());
-
- auto eod_prog = makeEodProgram(*this, bc, prog_build, eodNfaIterOffset);
- proto.eodProgramOffset = writeProgram(bc, move(eod_prog));
-
- size_t longLitStreamStateRequired = 0;
- proto.longLitTableOffset
- = buildLongLiteralTable(*this, bc.engine_blob, bc.longLiterals,
- longLitLengthThreshold, &historyRequired,
- &longLitStreamStateRequired);
-
- proto.lastByteHistoryIterOffset = buildLastByteIter(g, bc);
- proto.eagerIterOffset = writeEagerQueueIter(
- eager_queues, proto.leftfixBeginQueue, queue_count, bc.engine_blob);
-
- addSomRevNfas(bc, proto, ssm);
-
- writeDkeyInfo(rm, bc.engine_blob, proto);
- writeLeftInfo(bc.engine_blob, proto, leftInfoTable);
+static
+u32 writeEagerQueueIter(const set<u32> &eager, u32 leftfixBeginQueue,
+ u32 queue_count, RoseEngineBlob &engine_blob) {
+ if (eager.empty()) {
+ return 0;
+ }
+
+ vector<u32> vec;
+ for (u32 q : eager) {
+ assert(q >= leftfixBeginQueue);
+ vec.push_back(q - leftfixBeginQueue);
+ }
+
+ auto iter = mmbBuildSparseIterator(vec, queue_count - leftfixBeginQueue);
+ return engine_blob.add_iterator(iter);
+}
+
+static
+bytecode_ptr<RoseEngine> addSmallWriteEngine(const RoseBuildImpl &build,
+ const RoseResources &res,
+ bytecode_ptr<RoseEngine> rose) {
+ assert(rose);
+
+ if (roseIsPureLiteral(rose.get())) {
+ DEBUG_PRINTF("pure literal case, not adding smwr\n");
+ return rose;
+ }
+
+ u32 qual = roseQuality(res, rose.get());
+ auto smwr_engine = build.smwr.build(qual);
+ if (!smwr_engine) {
+ DEBUG_PRINTF("no smwr built\n");
+ return rose;
+ }
+
+ const size_t mainSize = rose.size();
+ const size_t smallWriteSize = smwr_engine.size();
+ DEBUG_PRINTF("adding smwr engine, size=%zu\n", smallWriteSize);
+
+ const size_t smwrOffset = ROUNDUP_CL(mainSize);
+ const size_t newSize = smwrOffset + smallWriteSize;
+
+ auto rose2 = make_zeroed_bytecode_ptr<RoseEngine>(newSize, 64);
+ char *ptr = (char *)rose2.get();
+ memcpy(ptr, rose.get(), mainSize);
+ memcpy(ptr + smwrOffset, smwr_engine.get(), smallWriteSize);
+
+ rose2->smallWriteOffset = verify_u32(smwrOffset);
+ rose2->size = verify_u32(newSize);
+
+ return rose2;
+}
+
+/**
+ * \brief Returns the pair (number of literals, max length) for all real
+ * literals in the floating table that are in-use.
+ */
+static
+pair<size_t, size_t> floatingCountAndMaxLen(const RoseBuildImpl &build) {
+ size_t num = 0;
+ size_t max_len = 0;
+
+ for (u32 id = 0; id < build.literals.size(); id++) {
+ const rose_literal_id &lit = build.literals.at(id);
+
+ if (lit.table != ROSE_FLOATING) {
+ continue;
+ }
+ if (lit.delay) {
+ // Skip delayed literals, so that we only count the undelayed
+ // version that ends up in the HWLM table.
+ continue;
+ }
+ if (!isUsedLiteral(build, id)) {
+ continue;
+ }
+
+ num++;
+ max_len = max(max_len, lit.s.length());
+ }
+ DEBUG_PRINTF("%zu floating literals with max_len=%zu\n", num, max_len);
+ return {num, max_len};
+}
+
+size_t calcLongLitThreshold(const RoseBuildImpl &build,
+ const size_t historyRequired) {
+ const auto &cc = build.cc;
+
+ // In block mode, we don't have history, so we don't need long literal
+ // support and can just use "medium-length" literal confirm. TODO: we could
+ // specialize further and have a block mode literal confirm instruction.
+ if (!cc.streaming) {
+ return SIZE_MAX;
+ }
+
+ size_t longLitLengthThreshold = ROSE_LONG_LITERAL_THRESHOLD_MIN;
+
+ // Expand to size of history we've already allocated. Note that we need N-1
+ // bytes of history to match a literal of length N.
+ longLitLengthThreshold = max(longLitLengthThreshold, historyRequired + 1);
+
+ // If we only have one literal, allow for a larger value in order to avoid
+ // building a long literal table for a trivial Noodle case that we could
+ // fit in history.
+ const auto num_len = floatingCountAndMaxLen(build);
+ if (num_len.first == 1) {
+ if (num_len.second > longLitLengthThreshold) {
+ DEBUG_PRINTF("expanding for single literal of length %zu\n",
+ num_len.second);
+ longLitLengthThreshold = num_len.second;
+ }
+ }
+
+ // Clamp to max history available.
+ longLitLengthThreshold =
+ min(longLitLengthThreshold, size_t{cc.grey.maxHistoryAvailable} + 1);
+
+ return longLitLengthThreshold;
+}
+
+static
+map<left_id, u32> makeLeftQueueMap(const RoseGraph &g,
+ const map<RoseVertex, left_build_info> &leftfix_info) {
+ map<left_id, u32> lqm;
+ for (const auto &e : leftfix_info) {
+ if (e.second.has_lookaround) {
+ continue;
+ }
+ DEBUG_PRINTF("%zu: using queue %u\n", g[e.first].index, e.second.queue);
+ assert(e.second.queue != INVALID_QUEUE);
+ left_id left(g[e.first].left);
+ assert(!contains(lqm, left) || lqm[left] == e.second.queue);
+ lqm[left] = e.second.queue;
+ }
+
+ return lqm;
+}
+
+bytecode_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
+ // We keep all our offsets, counts etc. in a prototype RoseEngine which we
+ // will copy into the real one once it is allocated: we can't do this
+ // until we know how big it will be.
+ RoseEngine proto;
+ memset(&proto, 0, sizeof(proto));
+
+ // Set scanning mode.
+ if (!cc.streaming) {
+ proto.mode = HS_MODE_BLOCK;
+ } else if (cc.vectored) {
+ proto.mode = HS_MODE_VECTORED;
+ } else {
+ proto.mode = HS_MODE_STREAM;
+ }
+
+ DerivedBoundaryReports dboundary(boundary);
+
+ size_t historyRequired = calcHistoryRequired(); // Updated by HWLM.
+ size_t longLitLengthThreshold = calcLongLitThreshold(*this,
+ historyRequired);
+ DEBUG_PRINTF("longLitLengthThreshold=%zu\n", longLitLengthThreshold);
+
+ vector<LitFragment> fragments = groupByFragment(*this);
+
+ auto anchored_dfas = buildAnchoredDfas(*this, fragments);
+
+ build_context bc;
+ u32 floatingMinLiteralMatchOffset
+ = findMinFloatingLiteralMatch(*this, anchored_dfas);
+ recordResources(bc.resources, *this, anchored_dfas, fragments);
+ bc.needs_mpv_catchup = needsMpvCatchup(*this);
+
+ makeBoundaryPrograms(*this, bc, boundary, dboundary, proto.boundary);
+
+ tie(proto.reportProgramOffset, proto.reportProgramCount) =
+ buildReportPrograms(*this, bc);
+
+ // Build NFAs
+ bool mpv_as_outfix;
+ prepMpv(*this, bc, &historyRequired, &mpv_as_outfix);
+ proto.outfixBeginQueue = qif.allocated_count();
+ if (!prepOutfixes(*this, bc, &historyRequired)) {
+ return nullptr;
+ }
+ proto.outfixEndQueue = qif.allocated_count();
+ proto.leftfixBeginQueue = proto.outfixEndQueue;
+
+ set<u32> no_retrigger_queues;
+ set<u32> eager_queues;
+
+ /* Note: buildNfas may reduce the lag for vertices that have prefixes */
+ if (!buildNfas(*this, bc, qif, &no_retrigger_queues, &eager_queues,
+ &proto.leftfixBeginQueue)) {
+ return nullptr;
+ }
+ u32 eodNfaIterOffset = buildEodNfaIterator(bc, proto.leftfixBeginQueue);
+ buildCountingMiracles(bc);
+
+ u32 queue_count = qif.allocated_count(); /* excludes anchored matcher q;
+ * som rev nfas */
+ if (queue_count > cc.grey.limitRoseEngineCount) {
+ throw ResourceLimitError();
+ }
+
+ // Enforce role table resource limit.
+ if (num_vertices(g) > cc.grey.limitRoseRoleCount) {
+ throw ResourceLimitError();
+ }
+
+ bc.roleStateIndices = assignStateIndices(*this);
+
+ u32 laggedRoseCount = 0;
+ vector<LeftNfaInfo> leftInfoTable;
+ buildLeftInfoTable(*this, bc, eager_queues, proto.leftfixBeginQueue,
+ queue_count - proto.leftfixBeginQueue, leftInfoTable,
+ &laggedRoseCount, &historyRequired);
+
+ // Information only needed for program construction.
+ ProgramBuild prog_build(floatingMinLiteralMatchOffset,
+ longLitLengthThreshold, needsCatchup(*this));
+ prog_build.vertex_group_map = getVertexGroupMap(*this);
+ prog_build.squashable_groups = getSquashableGroups(*this);
+
+ tie(proto.anchoredProgramOffset, proto.anchored_count) =
+ writeAnchoredPrograms(*this, fragments, bc, prog_build);
+
+ tie(proto.delayProgramOffset, proto.delay_count) =
+ writeDelayPrograms(*this, fragments, bc, prog_build);
+
+ // Build floating HWLM matcher prototype.
+ rose_group fgroups = 0;
+ auto fproto = buildFloatingMatcherProto(*this, fragments,
+ longLitLengthThreshold,
+ &fgroups, &historyRequired);
+
+ // Build delay rebuild HWLM matcher prototype.
+ auto drproto = buildDelayRebuildMatcherProto(*this, fragments,
+ longLitLengthThreshold);
+
+ // Build EOD-anchored HWLM matcher prototype.
+ auto eproto = buildEodAnchoredMatcherProto(*this, fragments);
+
+ // Build small-block HWLM matcher prototype.
+ auto sbproto = buildSmallBlockMatcherProto(*this, fragments);
+
+ buildLiteralPrograms(*this, fragments, bc, prog_build, fproto.get(),
+ drproto.get(), eproto.get(), sbproto.get());
+
+ auto eod_prog = makeEodProgram(*this, bc, prog_build, eodNfaIterOffset);
+ proto.eodProgramOffset = writeProgram(bc, move(eod_prog));
+
+ size_t longLitStreamStateRequired = 0;
+ proto.longLitTableOffset
+ = buildLongLiteralTable(*this, bc.engine_blob, bc.longLiterals,
+ longLitLengthThreshold, &historyRequired,
+ &longLitStreamStateRequired);
+
+ proto.lastByteHistoryIterOffset = buildLastByteIter(g, bc);
+ proto.eagerIterOffset = writeEagerQueueIter(
+ eager_queues, proto.leftfixBeginQueue, queue_count, bc.engine_blob);
+
+ addSomRevNfas(bc, proto, ssm);
+
+ writeDkeyInfo(rm, bc.engine_blob, proto);
+ writeLeftInfo(bc.engine_blob, proto, leftInfoTable);
writeLogicalInfo(rm, bc.engine_blob, proto);
auto flushComb_prog = makeFlushCombProgram(proto);
@@ -3741,154 +3741,154 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
proto.lastFlushCombProgramOffset =
writeProgram(bc, move(lastFlushComb_prog));
- // Build anchored matcher.
- auto atable = buildAnchoredMatcher(*this, fragments, anchored_dfas);
+ // Build anchored matcher.
+ auto atable = buildAnchoredMatcher(*this, fragments, anchored_dfas);
if (atable) {
- proto.amatcherOffset = bc.engine_blob.add(atable);
+ proto.amatcherOffset = bc.engine_blob.add(atable);
}
-
- // Build floating HWLM matcher.
- auto ftable = buildHWLMMatcher(*this, fproto.get());
+
+ // Build floating HWLM matcher.
+ auto ftable = buildHWLMMatcher(*this, fproto.get());
if (ftable) {
- proto.fmatcherOffset = bc.engine_blob.add(ftable);
- bc.resources.has_floating = true;
- }
-
- // Build delay rebuild HWLM matcher.
- auto drtable = buildHWLMMatcher(*this, drproto.get());
- if (drtable) {
- proto.drmatcherOffset = bc.engine_blob.add(drtable);
- }
-
- // Build EOD-anchored HWLM matcher.
- auto etable = buildHWLMMatcher(*this, eproto.get());
+ proto.fmatcherOffset = bc.engine_blob.add(ftable);
+ bc.resources.has_floating = true;
+ }
+
+ // Build delay rebuild HWLM matcher.
+ auto drtable = buildHWLMMatcher(*this, drproto.get());
+ if (drtable) {
+ proto.drmatcherOffset = bc.engine_blob.add(drtable);
+ }
+
+ // Build EOD-anchored HWLM matcher.
+ auto etable = buildHWLMMatcher(*this, eproto.get());
if (etable) {
- proto.ematcherOffset = bc.engine_blob.add(etable);
+ proto.ematcherOffset = bc.engine_blob.add(etable);
}
-
- // Build small-block HWLM matcher.
- auto sbtable = buildHWLMMatcher(*this, sbproto.get());
+
+ // Build small-block HWLM matcher.
+ auto sbtable = buildHWLMMatcher(*this, sbproto.get());
if (sbtable) {
- proto.sbmatcherOffset = bc.engine_blob.add(sbtable);
+ proto.sbmatcherOffset = bc.engine_blob.add(sbtable);
}
- proto.activeArrayCount = proto.leftfixBeginQueue;
+ proto.activeArrayCount = proto.leftfixBeginQueue;
- proto.anchorStateSize = atable ? anchoredStateSize(*atable) : 0;
+ proto.anchorStateSize = atable ? anchoredStateSize(*atable) : 0;
- DEBUG_PRINTF("rose history required %zu\n", historyRequired);
- assert(!cc.streaming || historyRequired <= cc.grey.maxHistoryAvailable);
+ DEBUG_PRINTF("rose history required %zu\n", historyRequired);
+ assert(!cc.streaming || historyRequired <= cc.grey.maxHistoryAvailable);
- // Some SOM schemes (reverse NFAs, for example) may require more history.
- historyRequired = max(historyRequired, (size_t)ssm.somHistoryRequired());
+ // Some SOM schemes (reverse NFAs, for example) may require more history.
+ historyRequired = max(historyRequired, (size_t)ssm.somHistoryRequired());
- assert(!cc.streaming || historyRequired <=
- max(cc.grey.maxHistoryAvailable, cc.grey.somMaxRevNfaLength));
+ assert(!cc.streaming || historyRequired <=
+ max(cc.grey.maxHistoryAvailable, cc.grey.somMaxRevNfaLength));
- fillStateOffsets(*this, bc.roleStateIndices.size(), proto.anchorStateSize,
- proto.activeArrayCount, proto.activeLeftCount,
- laggedRoseCount, longLitStreamStateRequired,
- historyRequired, &proto.stateOffsets);
+ fillStateOffsets(*this, bc.roleStateIndices.size(), proto.anchorStateSize,
+ proto.activeArrayCount, proto.activeLeftCount,
+ laggedRoseCount, longLitStreamStateRequired,
+ historyRequired, &proto.stateOffsets);
- // Write in NfaInfo structures. This will also update state size
- // information in proto.
- writeNfaInfo(*this, bc, proto, no_retrigger_queues);
+ // Write in NfaInfo structures. This will also update state size
+ // information in proto.
+ writeNfaInfo(*this, bc, proto, no_retrigger_queues);
- scatter_plan_raw state_scatter = buildStateScatterPlan(
- sizeof(u8), bc.roleStateIndices.size(), proto.activeLeftCount,
- proto.rosePrefixCount, proto.stateOffsets, cc.streaming,
- proto.activeArrayCount, proto.outfixBeginQueue, proto.outfixEndQueue);
+ scatter_plan_raw state_scatter = buildStateScatterPlan(
+ sizeof(u8), bc.roleStateIndices.size(), proto.activeLeftCount,
+ proto.rosePrefixCount, proto.stateOffsets, cc.streaming,
+ proto.activeArrayCount, proto.outfixBeginQueue, proto.outfixEndQueue);
- u32 currOffset; /* relative to base of RoseEngine */
- if (!bc.engine_blob.empty()) {
- currOffset = bc.engine_blob.base_offset + bc.engine_blob.size();
- } else {
- currOffset = sizeof(RoseEngine);
- }
+ u32 currOffset; /* relative to base of RoseEngine */
+ if (!bc.engine_blob.empty()) {
+ currOffset = bc.engine_blob.base_offset + bc.engine_blob.size();
+ } else {
+ currOffset = sizeof(RoseEngine);
+ }
- currOffset = ROUNDUP_CL(currOffset);
- DEBUG_PRINTF("currOffset %u\n", currOffset);
+ currOffset = ROUNDUP_CL(currOffset);
+ DEBUG_PRINTF("currOffset %u\n", currOffset);
- currOffset = ROUNDUP_N(currOffset, alignof(scatter_unit_u64a));
- u32 state_scatter_aux_offset = currOffset;
- currOffset += aux_size(state_scatter);
+ currOffset = ROUNDUP_N(currOffset, alignof(scatter_unit_u64a));
+ u32 state_scatter_aux_offset = currOffset;
+ currOffset += aux_size(state_scatter);
- proto.historyRequired = verify_u32(historyRequired);
- proto.ekeyCount = rm.numEkeys();
+ proto.historyRequired = verify_u32(historyRequired);
+ proto.ekeyCount = rm.numEkeys();
- proto.somHorizon = ssm.somPrecision();
- proto.somLocationCount = ssm.numSomSlots();
- proto.somLocationFatbitSize = fatbit_size(proto.somLocationCount);
+ proto.somHorizon = ssm.somPrecision();
+ proto.somLocationCount = ssm.numSomSlots();
+ proto.somLocationFatbitSize = fatbit_size(proto.somLocationCount);
- proto.runtimeImpl = pickRuntimeImpl(*this, bc.resources,
- proto.outfixEndQueue);
- proto.mpvTriggeredByLeaf = anyEndfixMpvTriggers(*this);
+ proto.runtimeImpl = pickRuntimeImpl(*this, bc.resources,
+ proto.outfixEndQueue);
+ proto.mpvTriggeredByLeaf = anyEndfixMpvTriggers(*this);
- proto.queueCount = queue_count;
- proto.activeQueueArraySize = fatbit_size(queue_count);
- proto.handledKeyCount = prog_build.handledKeys.size();
- proto.handledKeyFatbitSize = fatbit_size(proto.handledKeyCount);
+ proto.queueCount = queue_count;
+ proto.activeQueueArraySize = fatbit_size(queue_count);
+ proto.handledKeyCount = prog_build.handledKeys.size();
+ proto.handledKeyFatbitSize = fatbit_size(proto.handledKeyCount);
- proto.rolesWithStateCount = bc.roleStateIndices.size();
+ proto.rolesWithStateCount = bc.roleStateIndices.size();
- proto.initMpvNfa = mpv_as_outfix ? 0 : MO_INVALID_IDX;
- proto.stateSize = mmbit_size(bc.roleStateIndices.size());
+ proto.initMpvNfa = mpv_as_outfix ? 0 : MO_INVALID_IDX;
+ proto.stateSize = mmbit_size(bc.roleStateIndices.size());
- proto.delay_fatbit_size = fatbit_size(proto.delay_count);
- proto.anchored_fatbit_size = fatbit_size(proto.anchored_count);
+ proto.delay_fatbit_size = fatbit_size(proto.delay_count);
+ proto.anchored_fatbit_size = fatbit_size(proto.anchored_count);
// The Small Write matcher is (conditionally) added to the RoseEngine in
// another pass by the caller. Set to zero (meaning no SMWR engine) for
// now.
- proto.smallWriteOffset = 0;
-
- proto.amatcherMinWidth = findMinWidth(*this, ROSE_ANCHORED);
- proto.fmatcherMinWidth = findMinWidth(*this, ROSE_FLOATING);
- proto.eodmatcherMinWidth = findMinWidth(*this, ROSE_EOD_ANCHORED);
- proto.amatcherMaxBiAnchoredWidth = findMaxBAWidth(*this, ROSE_ANCHORED);
- proto.fmatcherMaxBiAnchoredWidth = findMaxBAWidth(*this, ROSE_FLOATING);
- proto.minWidth = hasBoundaryReports(boundary) ? 0 : minWidth;
- proto.minWidthExcludingBoundaries = minWidth;
- proto.floatingMinLiteralMatchOffset = floatingMinLiteralMatchOffset;
-
- proto.maxBiAnchoredWidth = findMaxBAWidth(*this);
- proto.noFloatingRoots = hasNoFloatingRoots();
- proto.requiresEodCheck = hasEodAnchors(*this, bc, proto.outfixEndQueue);
- proto.hasOutfixesInSmallBlock = hasNonSmallBlockOutfix(outfixes);
- proto.canExhaust = rm.patternSetCanExhaust();
- proto.hasSom = hasSom;
+ proto.smallWriteOffset = 0;
+
+ proto.amatcherMinWidth = findMinWidth(*this, ROSE_ANCHORED);
+ proto.fmatcherMinWidth = findMinWidth(*this, ROSE_FLOATING);
+ proto.eodmatcherMinWidth = findMinWidth(*this, ROSE_EOD_ANCHORED);
+ proto.amatcherMaxBiAnchoredWidth = findMaxBAWidth(*this, ROSE_ANCHORED);
+ proto.fmatcherMaxBiAnchoredWidth = findMaxBAWidth(*this, ROSE_FLOATING);
+ proto.minWidth = hasBoundaryReports(boundary) ? 0 : minWidth;
+ proto.minWidthExcludingBoundaries = minWidth;
+ proto.floatingMinLiteralMatchOffset = floatingMinLiteralMatchOffset;
+
+ proto.maxBiAnchoredWidth = findMaxBAWidth(*this);
+ proto.noFloatingRoots = hasNoFloatingRoots();
+ proto.requiresEodCheck = hasEodAnchors(*this, bc, proto.outfixEndQueue);
+ proto.hasOutfixesInSmallBlock = hasNonSmallBlockOutfix(outfixes);
+ proto.canExhaust = rm.patternSetCanExhaust();
+ proto.hasSom = hasSom;
/* populate anchoredDistance, floatingDistance, floatingMinDistance, etc */
- fillMatcherDistances(*this, &proto);
+ fillMatcherDistances(*this, &proto);
- proto.initialGroups = getInitialGroups();
- proto.floating_group_mask = fgroups;
- proto.totalNumLiterals = verify_u32(literal_info.size());
- proto.asize = verify_u32(atable.size());
- proto.ematcherRegionSize = ematcher_region_size;
+ proto.initialGroups = getInitialGroups();
+ proto.floating_group_mask = fgroups;
+ proto.totalNumLiterals = verify_u32(literal_info.size());
+ proto.asize = verify_u32(atable.size());
+ proto.ematcherRegionSize = ematcher_region_size;
- proto.size = currOffset;
+ proto.size = currOffset;
- // Time to allocate the real RoseEngine structure, at cacheline alignment.
- auto engine = make_zeroed_bytecode_ptr<RoseEngine>(currOffset, 64);
- assert(engine); // will have thrown bad_alloc otherwise.
+ // Time to allocate the real RoseEngine structure, at cacheline alignment.
+ auto engine = make_zeroed_bytecode_ptr<RoseEngine>(currOffset, 64);
+ assert(engine); // will have thrown bad_alloc otherwise.
- // Copy in our prototype engine data.
- memcpy(engine.get(), &proto, sizeof(proto));
+ // Copy in our prototype engine data.
+ memcpy(engine.get(), &proto, sizeof(proto));
- write_out(&engine->state_init, (char *)engine.get(), state_scatter,
- state_scatter_aux_offset);
+ write_out(&engine->state_init, (char *)engine.get(), state_scatter,
+ state_scatter_aux_offset);
- // Copy in the engine blob.
- bc.engine_blob.write_bytes(engine.get());
+ // Copy in the engine blob.
+ bc.engine_blob.write_bytes(engine.get());
- // Add a small write engine if appropriate.
- engine = addSmallWriteEngine(*this, bc.resources, move(engine));
+ // Add a small write engine if appropriate.
+ engine = addSmallWriteEngine(*this, bc.resources, move(engine));
- DEBUG_PRINTF("rose done %p\n", engine.get());
+ DEBUG_PRINTF("rose done %p\n", engine.get());
- dumpRose(*this, fragments, makeLeftQueueMap(g, bc.leftfix_info),
- bc.suffixes, engine.get());
+ dumpRose(*this, fragments, makeLeftQueueMap(g, bc.leftfix_info),
+ bc.suffixes, engine.get());
return engine;
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_castle.cpp b/contrib/libs/hyperscan/src/rose/rose_build_castle.cpp
index fd8b5121073..59bab3b1f98 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_castle.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_castle.cpp
@@ -1,396 +1,396 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_castle.h"
-
-#include "rose_build_impl.h"
-#include "ue2common.h"
-#include "nfa/castlecompile.h"
-#include "nfagraph/ng_holder.h"
-#include "nfagraph/ng_puff.h"
-#include "util/charreach.h"
-#include "util/compile_context.h"
-#include "util/container.h"
-#include "util/dump_charclass.h"
-#include "util/graph_range.h"
-#include "util/ue2string.h"
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include <boost/range/adaptor/map.hpp>
-
-using namespace std;
-using boost::adaptors::map_values;
-
-namespace ue2 {
-
-static
-void makeCastle(LeftEngInfo &left,
- unordered_map<const NGHolder *, shared_ptr<CastleProto>> &cache) {
- if (left.dfa || left.haig || left.castle) {
- return;
- }
- if (!left.graph) {
- return;
- }
-
- const NGHolder &h = *left.graph;
- DEBUG_PRINTF("prefix %p\n", &h);
-
- if (contains(cache, &h)) {
- DEBUG_PRINTF("using cached CastleProto\n");
- left.castle = cache[&h];
- left.graph.reset();
- return;
- }
-
- PureRepeat pr;
- if (isPureRepeat(h, pr) && pr.reports.size() == 1) {
- DEBUG_PRINTF("vertex preceded by infix repeat %s\n",
- pr.bounds.str().c_str());
- left.castle = make_shared<CastleProto>(h.kind, pr);
- cache[&h] = left.castle;
- left.graph.reset();
- }
-}
-
-static
-void makeCastleSuffix(RoseBuildImpl &tbi, RoseVertex v,
- unordered_map<const NGHolder *, shared_ptr<CastleProto>> &cache) {
- RoseSuffixInfo &suffix = tbi.g[v].suffix;
- if (!suffix.graph) {
- return;
- }
- const NGHolder &h = *suffix.graph;
- DEBUG_PRINTF("suffix %p\n", &h);
-
- if (contains(cache, &h)) {
- DEBUG_PRINTF("using cached CastleProto\n");
- suffix.castle = cache[&h];
- suffix.graph.reset();
- return;
- }
-
- // The MPV will probably do a better job on the cases it's designed
- // for.
- const bool fixed_depth = tbi.g[v].min_offset == tbi.g[v].max_offset;
- if (isPuffable(h, fixed_depth, tbi.rm, tbi.cc.grey)) {
- DEBUG_PRINTF("leaving suffix for puff\n");
- return;
- }
-
- PureRepeat pr;
- if (isPureRepeat(h, pr) && pr.reports.size() == 1) {
- DEBUG_PRINTF("suffix repeat %s\n", pr.bounds.str().c_str());
-
- // Right now, the Castle uses much more stream state to represent a
- // {m,1} repeat than just leaving it to an NFA.
- if (pr.bounds.max <= depth(1)) {
- DEBUG_PRINTF("leaving for other engines\n");
- return;
- }
-
- suffix.castle = make_shared<CastleProto>(h.kind, pr);
- cache[&h] = suffix.castle;
- suffix.graph.reset();
- }
-}
-
-static
-vector<rose_literal_id> literals_for_vertex(const RoseBuildImpl &tbi,
- RoseVertex v) {
- vector<rose_literal_id> rv;
-
- for (const u32 id : tbi.g[v].literals) {
- rv.push_back(tbi.literals.at(id));
- }
-
- return rv;
-}
-
-static
-void renovateCastle(RoseBuildImpl &tbi, CastleProto *castle,
- const vector<RoseVertex> &verts) {
- DEBUG_PRINTF("looking to renovate\n");
-
- if (castle->repeats.size() != 1) {
- assert(0); /* should not have merged castles yet */
- return;
- }
-
- PureRepeat &pr = castle->repeats.begin()->second;
- if (pr.bounds.max.is_finite()) {
- /* repeat cannot be turned into pseudo .* */
- return;
- }
-
- RoseGraph &g = tbi.g;
- const CharReach &cr = castle->reach();
-
- DEBUG_PRINTF("cr || %zu\n", cr.count());
-
- u32 allowed_to_remove = ~0;
- size_t min_succ_lit_len = 0;
-
- for (RoseVertex v : verts) {
- assert(g[v].left.castle.get() == castle);
- DEBUG_PRINTF("%zu checks at lag %u\n", g[v].index, g[v].left.lag);
- vector<rose_literal_id> lits = literals_for_vertex(tbi, v);
- for (const auto &e : lits) {
- DEBUG_PRINTF("%s +%u\n", dumpString(e.s).c_str(), e.delay);
- if (e.delay) {
- return; /* bail - TODO: be less lazy */
- }
-
- vector<CharReach> rem_local_cr;
- u32 ok_count = 0;
- for (auto it = e.s.end() - g[v].left.lag; it != e.s.end(); ++it) {
- if (!isSubsetOf(*it, cr)) {
- break;
- }
-
- ok_count++;
- }
- LIMIT_TO_AT_MOST(&allowed_to_remove, ok_count);
- ENSURE_AT_LEAST(&min_succ_lit_len, e.elength());
- }
- }
-
- DEBUG_PRINTF("possible to decrease lag by %u\n", allowed_to_remove);
-
-
- for (RoseVertex v : verts) {
- assert(g[v].left.lag >= allowed_to_remove);
- g[v].left.lag -= allowed_to_remove;
- }
-
- assert(castle->repeats.size() == 1); /* should not have merged castles yet */
-
- pr.bounds.max += allowed_to_remove;
-
- /* Although it is always safe to increase the min bound as well, we would
- * rather not as a >0 min bound means that we have to store state as well.
- *
- * As it was legal to run with the original lag, we know that it is not
- * possible to have an overlapping match which finishes within the trigger
- * literal past the original lag point. However, if there is already a min
- * bound constraint this would be broken if we did not also increase the
- * min bound. */
-
- if (pr.bounds.min > 0ULL || allowed_to_remove > min_succ_lit_len) {
- pr.bounds.min += allowed_to_remove;
- }
-}
-
-void makeCastles(RoseBuildImpl &tbi) {
- if (!tbi.cc.grey.allowCastle && !tbi.cc.grey.allowLbr) {
- return;
- }
-
- RoseGraph &g = tbi.g;
-
- // Caches so that we can reuse analysis on graphs we've seen already.
- unordered_map<const NGHolder *, shared_ptr<CastleProto> > left_cache;
- unordered_map<const NGHolder *, shared_ptr<CastleProto> > suffix_cache;
-
- unordered_map<CastleProto *, vector<RoseVertex>> rev;
-
- for (RoseVertex v : vertices_range(g)) {
- if (g[v].left && !tbi.isRootSuccessor(v)) {
- makeCastle(g[v].left, left_cache);
- if (g[v].left.castle) {
- rev[g[v].left.castle.get()].push_back(v);
- }
- }
-
- if (g[v].suffix) {
- makeCastleSuffix(tbi, v, suffix_cache);
- }
- }
-
- for (const auto &e : rev) {
- renovateCastle(tbi, e.first, e.second);
- }
-}
-
-bool unmakeCastles(RoseBuildImpl &tbi) {
- RoseGraph &g = tbi.g;
-
- const size_t MAX_UNMAKE_VERTICES = 64;
-
- map<left_id, vector<RoseVertex> > left_castles;
- map<suffix_id, vector<RoseVertex> > suffix_castles;
- bool changed = false;
-
- for (auto v : vertices_range(g)) {
- const LeftEngInfo &left = g[v].left;
- if (left.castle && left.castle->repeats.size() > 1) {
- left_castles[left].push_back(v);
- }
- const RoseSuffixInfo &suffix = g[v].suffix;
- if (suffix.castle && suffix.castle->repeats.size() > 1) {
- suffix_castles[suffix].push_back(v);
- }
- }
-
- for (const auto &e : left_castles) {
- assert(e.first.castle());
- shared_ptr<NGHolder> h = makeHolder(*e.first.castle(), tbi.cc);
- if (!h || num_vertices(*h) > MAX_UNMAKE_VERTICES) {
- continue;
- }
- DEBUG_PRINTF("replace rose with holder (%zu vertices)\n",
- num_vertices(*h));
- for (auto v : e.second) {
- assert(g[v].left.castle.get() == e.first.castle());
- g[v].left.graph = h;
- g[v].left.castle.reset();
- changed = true;
- }
- }
-
- for (const auto &e : suffix_castles) {
- assert(e.first.castle());
- shared_ptr<NGHolder> h = makeHolder(*e.first.castle(), tbi.cc);
- if (!h || num_vertices(*h) > MAX_UNMAKE_VERTICES) {
- continue;
- }
- DEBUG_PRINTF("replace suffix with holder (%zu vertices)\n",
- num_vertices(*h));
- for (auto v : e.second) {
- assert(g[v].suffix.castle.get() == e.first.castle());
- g[v].suffix.graph = h;
- g[v].suffix.castle.reset();
- changed = true;
- }
- }
-
- return changed;
-}
-
-void remapCastleTops(RoseBuildImpl &tbi) {
- unordered_map<CastleProto *, vector<RoseVertex>> rose_castles;
- unordered_map<CastleProto *, vector<RoseVertex>> suffix_castles;
-
- RoseGraph &g = tbi.g;
- for (auto v : vertices_range(g)) {
- if (g[v].left.castle) {
- rose_castles[g[v].left.castle.get()].push_back(v);
- }
- if (g[v].suffix.castle) {
- suffix_castles[g[v].suffix.castle.get()].push_back(v);
- }
- }
-
- DEBUG_PRINTF("%zu rose castles, %zu suffix castles\n", rose_castles.size(),
- suffix_castles.size());
-
- map<u32, u32> top_map;
-
- // Remap Rose Castles.
- for (const auto &rc : rose_castles) {
- CastleProto *c = rc.first;
- const vector<RoseVertex> &verts = rc.second;
-
- DEBUG_PRINTF("rose castle %p (%zu repeats) has %zu verts\n", c,
- c->repeats.size(), verts.size());
-
- top_map.clear();
- remapCastleTops(*c, top_map);
-
- // Update the tops on the edges leading into vertices in v.
- for (auto v : verts) {
- for (const auto &e : in_edges_range(v, g)) {
- g[e].rose_top = top_map.at(g[e].rose_top);
- }
- }
- }
-
- // Remap Suffix Castles.
- for (const auto &e : suffix_castles) {
- CastleProto *c = e.first;
- const vector<RoseVertex> &verts = e.second;
-
- DEBUG_PRINTF("suffix castle %p (%zu repeats) has %zu verts\n", c,
- c->repeats.size(), verts.size());
-
- top_map.clear();
- remapCastleTops(*c, top_map);
-
- // Update the tops on the suffixes.
- for (auto v : verts) {
- assert(g[v].suffix);
- g[v].suffix.top = top_map.at(g[v].suffix.top);
- }
- }
-}
-
-bool triggerKillsRoseCastle(const RoseBuildImpl &tbi, const left_id &left,
- const set<ue2_literal> &all_lits,
- const RoseEdge &e) {
- assert(left.castle());
- const CastleProto &c = *left.castle();
-
- const depth max_width = findMaxWidth(c);
- DEBUG_PRINTF("castle max width is %s\n", max_width.str().c_str());
-
- /* check each pred literal to see if they all kill previous castle
- * state */
- for (u32 lit_id : tbi.g[source(e, tbi.g)].literals) {
- const rose_literal_id &pred_lit = tbi.literals.at(lit_id);
- const ue2_literal s = findNonOverlappingTail(all_lits, pred_lit.s);
- const CharReach &cr = c.reach();
-
- DEBUG_PRINTF("s=%s, castle reach=%s\n", dumpString(s).c_str(),
- describeClass(cr).c_str());
-
- for (const auto &s_cr : s) {
- if (!overlaps(cr, s_cr)) {
- DEBUG_PRINTF("reach %s kills castle\n",
- describeClass(s_cr).c_str());
- goto next_pred;
- }
- }
-
- if (max_width < depth(s.length())) {
- DEBUG_PRINTF("literal width >= castle max width\n");
- goto next_pred;
- }
-
- return false;
-
- next_pred:;
- }
-
- return true;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_castle.h"
+
+#include "rose_build_impl.h"
+#include "ue2common.h"
+#include "nfa/castlecompile.h"
+#include "nfagraph/ng_holder.h"
+#include "nfagraph/ng_puff.h"
+#include "util/charreach.h"
+#include "util/compile_context.h"
+#include "util/container.h"
+#include "util/dump_charclass.h"
+#include "util/graph_range.h"
+#include "util/ue2string.h"
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <boost/range/adaptor/map.hpp>
+
+using namespace std;
+using boost::adaptors::map_values;
+
+namespace ue2 {
+
+static
+void makeCastle(LeftEngInfo &left,
+ unordered_map<const NGHolder *, shared_ptr<CastleProto>> &cache) {
+ if (left.dfa || left.haig || left.castle) {
+ return;
+ }
+ if (!left.graph) {
+ return;
+ }
+
+ const NGHolder &h = *left.graph;
+ DEBUG_PRINTF("prefix %p\n", &h);
+
+ if (contains(cache, &h)) {
+ DEBUG_PRINTF("using cached CastleProto\n");
+ left.castle = cache[&h];
+ left.graph.reset();
+ return;
+ }
+
+ PureRepeat pr;
+ if (isPureRepeat(h, pr) && pr.reports.size() == 1) {
+ DEBUG_PRINTF("vertex preceded by infix repeat %s\n",
+ pr.bounds.str().c_str());
+ left.castle = make_shared<CastleProto>(h.kind, pr);
+ cache[&h] = left.castle;
+ left.graph.reset();
+ }
+}
+
+static
+void makeCastleSuffix(RoseBuildImpl &tbi, RoseVertex v,
+ unordered_map<const NGHolder *, shared_ptr<CastleProto>> &cache) {
+ RoseSuffixInfo &suffix = tbi.g[v].suffix;
+ if (!suffix.graph) {
+ return;
+ }
+ const NGHolder &h = *suffix.graph;
+ DEBUG_PRINTF("suffix %p\n", &h);
+
+ if (contains(cache, &h)) {
+ DEBUG_PRINTF("using cached CastleProto\n");
+ suffix.castle = cache[&h];
+ suffix.graph.reset();
+ return;
+ }
+
+ // The MPV will probably do a better job on the cases it's designed
+ // for.
+ const bool fixed_depth = tbi.g[v].min_offset == tbi.g[v].max_offset;
+ if (isPuffable(h, fixed_depth, tbi.rm, tbi.cc.grey)) {
+ DEBUG_PRINTF("leaving suffix for puff\n");
+ return;
+ }
+
+ PureRepeat pr;
+ if (isPureRepeat(h, pr) && pr.reports.size() == 1) {
+ DEBUG_PRINTF("suffix repeat %s\n", pr.bounds.str().c_str());
+
+ // Right now, the Castle uses much more stream state to represent a
+ // {m,1} repeat than just leaving it to an NFA.
+ if (pr.bounds.max <= depth(1)) {
+ DEBUG_PRINTF("leaving for other engines\n");
+ return;
+ }
+
+ suffix.castle = make_shared<CastleProto>(h.kind, pr);
+ cache[&h] = suffix.castle;
+ suffix.graph.reset();
+ }
+}
+
+static
+vector<rose_literal_id> literals_for_vertex(const RoseBuildImpl &tbi,
+ RoseVertex v) {
+ vector<rose_literal_id> rv;
+
+ for (const u32 id : tbi.g[v].literals) {
+ rv.push_back(tbi.literals.at(id));
+ }
+
+ return rv;
+}
+
+static
+void renovateCastle(RoseBuildImpl &tbi, CastleProto *castle,
+ const vector<RoseVertex> &verts) {
+ DEBUG_PRINTF("looking to renovate\n");
+
+ if (castle->repeats.size() != 1) {
+ assert(0); /* should not have merged castles yet */
+ return;
+ }
+
+ PureRepeat &pr = castle->repeats.begin()->second;
+ if (pr.bounds.max.is_finite()) {
+ /* repeat cannot be turned into pseudo .* */
+ return;
+ }
+
+ RoseGraph &g = tbi.g;
+ const CharReach &cr = castle->reach();
+
+ DEBUG_PRINTF("cr || %zu\n", cr.count());
+
+ u32 allowed_to_remove = ~0;
+ size_t min_succ_lit_len = 0;
+
+ for (RoseVertex v : verts) {
+ assert(g[v].left.castle.get() == castle);
+ DEBUG_PRINTF("%zu checks at lag %u\n", g[v].index, g[v].left.lag);
+ vector<rose_literal_id> lits = literals_for_vertex(tbi, v);
+ for (const auto &e : lits) {
+ DEBUG_PRINTF("%s +%u\n", dumpString(e.s).c_str(), e.delay);
+ if (e.delay) {
+ return; /* bail - TODO: be less lazy */
+ }
+
+ vector<CharReach> rem_local_cr;
+ u32 ok_count = 0;
+ for (auto it = e.s.end() - g[v].left.lag; it != e.s.end(); ++it) {
+ if (!isSubsetOf(*it, cr)) {
+ break;
+ }
+
+ ok_count++;
+ }
+ LIMIT_TO_AT_MOST(&allowed_to_remove, ok_count);
+ ENSURE_AT_LEAST(&min_succ_lit_len, e.elength());
+ }
+ }
+
+ DEBUG_PRINTF("possible to decrease lag by %u\n", allowed_to_remove);
+
+
+ for (RoseVertex v : verts) {
+ assert(g[v].left.lag >= allowed_to_remove);
+ g[v].left.lag -= allowed_to_remove;
+ }
+
+ assert(castle->repeats.size() == 1); /* should not have merged castles yet */
+
+ pr.bounds.max += allowed_to_remove;
+
+ /* Although it is always safe to increase the min bound as well, we would
+ * rather not as a >0 min bound means that we have to store state as well.
+ *
+ * As it was legal to run with the original lag, we know that it is not
+ * possible to have an overlapping match which finishes within the trigger
+ * literal past the original lag point. However, if there is already a min
+ * bound constraint this would be broken if we did not also increase the
+ * min bound. */
+
+ if (pr.bounds.min > 0ULL || allowed_to_remove > min_succ_lit_len) {
+ pr.bounds.min += allowed_to_remove;
+ }
+}
+
+void makeCastles(RoseBuildImpl &tbi) {
+ if (!tbi.cc.grey.allowCastle && !tbi.cc.grey.allowLbr) {
+ return;
+ }
+
+ RoseGraph &g = tbi.g;
+
+ // Caches so that we can reuse analysis on graphs we've seen already.
+ unordered_map<const NGHolder *, shared_ptr<CastleProto> > left_cache;
+ unordered_map<const NGHolder *, shared_ptr<CastleProto> > suffix_cache;
+
+ unordered_map<CastleProto *, vector<RoseVertex>> rev;
+
+ for (RoseVertex v : vertices_range(g)) {
+ if (g[v].left && !tbi.isRootSuccessor(v)) {
+ makeCastle(g[v].left, left_cache);
+ if (g[v].left.castle) {
+ rev[g[v].left.castle.get()].push_back(v);
+ }
+ }
+
+ if (g[v].suffix) {
+ makeCastleSuffix(tbi, v, suffix_cache);
+ }
+ }
+
+ for (const auto &e : rev) {
+ renovateCastle(tbi, e.first, e.second);
+ }
+}
+
+bool unmakeCastles(RoseBuildImpl &tbi) {
+ RoseGraph &g = tbi.g;
+
+ const size_t MAX_UNMAKE_VERTICES = 64;
+
+ map<left_id, vector<RoseVertex> > left_castles;
+ map<suffix_id, vector<RoseVertex> > suffix_castles;
+ bool changed = false;
+
+ for (auto v : vertices_range(g)) {
+ const LeftEngInfo &left = g[v].left;
+ if (left.castle && left.castle->repeats.size() > 1) {
+ left_castles[left].push_back(v);
+ }
+ const RoseSuffixInfo &suffix = g[v].suffix;
+ if (suffix.castle && suffix.castle->repeats.size() > 1) {
+ suffix_castles[suffix].push_back(v);
+ }
+ }
+
+ for (const auto &e : left_castles) {
+ assert(e.first.castle());
+ shared_ptr<NGHolder> h = makeHolder(*e.first.castle(), tbi.cc);
+ if (!h || num_vertices(*h) > MAX_UNMAKE_VERTICES) {
+ continue;
+ }
+ DEBUG_PRINTF("replace rose with holder (%zu vertices)\n",
+ num_vertices(*h));
+ for (auto v : e.second) {
+ assert(g[v].left.castle.get() == e.first.castle());
+ g[v].left.graph = h;
+ g[v].left.castle.reset();
+ changed = true;
+ }
+ }
+
+ for (const auto &e : suffix_castles) {
+ assert(e.first.castle());
+ shared_ptr<NGHolder> h = makeHolder(*e.first.castle(), tbi.cc);
+ if (!h || num_vertices(*h) > MAX_UNMAKE_VERTICES) {
+ continue;
+ }
+ DEBUG_PRINTF("replace suffix with holder (%zu vertices)\n",
+ num_vertices(*h));
+ for (auto v : e.second) {
+ assert(g[v].suffix.castle.get() == e.first.castle());
+ g[v].suffix.graph = h;
+ g[v].suffix.castle.reset();
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+void remapCastleTops(RoseBuildImpl &tbi) {
+ unordered_map<CastleProto *, vector<RoseVertex>> rose_castles;
+ unordered_map<CastleProto *, vector<RoseVertex>> suffix_castles;
+
+ RoseGraph &g = tbi.g;
+ for (auto v : vertices_range(g)) {
+ if (g[v].left.castle) {
+ rose_castles[g[v].left.castle.get()].push_back(v);
+ }
+ if (g[v].suffix.castle) {
+ suffix_castles[g[v].suffix.castle.get()].push_back(v);
+ }
+ }
+
+ DEBUG_PRINTF("%zu rose castles, %zu suffix castles\n", rose_castles.size(),
+ suffix_castles.size());
+
+ map<u32, u32> top_map;
+
+ // Remap Rose Castles.
+ for (const auto &rc : rose_castles) {
+ CastleProto *c = rc.first;
+ const vector<RoseVertex> &verts = rc.second;
+
+ DEBUG_PRINTF("rose castle %p (%zu repeats) has %zu verts\n", c,
+ c->repeats.size(), verts.size());
+
+ top_map.clear();
+ remapCastleTops(*c, top_map);
+
+ // Update the tops on the edges leading into vertices in v.
+ for (auto v : verts) {
+ for (const auto &e : in_edges_range(v, g)) {
+ g[e].rose_top = top_map.at(g[e].rose_top);
+ }
+ }
+ }
+
+ // Remap Suffix Castles.
+ for (const auto &e : suffix_castles) {
+ CastleProto *c = e.first;
+ const vector<RoseVertex> &verts = e.second;
+
+ DEBUG_PRINTF("suffix castle %p (%zu repeats) has %zu verts\n", c,
+ c->repeats.size(), verts.size());
+
+ top_map.clear();
+ remapCastleTops(*c, top_map);
+
+ // Update the tops on the suffixes.
+ for (auto v : verts) {
+ assert(g[v].suffix);
+ g[v].suffix.top = top_map.at(g[v].suffix.top);
+ }
+ }
+}
+
+bool triggerKillsRoseCastle(const RoseBuildImpl &tbi, const left_id &left,
+ const set<ue2_literal> &all_lits,
+ const RoseEdge &e) {
+ assert(left.castle());
+ const CastleProto &c = *left.castle();
+
+ const depth max_width = findMaxWidth(c);
+ DEBUG_PRINTF("castle max width is %s\n", max_width.str().c_str());
+
+ /* check each pred literal to see if they all kill previous castle
+ * state */
+ for (u32 lit_id : tbi.g[source(e, tbi.g)].literals) {
+ const rose_literal_id &pred_lit = tbi.literals.at(lit_id);
+ const ue2_literal s = findNonOverlappingTail(all_lits, pred_lit.s);
+ const CharReach &cr = c.reach();
+
+ DEBUG_PRINTF("s=%s, castle reach=%s\n", dumpString(s).c_str(),
+ describeClass(cr).c_str());
+
+ for (const auto &s_cr : s) {
+ if (!overlaps(cr, s_cr)) {
+ DEBUG_PRINTF("reach %s kills castle\n",
+ describeClass(s_cr).c_str());
+ goto next_pred;
+ }
+ }
+
+ if (max_width < depth(s.length())) {
+ DEBUG_PRINTF("literal width >= castle max width\n");
+ goto next_pred;
+ }
+
+ return false;
+
+ next_pred:;
+ }
+
+ return true;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_castle.h b/contrib/libs/hyperscan/src/rose/rose_build_castle.h
index f03feeab049..4a2b6188b09 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_castle.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_castle.h
@@ -1,69 +1,69 @@
-/*
- * Copyright (c) 2015, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_CASTLE_H
-#define ROSE_BUILD_CASTLE_H
-
-#include "rose_graph.h"
-
-#include <set>
-
-namespace ue2 {
-
-class RoseBuildImpl;
-struct left_id;
-struct ue2_literal;
-
-/**
- * Runs over all rose infix/suffix engines and converts those that are pure
- * repeats with one report into CastleProto engines.
- */
-void makeCastles(RoseBuildImpl &tbi);
-
-/**
- * Identifies all the CastleProto prototypes that are small enough that they
- * would be better implemented as NFAs, and converts them back to NGHolder
- * prototypes.
- *
- * Returns true if any changes were made.
- */
-bool unmakeCastles(RoseBuildImpl &tbi);
-
-/**
- * Runs over all the Castle engine prototypes in the graph and ensures that
- * they have tops in a contiguous range, ready for construction.
- */
-void remapCastleTops(RoseBuildImpl &tbi);
-
-bool triggerKillsRoseCastle(const RoseBuildImpl &tbi, const left_id &left,
- const std::set<ue2_literal> &all_lits,
- const RoseEdge &e);
-
-}
-
-#endif
+/*
+ * Copyright (c) 2015, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_CASTLE_H
+#define ROSE_BUILD_CASTLE_H
+
+#include "rose_graph.h"
+
+#include <set>
+
+namespace ue2 {
+
+class RoseBuildImpl;
+struct left_id;
+struct ue2_literal;
+
+/**
+ * Runs over all rose infix/suffix engines and converts those that are pure
+ * repeats with one report into CastleProto engines.
+ */
+void makeCastles(RoseBuildImpl &tbi);
+
+/**
+ * Identifies all the CastleProto prototypes that are small enough that they
+ * would be better implemented as NFAs, and converts them back to NGHolder
+ * prototypes.
+ *
+ * Returns true if any changes were made.
+ */
+bool unmakeCastles(RoseBuildImpl &tbi);
+
+/**
+ * Runs over all the Castle engine prototypes in the graph and ensures that
+ * they have tops in a contiguous range, ready for construction.
+ */
+void remapCastleTops(RoseBuildImpl &tbi);
+
+bool triggerKillsRoseCastle(const RoseBuildImpl &tbi, const left_id &left,
+ const std::set<ue2_literal> &all_lits,
+ const RoseEdge &e);
+
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_compile.cpp b/contrib/libs/hyperscan/src/rose/rose_build_compile.cpp
index 76439695aea..1cf3bbe6956 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_compile.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_compile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,16 +31,16 @@
#include "grey.h"
#include "hs_internal.h"
#include "rose_build_anchored.h"
-#include "rose_build_castle.h"
+#include "rose_build_castle.h"
#include "rose_build_convert.h"
#include "rose_build_dump.h"
-#include "rose_build_groups.h"
-#include "rose_build_matchers.h"
+#include "rose_build_groups.h"
+#include "rose_build_matchers.h"
#include "rose_build_merge.h"
#include "rose_build_role_aliasing.h"
#include "rose_build_util.h"
#include "ue2common.h"
-#include "hwlm/hwlm_literal.h"
+#include "hwlm/hwlm_literal.h"
#include "nfa/nfa_internal.h"
#include "nfa/rdfa.h"
#include "nfagraph/ng_holder.h"
@@ -48,7 +48,7 @@
#include "nfagraph/ng_is_equal.h"
#include "nfagraph/ng_limex.h"
#include "nfagraph/ng_mcclellan.h"
-#include "nfagraph/ng_prune.h"
+#include "nfagraph/ng_prune.h"
#include "nfagraph/ng_repeat.h"
#include "nfagraph/ng_reports.h"
#include "nfagraph/ng_stop.h"
@@ -61,7 +61,7 @@
#include "util/compile_context.h"
#include "util/container.h"
#include "util/dump_charclass.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/order_check.h"
#include "util/report_manager.h"
@@ -89,89 +89,89 @@ namespace ue2 {
#define ANCHORED_REHOME_DEEP 25
#define ANCHORED_REHOME_SHORT_LEN 3
-#define MAX_EXPLOSION_NC 3
+#define MAX_EXPLOSION_NC 3
static
-bool limited_explosion(const ue2_literal &s) {
- u32 nc_count = 0;
+bool limited_explosion(const ue2_literal &s) {
+ u32 nc_count = 0;
- for (const auto &e : s) {
- if (e.nocase) {
- nc_count++;
+ for (const auto &e : s) {
+ if (e.nocase) {
+ nc_count++;
}
}
- return nc_count <= MAX_EXPLOSION_NC;
+ return nc_count <= MAX_EXPLOSION_NC;
}
static
-void removeLiteralFromGraph(RoseBuildImpl &build, u32 id) {
- assert(id < build.literal_info.size());
- auto &info = build.literal_info.at(id);
- for (const auto &v : info.vertices) {
- build.g[v].literals.erase(id);
+void removeLiteralFromGraph(RoseBuildImpl &build, u32 id) {
+ assert(id < build.literal_info.size());
+ auto &info = build.literal_info.at(id);
+ for (const auto &v : info.vertices) {
+ build.g[v].literals.erase(id);
}
- info.vertices.clear();
+ info.vertices.clear();
}
-/**
- * \brief Replace the given mixed-case literal with the set of its caseless
- * variants.
- */
+/**
+ * \brief Replace the given mixed-case literal with the set of its caseless
+ * variants.
+ */
static
-void explodeLiteral(RoseBuildImpl &build, u32 id) {
- const auto &lit = build.literals.at(id);
- auto &info = build.literal_info[id];
+void explodeLiteral(RoseBuildImpl &build, u32 id) {
+ const auto &lit = build.literals.at(id);
+ auto &info = build.literal_info[id];
- assert(!info.group_mask); // not set yet
- assert(info.undelayed_id == id); // we do not explode delayed literals
+ assert(!info.group_mask); // not set yet
+ assert(info.undelayed_id == id); // we do not explode delayed literals
- for (auto it = caseIterateBegin(lit.s); it != caseIterateEnd(); ++it) {
- ue2_literal new_str(*it, false);
+ for (auto it = caseIterateBegin(lit.s); it != caseIterateEnd(); ++it) {
+ ue2_literal new_str(*it, false);
- if (!maskIsConsistent(new_str.get_string(), false, lit.msk, lit.cmp)) {
- DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
+ if (!maskIsConsistent(new_str.get_string(), false, lit.msk, lit.cmp)) {
+ DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue;
}
- u32 new_id =
- build.getLiteralId(new_str, lit.msk, lit.cmp, lit.delay, lit.table);
+ u32 new_id =
+ build.getLiteralId(new_str, lit.msk, lit.cmp, lit.delay, lit.table);
- DEBUG_PRINTF("adding exploded lit %u: '%s'\n", new_id,
- dumpString(new_str).c_str());
+ DEBUG_PRINTF("adding exploded lit %u: '%s'\n", new_id,
+ dumpString(new_str).c_str());
- const auto &new_lit = build.literals.at(new_id);
- auto &new_info = build.literal_info.at(new_id);
- insert(&new_info.vertices, info.vertices);
- for (const auto &v : info.vertices) {
- build.g[v].literals.insert(new_id);
+ const auto &new_lit = build.literals.at(new_id);
+ auto &new_info = build.literal_info.at(new_id);
+ insert(&new_info.vertices, info.vertices);
+ for (const auto &v : info.vertices) {
+ build.g[v].literals.insert(new_id);
}
- build.literal_info[new_id].undelayed_id = new_id;
- if (!info.delayed_ids.empty()) {
- flat_set<u32> &del_ids = new_info.delayed_ids;
- for (u32 delay_id : info.delayed_ids) {
- const auto &dlit = build.literals.at(delay_id);
- u32 new_delay_id =
- build.getLiteralId(new_lit.s, new_lit.msk, new_lit.cmp,
- dlit.delay, dlit.table);
- del_ids.insert(new_delay_id);
- build.literal_info[new_delay_id].undelayed_id = new_id;
+ build.literal_info[new_id].undelayed_id = new_id;
+ if (!info.delayed_ids.empty()) {
+ flat_set<u32> &del_ids = new_info.delayed_ids;
+ for (u32 delay_id : info.delayed_ids) {
+ const auto &dlit = build.literals.at(delay_id);
+ u32 new_delay_id =
+ build.getLiteralId(new_lit.s, new_lit.msk, new_lit.cmp,
+ dlit.delay, dlit.table);
+ del_ids.insert(new_delay_id);
+ build.literal_info[new_delay_id].undelayed_id = new_id;
}
}
}
- // Remove the old literal and any old delay variants.
- removeLiteralFromGraph(build, id);
- for (u32 delay_id : info.delayed_ids) {
- removeLiteralFromGraph(build, delay_id);
+ // Remove the old literal and any old delay variants.
+ removeLiteralFromGraph(build, id);
+ for (u32 delay_id : info.delayed_ids) {
+ removeLiteralFromGraph(build, delay_id);
}
- info.delayed_ids.clear();
+ info.delayed_ids.clear();
}
void RoseBuildImpl::handleMixedSensitivity(void) {
- vector<u32> explode;
- for (u32 id = 0; id < literals.size(); id++) {
- const rose_literal_id &lit = literals.at(id);
+ vector<u32> explode;
+ for (u32 id = 0; id < literals.size(); id++) {
+ const rose_literal_id &lit = literals.at(id);
if (lit.delay) {
continue; /* delay id's are virtual-ish */
@@ -185,24 +185,24 @@ void RoseBuildImpl::handleMixedSensitivity(void) {
continue;
}
- // We don't want to explode long literals, as they require confirmation
- // with a CHECK_LONG_LIT instruction and need unique final_ids.
- // TODO: we could allow explosion for literals where the prefixes
- // covered by CHECK_LONG_LIT are identical.
-
- if (lit.s.length() <= ROSE_LONG_LITERAL_THRESHOLD_MIN &&
- limited_explosion(lit.s) && literal_info[id].delayed_ids.empty()) {
+ // We don't want to explode long literals, as they require confirmation
+ // with a CHECK_LONG_LIT instruction and need unique final_ids.
+ // TODO: we could allow explosion for literals where the prefixes
+ // covered by CHECK_LONG_LIT are identical.
+
+ if (lit.s.length() <= ROSE_LONG_LITERAL_THRESHOLD_MIN &&
+ limited_explosion(lit.s) && literal_info[id].delayed_ids.empty()) {
DEBUG_PRINTF("need to explode existing string '%s'\n",
dumpString(lit.s).c_str());
- explode.push_back(id);
+ explode.push_back(id);
} else {
literal_info[id].requires_benefits = true;
}
}
-
- for (u32 id : explode) {
- explodeLiteral(*this, id);
- }
+
+ for (u32 id : explode) {
+ explodeLiteral(*this, id);
+ }
}
// Returns the length of the longest prefix of s that is (a) also a suffix of s
@@ -294,7 +294,7 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) {
const RoseVertex u = source(e, g); /* pred role */
const RoseVertex v = target(e, g); /* current role */
- DEBUG_PRINTF("find history for [%zu,%zu]\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("find history for [%zu,%zu]\n", g[u].index, g[v].index);
DEBUG_PRINTF("u has min_offset=%u, max_offset=%u\n", g[u].min_offset,
g[u].max_offset);
@@ -335,9 +335,9 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) {
// If the bounds are {0,0}, this role can only match precisely at EOD.
if (minBound == 0 && maxBound == 0) {
- /* last byte history will squash the state byte so cannot have other
- * succ */
- assert(out_degree(u, g) == 1);
+ /* last byte history will squash the state byte so cannot have other
+ * succ */
+ assert(out_degree(u, g) == 1);
return ROSE_ROLE_HISTORY_LAST_BYTE;
}
@@ -348,7 +348,7 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) {
// Non-EOD cases.
DEBUG_PRINTF("examining edge [%zu,%zu] with bounds {%u,%u}\n",
- g[u].index, g[v].index, g[e].minBound, g[e].maxBound);
+ g[u].index, g[v].index, g[e].minBound, g[e].maxBound);
if (tbi.isAnchored(v)) {
// Matches for literals in the anchored table will always arrive at the
@@ -358,8 +358,8 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) {
return ROSE_ROLE_HISTORY_NONE;
}
- if (g[u].fixedOffset() &&
- (g[e].minBound || g[e].maxBound != ROSE_BOUND_INF)) {
+ if (g[u].fixedOffset() &&
+ (g[e].minBound || g[e].maxBound != ROSE_BOUND_INF)) {
DEBUG_PRINTF("fixed offset -> anch\n");
return ROSE_ROLE_HISTORY_ANCH;
}
@@ -402,7 +402,7 @@ bool RoseBuildImpl::isDirectReport(u32 id) const {
// role's reports from a list.
for (auto v : info.vertices) {
- assert(contains(g[v].literals, id));
+ assert(contains(g[v].literals, id));
if (g[v].reports.empty() ||
g[v].eod_accept || // no accept EOD
@@ -412,14 +412,14 @@ bool RoseBuildImpl::isDirectReport(u32 id) const {
return false;
}
- // Use the program to handle cases that aren't external reports.
- for (const ReportID &rid : g[v].reports) {
- if (!isExternalReport(rm.getReport(rid))) {
- return false;
- }
- }
-
- if (literals.at(id).table == ROSE_ANCHORED) {
+ // Use the program to handle cases that aren't external reports.
+ for (const ReportID &rid : g[v].reports) {
+ if (!isExternalReport(rm.getReport(rid))) {
+ return false;
+ }
+ }
+
+ if (literals.at(id).table == ROSE_ANCHORED) {
/* in-edges are irrelevant for anchored region. */
continue;
}
@@ -438,52 +438,52 @@ bool RoseBuildImpl::isDirectReport(u32 id) const {
}
DEBUG_PRINTF("literal %u ('%s') is a %s report\n", id,
- dumpString(literals.at(id).s).c_str(),
+ dumpString(literals.at(id).s).c_str(),
info.vertices.size() > 1 ? "multi-direct" : "direct");
return true;
}
-
-/* If we have prefixes that can squash all the floating roots, we can have a
- * somewhat-conditional floating table. As we can't yet look at squash_masks, we
- * have to make some guess as to if we are in this case but the win for not
- * running a floating table over a large portion of the stream is significantly
- * larger than avoiding running an eod table over the last N bytes. */
+
+/* If we have prefixes that can squash all the floating roots, we can have a
+ * somewhat-conditional floating table. As we can't yet look at squash_masks, we
+ * have to make some guess as to if we are in this case but the win for not
+ * running a floating table over a large portion of the stream is significantly
+ * larger than avoiding running an eod table over the last N bytes. */
+static
+bool checkFloatingKillableByPrefixes(const RoseBuildImpl &tbi) {
+ for (auto v : vertices_range(tbi.g)) {
+ if (!tbi.isRootSuccessor(v)) {
+ continue;
+ }
+
+ if (!tbi.isFloating(v)) {
+ continue;
+ }
+
+ if (!tbi.g[v].left) {
+ DEBUG_PRINTF("unguarded floating root\n");
+ return false;
+ }
+
+ if (tbi.g[v].left.graph) {
+ const NGHolder &h = *tbi.g[v].left.graph;
+ if (proper_out_degree(h.startDs, h)) {
+ DEBUG_PRINTF("floating nfa prefix, won't die\n");
+ return false;
+ }
+ } else if (tbi.g[v].left.dfa) {
+ if (tbi.g[v].left.dfa->start_floating != DEAD_STATE) {
+ DEBUG_PRINTF("floating dfa prefix, won't die\n");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
static
-bool checkFloatingKillableByPrefixes(const RoseBuildImpl &tbi) {
- for (auto v : vertices_range(tbi.g)) {
- if (!tbi.isRootSuccessor(v)) {
- continue;
- }
-
- if (!tbi.isFloating(v)) {
- continue;
- }
-
- if (!tbi.g[v].left) {
- DEBUG_PRINTF("unguarded floating root\n");
- return false;
- }
-
- if (tbi.g[v].left.graph) {
- const NGHolder &h = *tbi.g[v].left.graph;
- if (proper_out_degree(h.startDs, h)) {
- DEBUG_PRINTF("floating nfa prefix, won't die\n");
- return false;
- }
- } else if (tbi.g[v].left.dfa) {
- if (tbi.g[v].left.dfa->start_floating != DEAD_STATE) {
- DEBUG_PRINTF("floating dfa prefix, won't die\n");
- return false;
- }
- }
- }
-
- return true;
-}
-
-static
-bool checkEodStealFloating(const RoseBuildImpl &build,
+bool checkEodStealFloating(const RoseBuildImpl &build,
const vector<u32> &eodLiteralsForFloating,
u32 numFloatingLiterals,
size_t shortestFloatingLen) {
@@ -497,35 +497,35 @@ bool checkEodStealFloating(const RoseBuildImpl &build,
return false;
}
- if (build.hasNoFloatingRoots()) {
+ if (build.hasNoFloatingRoots()) {
DEBUG_PRINTF("skipping as floating table is conditional\n");
/* TODO: investigate putting stuff in atable */
return false;
}
- if (checkFloatingKillableByPrefixes(build)) {
- DEBUG_PRINTF("skipping as prefixes may make ftable conditional\n");
- return false;
- }
-
- // Collect a set of all floating literals.
- unordered_set<ue2_literal> floating_lits;
- for (auto &lit : build.literals) {
- if (lit.table == ROSE_FLOATING) {
- floating_lits.insert(lit.s);
- }
- }
-
+ if (checkFloatingKillableByPrefixes(build)) {
+ DEBUG_PRINTF("skipping as prefixes may make ftable conditional\n");
+ return false;
+ }
+
+ // Collect a set of all floating literals.
+ unordered_set<ue2_literal> floating_lits;
+ for (auto &lit : build.literals) {
+ if (lit.table == ROSE_FLOATING) {
+ floating_lits.insert(lit.s);
+ }
+ }
+
DEBUG_PRINTF("%zu are eod literals, %u floating; floating len=%zu\n",
eodLiteralsForFloating.size(), numFloatingLiterals,
shortestFloatingLen);
u32 new_floating_lits = 0;
for (u32 eod_id : eodLiteralsForFloating) {
- const rose_literal_id &lit = build.literals.at(eod_id);
+ const rose_literal_id &lit = build.literals.at(eod_id);
DEBUG_PRINTF("checking '%s'\n", dumpString(lit.s).c_str());
- if (contains(floating_lits, lit.s)) {
+ if (contains(floating_lits, lit.s)) {
DEBUG_PRINTF("skip; there is already a floating version\n");
continue;
}
@@ -556,16 +556,16 @@ bool checkEodStealFloating(const RoseBuildImpl &build,
static
void promoteEodToFloating(RoseBuildImpl &tbi, const vector<u32> &eodLiterals) {
- DEBUG_PRINTF("promoting %zu eod literals to floating table\n",
- eodLiterals.size());
+ DEBUG_PRINTF("promoting %zu eod literals to floating table\n",
+ eodLiterals.size());
for (u32 eod_id : eodLiterals) {
- const rose_literal_id &lit = tbi.literals.at(eod_id);
- DEBUG_PRINTF("eod_id=%u, lit=%s\n", eod_id, dumpString(lit.s).c_str());
+ const rose_literal_id &lit = tbi.literals.at(eod_id);
+ DEBUG_PRINTF("eod_id=%u, lit=%s\n", eod_id, dumpString(lit.s).c_str());
u32 floating_id = tbi.getLiteralId(lit.s, lit.msk, lit.cmp, lit.delay,
ROSE_FLOATING);
- DEBUG_PRINTF("floating_id=%u, lit=%s\n", floating_id,
- dumpString(tbi.literals.at(floating_id).s).c_str());
+ DEBUG_PRINTF("floating_id=%u, lit=%s\n", floating_id,
+ dumpString(tbi.literals.at(floating_id).s).c_str());
auto &float_verts = tbi.literal_info[floating_id].vertices;
auto &eod_verts = tbi.literal_info[eod_id].vertices;
@@ -590,7 +590,7 @@ bool promoteEodToAnchored(RoseBuildImpl &tbi, const vector<u32> &eodLiterals) {
bool rv = true;
for (u32 eod_id : eodLiterals) {
- const rose_literal_id &lit = tbi.literals.at(eod_id);
+ const rose_literal_id &lit = tbi.literals.at(eod_id);
NGHolder h;
add_edge(h.start, h.accept, h);
@@ -730,7 +730,7 @@ void stealEodVertices(RoseBuildImpl &tbi) {
continue; // skip unused literals
}
- const rose_literal_id &lit = tbi.literals.at(i);
+ const rose_literal_id &lit = tbi.literals.at(i);
if (lit.table == ROSE_EOD_ANCHORED) {
if (suitableForAnchored(tbi, lit, info)) {
@@ -770,335 +770,335 @@ bool RoseBuildImpl::isDelayed(u32 id) const {
return literal_info.at(id).undelayed_id != id;
}
-bool RoseBuildImpl::hasDelayedLiteral(RoseVertex v) const {
- for (u32 lit_id : g[v].literals) {
- if (literals.at(lit_id).delay) {
- return true;
+bool RoseBuildImpl::hasDelayedLiteral(RoseVertex v) const {
+ for (u32 lit_id : g[v].literals) {
+ if (literals.at(lit_id).delay) {
+ return true;
}
}
- return false;
+ return false;
}
-bool RoseBuildImpl::hasDelayPred(RoseVertex v) const {
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (hasDelayedLiteral(u)) {
- return true;
+bool RoseBuildImpl::hasDelayPred(RoseVertex v) const {
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (hasDelayedLiteral(u)) {
+ return true;
}
}
return false;
}
-bool RoseBuildImpl::hasAnchoredTablePred(RoseVertex v) const {
+bool RoseBuildImpl::hasAnchoredTablePred(RoseVertex v) const {
for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (isAnchored(u)) {
- return true;
+ if (isAnchored(u)) {
+ return true;
}
}
- return false;
+ return false;
}
-void RoseBuildImpl::findTransientLeftfixes(void) {
- for (auto v : vertices_range(g)) {
- if (!g[v].left) {
+void RoseBuildImpl::findTransientLeftfixes(void) {
+ for (auto v : vertices_range(g)) {
+ if (!g[v].left) {
continue;
}
- /* infixes can never (or at least not yet) be transient */
- if (isNonRootSuccessor(v)) {
+ /* infixes can never (or at least not yet) be transient */
+ if (isNonRootSuccessor(v)) {
continue;
}
- const left_id &left(g[v].left);
+ const left_id &left(g[v].left);
- if (::ue2::isAnchored(left) && !isInETable(v)) {
- /* etable prefixes currently MUST be transient as we do not know
- * where we can safely catch them up to (yet). */
- DEBUG_PRINTF("anchored roses in rocky soil are not fleeting\n");
- continue;
- }
+ if (::ue2::isAnchored(left) && !isInETable(v)) {
+ /* etable prefixes currently MUST be transient as we do not know
+ * where we can safely catch them up to (yet). */
+ DEBUG_PRINTF("anchored roses in rocky soil are not fleeting\n");
+ continue;
+ }
- const depth max_width = findMaxWidth(left);
- if (!max_width.is_finite()) {
- DEBUG_PRINTF("inf max width\n");
+ const depth max_width = findMaxWidth(left);
+ if (!max_width.is_finite()) {
+ DEBUG_PRINTF("inf max width\n");
continue;
}
- if (cc.streaming) {
- /* STREAMING: transient prefixes must be able to run using history
- * rather than storing state. */
- u32 his = g[v].left.lag + max_width;
+ if (cc.streaming) {
+ /* STREAMING: transient prefixes must be able to run using history
+ * rather than storing state. */
+ u32 his = g[v].left.lag + max_width;
- // If this vertex has an event literal, we need to add one to cope
- // with it.
- if (hasLiteralInTable(v, ROSE_EVENT)) {
- his++;
- }
+ // If this vertex has an event literal, we need to add one to cope
+ // with it.
+ if (hasLiteralInTable(v, ROSE_EVENT)) {
+ his++;
+ }
- /* +1 as trigger must appear in main buffer and no byte is needed to
- * decompress the state */
- if (his <= cc.grey.maxHistoryAvailable + 1) {
- transient.insert(left);
- DEBUG_PRINTF("a transient leftfix spotted his=%u\n", his);
+ /* +1 as trigger must appear in main buffer and no byte is needed to
+ * decompress the state */
+ if (his <= cc.grey.maxHistoryAvailable + 1) {
+ transient.insert(left);
+ DEBUG_PRINTF("a transient leftfix spotted his=%u\n", his);
+ }
+ } else {
+ /* BLOCK: transientness is less important and more fuzzy, ideally
+ * it should be quick to calculate the state. No need to worry about
+ * history (and hence lag). */
+ if (max_width < depth(ROSE_BLOCK_TRANSIENT_MAX_WIDTH)) {
+ transient.insert(left);
+ DEBUG_PRINTF("a transient block leftfix spotted [%u]\n",
+ (u32)max_width);
}
- } else {
- /* BLOCK: transientness is less important and more fuzzy, ideally
- * it should be quick to calculate the state. No need to worry about
- * history (and hence lag). */
- if (max_width < depth(ROSE_BLOCK_TRANSIENT_MAX_WIDTH)) {
- transient.insert(left);
- DEBUG_PRINTF("a transient block leftfix spotted [%u]\n",
- (u32)max_width);
- }
- }
- }
-}
-
-/** Find all the different roses and their associated literals. */
-static
-map<left_id, vector<RoseVertex>> findLeftSucc(const RoseBuildImpl &build) {
- map<left_id, vector<RoseVertex>> leftfixes;
- for (auto v : vertices_range(build.g)) {
- if (build.g[v].left) {
- const LeftEngInfo &lei = build.g[v].left;
- leftfixes[lei].push_back(v);
- }
- }
- return leftfixes;
-}
-
-namespace {
-struct infix_info {
- set<RoseVertex> preds;
- set<RoseVertex> succs;
-};
-}
-
-static
-map<NGHolder *, infix_info> findInfixGraphInfo(const RoseBuildImpl &build) {
- map<NGHolder *, infix_info> rv;
-
- for (auto v : vertices_range(build.g)) {
- if (!build.g[v].left) {
+ }
+ }
+}
+
+/** Find all the different roses and their associated literals. */
+static
+map<left_id, vector<RoseVertex>> findLeftSucc(const RoseBuildImpl &build) {
+ map<left_id, vector<RoseVertex>> leftfixes;
+ for (auto v : vertices_range(build.g)) {
+ if (build.g[v].left) {
+ const LeftEngInfo &lei = build.g[v].left;
+ leftfixes[lei].push_back(v);
+ }
+ }
+ return leftfixes;
+}
+
+namespace {
+struct infix_info {
+ set<RoseVertex> preds;
+ set<RoseVertex> succs;
+};
+}
+
+static
+map<NGHolder *, infix_info> findInfixGraphInfo(const RoseBuildImpl &build) {
+ map<NGHolder *, infix_info> rv;
+
+ for (auto v : vertices_range(build.g)) {
+ if (!build.g[v].left) {
continue;
}
- if (build.isRootSuccessor(v)) {
- DEBUG_PRINTF("a prefix is never an infix\n");
- continue;
+ if (build.isRootSuccessor(v)) {
+ DEBUG_PRINTF("a prefix is never an infix\n");
+ continue;
}
- /* ensure only proper nfas */
- const LeftEngInfo &lei = build.g[v].left;
- if (!lei.graph) {
+ /* ensure only proper nfas */
+ const LeftEngInfo &lei = build.g[v].left;
+ if (!lei.graph) {
continue;
}
- if (lei.haig || lei.dfa) {
- continue;
+ if (lei.haig || lei.dfa) {
+ continue;
}
- assert(!lei.castle);
- infix_info &info = rv[lei.graph.get()];
- insert(&info.preds, inv_adjacent_vertices_range(v, build.g));
- info.succs.insert(v);
+ assert(!lei.castle);
+ infix_info &info = rv[lei.graph.get()];
+ insert(&info.preds, inv_adjacent_vertices_range(v, build.g));
+ info.succs.insert(v);
}
- return rv;
+ return rv;
}
-static
-map<u32, flat_set<NFAEdge>> getTopInfo(const NGHolder &h) {
- map<u32, flat_set<NFAEdge>> rv;
- for (NFAEdge e : out_edges_range(h.start, h)) {
- for (u32 t : h[e].tops) {
- rv[t].insert(e);
+static
+map<u32, flat_set<NFAEdge>> getTopInfo(const NGHolder &h) {
+ map<u32, flat_set<NFAEdge>> rv;
+ for (NFAEdge e : out_edges_range(h.start, h)) {
+ for (u32 t : h[e].tops) {
+ rv[t].insert(e);
}
}
- return rv;
+ return rv;
}
-static
-u32 findUnusedTop(const map<u32, flat_set<NFAEdge>> &tops) {
- u32 i = 0;
- while (contains(tops, i)) {
- i++;
+static
+u32 findUnusedTop(const map<u32, flat_set<NFAEdge>> &tops) {
+ u32 i = 0;
+ while (contains(tops, i)) {
+ i++;
}
- return i;
+ return i;
}
-static
-bool reduceTopTriggerLoad(RoseBuildImpl &build, NGHolder &h, RoseVertex u) {
- RoseGraph &g = build.g;
-
- set<u32> tops; /* tops triggered by u */
- for (RoseEdge e : out_edges_range(u, g)) {
- RoseVertex v = target(e, g);
- if (g[v].left.graph.get() != &h) {
- continue;
+static
+bool reduceTopTriggerLoad(RoseBuildImpl &build, NGHolder &h, RoseVertex u) {
+ RoseGraph &g = build.g;
+
+ set<u32> tops; /* tops triggered by u */
+ for (RoseEdge e : out_edges_range(u, g)) {
+ RoseVertex v = target(e, g);
+ if (g[v].left.graph.get() != &h) {
+ continue;
}
- tops.insert(g[e].rose_top);
+ tops.insert(g[e].rose_top);
}
- assert(!tops.empty());
- if (tops.size() <= 1) {
+ assert(!tops.empty());
+ if (tops.size() <= 1) {
return false;
}
- DEBUG_PRINTF("%zu triggers %zu tops for %p\n", build.g[u].index,
- tops.size(), &h);
+ DEBUG_PRINTF("%zu triggers %zu tops for %p\n", build.g[u].index,
+ tops.size(), &h);
- auto h_top_info = getTopInfo(h);
- flat_set<NFAEdge> edges_to_trigger;
- for (u32 t : tops) {
- insert(&edges_to_trigger, h_top_info[t]);
+ auto h_top_info = getTopInfo(h);
+ flat_set<NFAEdge> edges_to_trigger;
+ for (u32 t : tops) {
+ insert(&edges_to_trigger, h_top_info[t]);
}
- u32 new_top = ~0U;
- /* check if there is already a top with the right the successor set */
- for (const auto &elem : h_top_info) {
- if (elem.second == edges_to_trigger) {
- new_top = elem.first;
- break;
+ u32 new_top = ~0U;
+ /* check if there is already a top with the right the successor set */
+ for (const auto &elem : h_top_info) {
+ if (elem.second == edges_to_trigger) {
+ new_top = elem.first;
+ break;
}
}
- /* if no existing suitable top, add a new top for us */
- if (new_top == ~0U) {
- new_top = findUnusedTop(h_top_info);
+ /* if no existing suitable top, add a new top for us */
+ if (new_top == ~0U) {
+ new_top = findUnusedTop(h_top_info);
- /* add top to edges out of start */
- for (NFAEdge e : out_edges_range(h.start, h)) {
- if (has_intersection(tops, h[e].tops)) {
- h[e].tops.insert(new_top);
- }
+ /* add top to edges out of start */
+ for (NFAEdge e : out_edges_range(h.start, h)) {
+ if (has_intersection(tops, h[e].tops)) {
+ h[e].tops.insert(new_top);
+ }
}
- /* check still implementable if we add a new top */
- if (!isImplementableNFA(h, nullptr, build.cc)) {
- DEBUG_PRINTF("unable to add new top\n");
- for (NFAEdge e : out_edges_range(h.start, h)) {
- h[e].tops.erase(new_top);
- }
- /* we should be back to the original graph */
- assert(isImplementableNFA(h, nullptr, build.cc));
+ /* check still implementable if we add a new top */
+ if (!isImplementableNFA(h, nullptr, build.cc)) {
+ DEBUG_PRINTF("unable to add new top\n");
+ for (NFAEdge e : out_edges_range(h.start, h)) {
+ h[e].tops.erase(new_top);
+ }
+ /* we should be back to the original graph */
+ assert(isImplementableNFA(h, nullptr, build.cc));
return false;
}
}
- DEBUG_PRINTF("using new merged top %u\n", new_top);
- assert(new_top != ~0U);
- for (RoseEdge e: out_edges_range(u, g)) {
- RoseVertex v = target(e, g);
- if (g[v].left.graph.get() != &h) {
- continue;
+ DEBUG_PRINTF("using new merged top %u\n", new_top);
+ assert(new_top != ~0U);
+ for (RoseEdge e: out_edges_range(u, g)) {
+ RoseVertex v = target(e, g);
+ if (g[v].left.graph.get() != &h) {
+ continue;
}
- g[e].rose_top = new_top;
+ g[e].rose_top = new_top;
}
- return true;
+ return true;
}
static
-void packInfixTops(NGHolder &h, RoseGraph &g,
- const set<RoseVertex> &verts) {
- if (!is_triggered(h)) {
- DEBUG_PRINTF("not triggered, no tops\n");
- return;
+void packInfixTops(NGHolder &h, RoseGraph &g,
+ const set<RoseVertex> &verts) {
+ if (!is_triggered(h)) {
+ DEBUG_PRINTF("not triggered, no tops\n");
+ return;
}
- assert(isCorrectlyTopped(h));
- DEBUG_PRINTF("pruning unused tops\n");
- flat_set<u32> used_tops;
- for (auto v : verts) {
- assert(g[v].left.graph.get() == &h);
+ assert(isCorrectlyTopped(h));
+ DEBUG_PRINTF("pruning unused tops\n");
+ flat_set<u32> used_tops;
+ for (auto v : verts) {
+ assert(g[v].left.graph.get() == &h);
- for (const auto &e : in_edges_range(v, g)) {
- u32 top = g[e].rose_top;
- used_tops.insert(top);
- }
+ for (const auto &e : in_edges_range(v, g)) {
+ u32 top = g[e].rose_top;
+ used_tops.insert(top);
+ }
}
- map<u32, u32> top_mapping;
- for (u32 t : used_tops) {
- u32 new_top = top_mapping.size();
- top_mapping[t] = new_top;
+ map<u32, u32> top_mapping;
+ for (u32 t : used_tops) {
+ u32 new_top = top_mapping.size();
+ top_mapping[t] = new_top;
}
- for (auto v : verts) {
- assert(g[v].left.graph.get() == &h);
+ for (auto v : verts) {
+ assert(g[v].left.graph.get() == &h);
- for (const auto &e : in_edges_range(v, g)) {
- g[e].rose_top = top_mapping.at(g[e].rose_top);
+ for (const auto &e : in_edges_range(v, g)) {
+ g[e].rose_top = top_mapping.at(g[e].rose_top);
}
- }
+ }
- vector<NFAEdge> dead;
- for (const auto &e : out_edges_range(h.start, h)) {
- NFAVertex v = target(e, h);
- if (v == h.startDs) {
- continue; // stylised edge, leave it alone.
+ vector<NFAEdge> dead;
+ for (const auto &e : out_edges_range(h.start, h)) {
+ NFAVertex v = target(e, h);
+ if (v == h.startDs) {
+ continue; // stylised edge, leave it alone.
}
- flat_set<u32> updated_tops;
- for (u32 t : h[e].tops) {
- if (contains(top_mapping, t)) {
- updated_tops.insert(top_mapping.at(t));
+ flat_set<u32> updated_tops;
+ for (u32 t : h[e].tops) {
+ if (contains(top_mapping, t)) {
+ updated_tops.insert(top_mapping.at(t));
}
}
- h[e].tops = std::move(updated_tops);
- if (h[e].tops.empty()) {
- DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index);
- dead.push_back(e);
+ h[e].tops = std::move(updated_tops);
+ if (h[e].tops.empty()) {
+ DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index);
+ dead.push_back(e);
}
}
- if (dead.empty()) {
- return;
+ if (dead.empty()) {
+ return;
}
- remove_edges(dead, h);
- pruneUseless(h);
- clearReports(h); // As we may have removed vacuous edges.
+ remove_edges(dead, h);
+ pruneUseless(h);
+ clearReports(h); // As we may have removed vacuous edges.
}
static
-void reduceTopTriggerLoad(RoseBuildImpl &build) {
- auto infixes = findInfixGraphInfo(build);
+void reduceTopTriggerLoad(RoseBuildImpl &build) {
+ auto infixes = findInfixGraphInfo(build);
- for (auto &p : infixes) {
- if (onlyOneTop(*p.first)) {
+ for (auto &p : infixes) {
+ if (onlyOneTop(*p.first)) {
continue;
}
- bool changed = false;
- for (RoseVertex v : p.second.preds) {
- changed |= reduceTopTriggerLoad(build, *p.first, v);
+ bool changed = false;
+ for (RoseVertex v : p.second.preds) {
+ changed |= reduceTopTriggerLoad(build, *p.first, v);
}
- if (changed) {
- packInfixTops(*p.first, build.g, p.second.succs);
- reduceImplementableGraph(*p.first, SOM_NONE, nullptr, build.cc);
+ if (changed) {
+ packInfixTops(*p.first, build.g, p.second.succs);
+ reduceImplementableGraph(*p.first, SOM_NONE, nullptr, build.cc);
}
}
}
static
-bool triggerKillsRoseGraph(const RoseBuildImpl &build, const left_id &left,
+bool triggerKillsRoseGraph(const RoseBuildImpl &build, const left_id &left,
const set<ue2_literal> &all_lits,
const RoseEdge &e) {
assert(left.graph());
const NGHolder &h = *left.graph();
- flat_set<NFAVertex> all_states;
+ flat_set<NFAVertex> all_states;
insert(&all_states, vertices(h));
assert(out_degree(h.startDs, h) == 1); /* triggered don't use sds */
DEBUG_PRINTF("removing sds\n");
all_states.erase(h.startDs);
- flat_set<NFAVertex> states;
+ flat_set<NFAVertex> states;
/* check each pred literal to see if they all kill previous graph
* state */
- for (u32 lit_id : build.g[source(e, build.g)].literals) {
- const rose_literal_id &pred_lit = build.literals.at(lit_id);
+ for (u32 lit_id : build.g[source(e, build.g)].literals) {
+ const rose_literal_id &pred_lit = build.literals.at(lit_id);
const ue2_literal s = findNonOverlappingTail(all_lits, pred_lit.s);
DEBUG_PRINTF("running graph %zu\n", states.size());
@@ -1114,7 +1114,7 @@ bool triggerKillsRoseGraph(const RoseBuildImpl &build, const left_id &left,
}
static
-bool triggerKillsRose(const RoseBuildImpl &build, const left_id &left,
+bool triggerKillsRose(const RoseBuildImpl &build, const left_id &left,
const set<ue2_literal> &all_lits, const RoseEdge &e) {
if (left.haig()) {
/* TODO: To allow this for som-based engines we would also need to
@@ -1124,30 +1124,30 @@ bool triggerKillsRose(const RoseBuildImpl &build, const left_id &left,
}
if (left.graph()) {
- return triggerKillsRoseGraph(build, left, all_lits, e);
+ return triggerKillsRoseGraph(build, left, all_lits, e);
}
if (left.castle()) {
- return triggerKillsRoseCastle(build, left, all_lits, e);
+ return triggerKillsRoseCastle(build, left, all_lits, e);
}
return false;
}
-/* Sometimes the arrival of a top for a rose infix can ensure that the nfa would
- * be dead at that time. In the case of multiple trigger literals, we can only
- * base our decision on that portion of literal after any overlapping literals.
- */
+/* Sometimes the arrival of a top for a rose infix can ensure that the nfa would
+ * be dead at that time. In the case of multiple trigger literals, we can only
+ * base our decision on that portion of literal after any overlapping literals.
+ */
static
-void findTopTriggerCancels(RoseBuildImpl &build) {
- auto left_succ = findLeftSucc(build); /* leftfixes -> succ verts */
+void findTopTriggerCancels(RoseBuildImpl &build) {
+ auto left_succ = findLeftSucc(build); /* leftfixes -> succ verts */
- for (const auto &r : left_succ) {
+ for (const auto &r : left_succ) {
const left_id &left = r.first;
const vector<RoseVertex> &succs = r.second;
assert(!succs.empty());
- if (build.isRootSuccessor(*succs.begin())) {
+ if (build.isRootSuccessor(*succs.begin())) {
/* a prefix is never an infix */
continue;
}
@@ -1157,10 +1157,10 @@ void findTopTriggerCancels(RoseBuildImpl &build) {
set<u32> pred_lit_ids;
for (auto v : succs) {
- for (const auto &e : in_edges_range(v, build.g)) {
- RoseVertex u = source(e, build.g);
- tops_seen.insert(build.g[e].rose_top);
- insert(&pred_lit_ids, build.g[u].literals);
+ for (const auto &e : in_edges_range(v, build.g)) {
+ RoseVertex u = source(e, build.g);
+ tops_seen.insert(build.g[e].rose_top);
+ insert(&pred_lit_ids, build.g[u].literals);
rose_edges.insert(e);
}
}
@@ -1172,7 +1172,7 @@ void findTopTriggerCancels(RoseBuildImpl &build) {
}
for (u32 lit_id : pred_lit_ids) {
- const rose_literal_id &p_lit = build.literals.at(lit_id);
+ const rose_literal_id &p_lit = build.literals.at(lit_id);
if (p_lit.delay || p_lit.table == ROSE_ANCHORED) {
goto next_rose;
}
@@ -1184,9 +1184,9 @@ void findTopTriggerCancels(RoseBuildImpl &build) {
all_lits.size(), rose_edges.size());
for (const auto &e : rose_edges) {
- if (triggerKillsRose(build, left, all_lits, e)) {
+ if (triggerKillsRose(build, left, all_lits, e)) {
DEBUG_PRINTF("top will override previous rose state\n");
- build.g[e].rose_cancel_prev_top = true;
+ build.g[e].rose_cancel_prev_top = true;
}
}
next_rose:;
@@ -1194,13 +1194,13 @@ void findTopTriggerCancels(RoseBuildImpl &build) {
}
static
-void optimiseRoseTops(RoseBuildImpl &build) {
- reduceTopTriggerLoad(build);
- /* prune unused tops ? */
- findTopTriggerCancels(build);
-}
-
-static
+void optimiseRoseTops(RoseBuildImpl &build) {
+ reduceTopTriggerLoad(build);
+ /* prune unused tops ? */
+ findTopTriggerCancels(build);
+}
+
+static
void buildRoseSquashMasks(RoseBuildImpl &tbi) {
/* Rose nfa squash masks are applied to the groups when the nfa can no
* longer match */
@@ -1243,15 +1243,15 @@ void buildRoseSquashMasks(RoseBuildImpl &tbi) {
}
}
- rose_group unsquashable = tbi.boundary_group_mask;
+ rose_group unsquashable = tbi.boundary_group_mask;
for (u32 lit_id : lit_ids) {
const rose_literal_info &info = tbi.literal_info[lit_id];
- if (!info.delayed_ids.empty()
- || !all_of_in(info.vertices,
- [&](RoseVertex v) {
- return left == tbi.g[v].left; })) {
- DEBUG_PRINTF("group %llu is unsquashable\n", info.group_mask);
+ if (!info.delayed_ids.empty()
+ || !all_of_in(info.vertices,
+ [&](RoseVertex v) {
+ return left == tbi.g[v].left; })) {
+ DEBUG_PRINTF("group %llu is unsquashable\n", info.group_mask);
unsquashable |= info.group_mask;
}
}
@@ -1273,7 +1273,7 @@ void countFloatingLiterals(const RoseBuildImpl &tbi, u32 *total_count,
u32 *short_count) {
*total_count = 0;
*short_count = 0;
- for (const rose_literal_id &lit : tbi.literals) {
+ for (const rose_literal_id &lit : tbi.literals) {
if (lit.delay) {
continue; /* delay id's are virtual-ish */
}
@@ -1384,7 +1384,7 @@ void addSmallBlockLiteral(RoseBuildImpl &tbi, const simple_anchored_info &sai,
assert(old_id < tbi.literal_info.size());
const rose_literal_info &li = tbi.literal_info[old_id];
- for (auto lit_v : li.vertices) {
+ for (auto lit_v : li.vertices) {
// Clone vertex with the new literal ID.
RoseVertex v = add_vertex(g[lit_v], g);
g[v].literals.clear();
@@ -1393,9 +1393,9 @@ void addSmallBlockLiteral(RoseBuildImpl &tbi, const simple_anchored_info &sai,
g[v].max_offset = sai.max_bound + sai.literal.length();
lit_info.vertices.insert(v);
- RoseEdge e = add_edge(anchored_root, v, g);
- g[e].minBound = sai.min_bound;
- g[e].maxBound = sai.max_bound;
+ RoseEdge e = add_edge(anchored_root, v, g);
+ g[e].minBound = sai.min_bound;
+ g[e].maxBound = sai.max_bound;
}
}
}
@@ -1417,7 +1417,7 @@ void addSmallBlockLiteral(RoseBuildImpl &tbi, const ue2_literal &lit,
g[v].literals.insert(lit_id);
g[v].reports = reports;
- RoseEdge e = add_edge(tbi.root, v, g);
+ RoseEdge e = add_edge(tbi.root, v, g);
g[e].minBound = 0;
g[e].maxBound = ROSE_BOUND_INF;
g[v].min_offset = 1;
@@ -1533,8 +1533,8 @@ bool extractSEPLiterals(const OutfixInfo &outfix, const ReportManager &rm,
// SEP cases should always become DFAs, so that's the only extract code we
// have implemented here.
- if (outfix.rdfa()) {
- return extractSEPLiterals(*outfix.rdfa(), lits_out);
+ if (outfix.rdfa()) {
+ return extractSEPLiterals(*outfix.rdfa(), lits_out);
}
DEBUG_PRINTF("cannot extract literals from outfix type\n");
@@ -1623,7 +1623,7 @@ bool historiesAreValid(const RoseGraph &g) {
for (const auto &e : edges_range(g)) {
if (g[e].history == ROSE_ROLE_HISTORY_INVALID) {
DEBUG_PRINTF("edge [%zu,%zu] has invalid history\n",
- g[source(e, g)].index, g[target(e, g)].index);
+ g[source(e, g)].index, g[target(e, g)].index);
return false;
}
}
@@ -1639,23 +1639,23 @@ static
bool danglingVertexRef(RoseBuildImpl &tbi) {
RoseGraph::vertex_iterator vi, ve;
tie(vi, ve) = vertices(tbi.g);
- const unordered_set<RoseVertex> valid_vertices(vi, ve);
+ const unordered_set<RoseVertex> valid_vertices(vi, ve);
if (!contains(valid_vertices, tbi.anchored_root)) {
- DEBUG_PRINTF("anchored root vertex %zu not in graph\n",
- tbi.g[tbi.anchored_root].index);
+ DEBUG_PRINTF("anchored root vertex %zu not in graph\n",
+ tbi.g[tbi.anchored_root].index);
return true;
}
for (const auto &e : tbi.ghost) {
if (!contains(valid_vertices, e.first)) {
- DEBUG_PRINTF("ghost key vertex %zu not in graph\n",
- tbi.g[e.first].index);
+ DEBUG_PRINTF("ghost key vertex %zu not in graph\n",
+ tbi.g[e.first].index);
return true;
}
if (!contains(valid_vertices, e.second)) {
- DEBUG_PRINTF("ghost value vertex %zu not in graph\n",
- tbi.g[e.second].index);
+ DEBUG_PRINTF("ghost value vertex %zu not in graph\n",
+ tbi.g[e.second].index);
return true;
}
}
@@ -1667,11 +1667,11 @@ static
bool roleOffsetsAreValid(const RoseGraph &g) {
for (auto v : vertices_range(g)) {
if (g[v].min_offset >= ROSE_BOUND_INF) {
- DEBUG_PRINTF("invalid min_offset for role %zu\n", g[v].index);
+ DEBUG_PRINTF("invalid min_offset for role %zu\n", g[v].index);
return false;
}
if (g[v].min_offset > g[v].max_offset) {
- DEBUG_PRINTF("min_offset > max_offset for %zu\n", g[v].index);
+ DEBUG_PRINTF("min_offset > max_offset for %zu\n", g[v].index);
return false;
}
}
@@ -1679,8 +1679,8 @@ bool roleOffsetsAreValid(const RoseGraph &g) {
}
#endif // NDEBUG
-bytecode_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
- dumpRoseGraph(*this, "rose_early.dot");
+bytecode_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
+ dumpRoseGraph(*this, "rose_early.dot");
// Early check for Rose implementability.
assert(canImplementGraphs(*this));
@@ -1700,8 +1700,8 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
// If we've got a very small number of EOD-anchored literals, consider
// moving them into the floating table so that we only have one literal
- // matcher to run. Note that this needs to happen before
- // addAnchoredSmallBlockLiterals as it may create anchored literals.
+ // matcher to run. Note that this needs to happen before
+ // addAnchoredSmallBlockLiterals as it may create anchored literals.
assert(roleOffsetsAreValid(g));
stealEodVertices(*this);
@@ -1755,27 +1755,27 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
mergeSmallLeftfixes(*this);
}
- assert(!hasOrphanedTops(*this));
-
+ assert(!hasOrphanedTops(*this));
+
// Do a rose-merging aliasing pass.
aliasRoles(*this, true);
- assert(!hasOrphanedTops(*this));
+ assert(!hasOrphanedTops(*this));
// Run a merge pass over the outfixes as well.
mergeOutfixes(*this);
assert(!danglingVertexRef(*this));
- assert(!hasOrphanedTops(*this));
+ assert(!hasOrphanedTops(*this));
+
+ findMoreLiteralMasks(*this);
- findMoreLiteralMasks(*this);
-
- assignGroupsToLiterals(*this);
- assignGroupsToRoles(*this);
+ assignGroupsToLiterals(*this);
+ assignGroupsToRoles(*this);
findGroupSquashers(*this);
/* final prep work */
remapCastleTops(*this);
- optimiseRoseTops(*this);
+ optimiseRoseTops(*this);
buildRoseSquashMasks(*this);
rm.assignDkeys(this);
@@ -1791,7 +1791,7 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
assert(roleOffsetsAreValid(g));
assert(historiesAreValid(g));
- dumpRoseGraph(*this, "rose_pre_norm.dot");
+ dumpRoseGraph(*this, "rose_pre_norm.dot");
return buildFinalEngine(minWidth);
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_convert.cpp b/contrib/libs/hyperscan/src/rose/rose_build_convert.cpp
index 18815ef8b51..33351099f70 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_convert.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_convert.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -58,8 +58,8 @@
#include <queue>
#include <set>
#include <string>
-#include <unordered_map>
-#include <utility>
+#include <unordered_map>
+#include <utility>
#include <vector>
#include <boost/range/adaptor/map.hpp>
@@ -85,7 +85,7 @@ size_t suffixFloodLen(const ue2_literal &s) {
const ue2_literal::elem &c = s.back();
auto it = find_if(s.rbegin(), s.rend(),
- [&c](const ue2_literal::elem &e) { return e != c; });
+ [&c](const ue2_literal::elem &e) { return e != c; });
return distance(s.rbegin(), it);
}
@@ -100,10 +100,10 @@ unique_ptr<NGHolder> makeFloodProneSuffix(const ue2_literal &s, size_t len,
NFAVertex u = h->start;
for (auto it = s.begin() + s.length() - len; it != s.end(); ++it) {
NFAVertex v = addHolderVertex(*it, *h);
- NFAEdge e = add_edge(u, v, *h);
- if (u == h->start) {
- (*h)[e].tops.insert(DEFAULT_TOP);
- }
+ NFAEdge e = add_edge(u, v, *h);
+ if (u == h->start) {
+ (*h)[e].tops.insert(DEFAULT_TOP);
+ }
u = v;
}
@@ -167,7 +167,7 @@ bool delayLiteralWithPrefix(RoseBuildImpl &tbi, RoseVertex v, u32 lit_id,
shared_ptr<NGHolder> h = makeRosePrefix(lit.s);
ReportID prefix_report = 0;
- set_report(*h, prefix_report);
+ set_report(*h, prefix_report);
if (!isImplementableNFA(*h, &tbi.rm, tbi.cc)) {
DEBUG_PRINTF("prefix not implementable\n");
@@ -236,7 +236,7 @@ void convertFloodProneSuffix(RoseBuildImpl &tbi, RoseVertex v, u32 lit_id,
static
size_t findFloodProneSuffixLen(const RoseBuildImpl &tbi) {
size_t numLiterals = 0;
- for (const rose_literal_id &lit : tbi.literals) {
+ for (const rose_literal_id &lit : tbi.literals) {
if (lit.delay) {
continue; // delay ids are virtual-ish
}
@@ -294,7 +294,7 @@ void convertFloodProneSuffixes(RoseBuildImpl &tbi) {
}
u32 lit_id = *g[v].literals.begin();
- const rose_literal_id &lit = tbi.literals.at(lit_id);
+ const rose_literal_id &lit = tbi.literals.at(lit_id);
// anchored or delayed literals need thought.
if (lit.table != ROSE_FLOATING || lit.delay) {
@@ -354,27 +354,27 @@ CharReach getReachOfNormalVertex(const NGHolder &g) {
return CharReach();
}
-/**
- * \brief Set the edge bounds and appropriate history on the given edge in the
- * Rose graph.
- */
+/**
+ * \brief Set the edge bounds and appropriate history on the given edge in the
+ * Rose graph.
+ */
+static
+void setEdgeBounds(RoseGraph &g, const RoseEdge &e, u32 min_bound,
+ u32 max_bound) {
+ assert(min_bound <= max_bound);
+ assert(max_bound <= ROSE_BOUND_INF);
+
+ g[e].minBound = min_bound;
+ g[e].maxBound = max_bound;
+
+ if (min_bound || max_bound < ROSE_BOUND_INF) {
+ g[e].history = ROSE_ROLE_HISTORY_ANCH;
+ } else {
+ g[e].history = ROSE_ROLE_HISTORY_NONE;
+ }
+}
+
static
-void setEdgeBounds(RoseGraph &g, const RoseEdge &e, u32 min_bound,
- u32 max_bound) {
- assert(min_bound <= max_bound);
- assert(max_bound <= ROSE_BOUND_INF);
-
- g[e].minBound = min_bound;
- g[e].maxBound = max_bound;
-
- if (min_bound || max_bound < ROSE_BOUND_INF) {
- g[e].history = ROSE_ROLE_HISTORY_ANCH;
- } else {
- g[e].history = ROSE_ROLE_HISTORY_NONE;
- }
-}
-
-static
bool handleStartPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
const RoseEdge &e_old, RoseVertex ar,
vector<RoseEdge> *to_delete) {
@@ -409,10 +409,10 @@ bool handleStartPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
if (source(e_old, g) == ar) {
assert(g[e_old].minBound <= bound_min);
assert(g[e_old].maxBound >= bound_max);
- setEdgeBounds(g, e_old, bound_min, bound_max);
+ setEdgeBounds(g, e_old, bound_min, bound_max);
} else {
- RoseEdge e_new = add_edge(ar, v, g);
- setEdgeBounds(g, e_new, bound_min, bound_max);
+ RoseEdge e_new = add_edge(ar, v, g);
+ setEdgeBounds(g, e_new, bound_min, bound_max);
to_delete->push_back(e_old);
}
@@ -428,8 +428,8 @@ bool handleStartDsPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
u32 repeatCount = 0;
NFAVertex hu = h.startDs;
- auto start_succ = succs<set<NFAVertex>>(h.start, h);
- auto startds_succ = succs<set<NFAVertex>>(h.startDs, h);
+ auto start_succ = succs<set<NFAVertex>>(h.start, h);
+ auto startds_succ = succs<set<NFAVertex>>(h.startDs, h);
if (!is_subset_of(start_succ, startds_succ)) {
DEBUG_PRINTF("not a simple chain\n");
@@ -464,7 +464,7 @@ bool handleStartDsPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
/* update bounds on edge */
assert(g[e].minBound <= repeatCount);
- setEdgeBounds(g, e, repeatCount, ROSE_BOUND_INF);
+ setEdgeBounds(g, e, repeatCount, ROSE_BOUND_INF);
g[v].left.reset(); /* clear the prefix info */
@@ -479,12 +479,12 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
assert(in_degree(h.acceptEod, h) == 1);
bool anchored = !proper_out_degree(h.startDs, h);
- NFAVertex key = NGHolder::null_vertex();
+ NFAVertex key = NGHolder::null_vertex();
NFAVertex base = anchored ? h.start : h.startDs;
if (!anchored) {
- auto start_succ = succs<set<NFAVertex>>(h.start, h);
- auto startds_succ = succs<set<NFAVertex>>(h.startDs, h);
+ auto start_succ = succs<set<NFAVertex>>(h.start, h);
+ auto startds_succ = succs<set<NFAVertex>>(h.startDs, h);
if (!is_subset_of(start_succ, startds_succ)) {
DEBUG_PRINTF("not a simple chain\n");
@@ -493,7 +493,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
}
for (auto w : adjacent_vertices_range(base, h)) {
- DEBUG_PRINTF("checking %zu\n", h[w].index);
+ DEBUG_PRINTF("checking %zu\n", h[w].index);
if (!h[w].char_reach.all()) {
continue;
}
@@ -528,7 +528,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
set<NFAVertex> exits_and_repeat_verts;
for (auto repeat_v : ri.vertices) {
- DEBUG_PRINTF("repeat vertex %zu\n", h[repeat_v].index);
+ DEBUG_PRINTF("repeat vertex %zu\n", h[repeat_v].index);
succ(h, repeat_v, &exits_and_repeat_verts);
exits_and_repeat_verts.insert(repeat_v);
}
@@ -543,7 +543,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
exits = exits_and_repeat_verts;
erase_all(&exits, rep_verts);
- auto base_succ = succs<set<NFAVertex>>(base, h);
+ auto base_succ = succs<set<NFAVertex>>(base, h);
base_succ.erase(h.startDs);
if (is_subset_of(base_succ, rep_verts)) {
@@ -552,7 +552,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
&& is_subset_of(exits, base_succ)
&& is_subset_of(base_succ, exits_and_repeat_verts)) {
/* we have a jump edge */
- ri.repeatMin = depth(0);
+ ri.repeatMin = depth(0);
} else {
return false;
}
@@ -562,7 +562,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
DEBUG_PRINTF("woot?\n");
shared_ptr<NGHolder> h_new = make_shared<NGHolder>();
- unordered_map<NFAVertex, NFAVertex> rhs_map;
+ unordered_map<NFAVertex, NFAVertex> rhs_map;
vector<NFAVertex> exits_vec;
insert(&exits_vec, exits_vec.end(), exits);
splitRHS(h, exits_vec, h_new.get(), &rhs_map);
@@ -601,16 +601,16 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v,
}
if (source(e_old, g) == ar) {
- setEdgeBounds(g, e_old, ri.repeatMin + width, ri.repeatMax + width);
+ setEdgeBounds(g, e_old, ri.repeatMin + width, ri.repeatMax + width);
} else {
- RoseEdge e_new = add_edge(ar, v, g);
- setEdgeBounds(g, e_new, ri.repeatMin + width, ri.repeatMax + width);
+ RoseEdge e_new = add_edge(ar, v, g);
+ setEdgeBounds(g, e_new, ri.repeatMin + width, ri.repeatMax + width);
to_delete->push_back(e_old);
}
} else {
assert(g[e_old].minBound <= ri.repeatMin + width);
- setEdgeBounds(g, e_old, ri.repeatMin + width, ROSE_BOUND_INF);
+ setEdgeBounds(g, e_old, ri.repeatMin + width, ROSE_BOUND_INF);
}
g[v].left.dfa.reset();
@@ -655,7 +655,7 @@ void convertPrefixToBounds(RoseBuildImpl &tbi) {
continue;
}
- DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index);
+ DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index);
if (!proper_out_degree(h.startDs, h)) {
if (handleStartPrefixCliche(h, g, v, e, ar, &to_delete)) {
@@ -701,7 +701,7 @@ void convertPrefixToBounds(RoseBuildImpl &tbi) {
continue;
}
- DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index);
+ DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index);
if (!proper_out_degree(h.startDs, h)) {
if (handleStartPrefixCliche(h, g, v, e, ar, &to_delete)) {
@@ -736,7 +736,7 @@ void convertAnchPrefixToBounds(RoseBuildImpl &tbi) {
continue;
}
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
// This pass runs after makeCastles, so we use the fact that bounded
// repeat detection has already been done for us.
@@ -794,23 +794,23 @@ void convertAnchPrefixToBounds(RoseBuildImpl &tbi) {
const PureRepeat &pr = castle.repeats.begin()->second;
DEBUG_PRINTF("castle has repeat %s\n", pr.bounds.str().c_str());
- DEBUG_PRINTF("delay adj %u\n", (u32)delay_adj);
+ DEBUG_PRINTF("delay adj %u\n", (u32)delay_adj);
+
+ if (delay_adj >= pr.bounds.max) {
+ DEBUG_PRINTF("delay adj too large\n");
+ continue;
+ }
- if (delay_adj >= pr.bounds.max) {
- DEBUG_PRINTF("delay adj too large\n");
- continue;
- }
-
DepthMinMax bounds(pr.bounds); // copy
if (delay_adj > bounds.min) {
- bounds.min = depth(0);
- } else {
- bounds.min -= delay_adj;
+ bounds.min = depth(0);
+ } else {
+ bounds.min -= delay_adj;
}
bounds.max -= delay_adj;
- setEdgeBounds(g, e, bounds.min, bounds.max.is_finite()
- ? (u32)bounds.max
- : ROSE_BOUND_INF);
+ setEdgeBounds(g, e, bounds.min, bounds.max.is_finite()
+ ? (u32)bounds.max
+ : ROSE_BOUND_INF);
g[v].left.reset();
}
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_convert.h b/contrib/libs/hyperscan/src/rose/rose_build_convert.h
index 413cbeae19f..7307c213ca4 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_convert.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_convert.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_dedupe.cpp b/contrib/libs/hyperscan/src/rose/rose_build_dedupe.cpp
index a159bb67b37..d5d002d43b3 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_dedupe.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_dedupe.cpp
@@ -1,393 +1,393 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_impl.h"
-#include "nfa/castlecompile.h"
-#include "nfagraph/ng_repeat.h"
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_impl.h"
+#include "nfa/castlecompile.h"
+#include "nfagraph/ng_repeat.h"
#include "smallwrite/smallwrite_build.h"
-#include "util/compile_context.h"
-#include "util/boundary_reports.h"
-#include "util/make_unique.h"
-#include "util/report_manager.h"
-
-using namespace std;
-
-namespace ue2 {
-
-static
-bool requiresDedupe(const NGHolder &h, const flat_set<ReportID> &reports,
- const Grey &grey) {
- /* TODO: tighten */
- NFAVertex seen_vert = NGHolder::null_vertex();
-
- for (auto v : inv_adjacent_vertices_range(h.accept, h)) {
- if (has_intersection(h[v].reports, reports)) {
- if (seen_vert != NGHolder::null_vertex()) {
- return true;
- }
- seen_vert = v;
- }
- }
-
- for (auto v : inv_adjacent_vertices_range(h.acceptEod, h)) {
- if (has_intersection(h[v].reports, reports)) {
- if (seen_vert != NGHolder::null_vertex()) {
- return true;
- }
- seen_vert = v;
- }
- }
-
- if (seen_vert) {
- /* if the reporting vertex is part of of a terminal repeat, the
- * construction process may reform the graph splitting it into two
- * vertices (pos, cyclic) and hence require dedupe */
- vector<GraphRepeatInfo> repeats;
- findRepeats(h, grey.minExtBoundedRepeatSize, &repeats);
- for (const auto &repeat : repeats) {
- if (find(repeat.vertices.begin(), repeat.vertices.end(),
- seen_vert) != repeat.vertices.end()) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-class RoseDedupeAuxImpl : public RoseDedupeAux {
-public:
- explicit RoseDedupeAuxImpl(const RoseBuildImpl &build_in);
- bool requiresDedupeSupport(
- const flat_set<ReportID> &reports) const override;
-
-private:
- bool hasSafeMultiReports(const flat_set<ReportID> &reports) const;
-
- const RoseBuildImpl &build;
- map<ReportID, set<RoseVertex>> vert_map; //!< ordinary literals
- map<ReportID, set<RoseVertex>> sb_vert_map; //!< small block literals
- map<ReportID, set<suffix_id>> suffix_map;
- map<ReportID, set<const OutfixInfo *>> outfix_map;
- map<ReportID, set<const raw_puff *>> puff_map;
-
- unordered_set<ReportID> live_reports; //!< all live internal reports.
-};
-
-unique_ptr<RoseDedupeAux> RoseBuildImpl::generateDedupeAux() const {
- return ue2::make_unique<RoseDedupeAuxImpl>(*this);
-}
-
-RoseDedupeAux::~RoseDedupeAux() = default;
-
-RoseDedupeAuxImpl::RoseDedupeAuxImpl(const RoseBuildImpl &build_in)
- : build(build_in) {
- const RoseGraph &g = build.g;
-
- set<suffix_id> suffixes;
-
- for (auto v : vertices_range(g)) {
- insert(&live_reports, g[v].reports);
-
- // Literals in the small block table are "shadow" copies of literals in
- // the other tables that do not run in the same runtime invocation.
- // Dedupe key assignment will be taken care of by the real literals.
- if (build.hasLiteralInTable(v, ROSE_ANCHORED_SMALL_BLOCK)) {
- for (const auto &report_id : g[v].reports) {
- sb_vert_map[report_id].insert(v);
- }
- } else {
- for (const auto &report_id : g[v].reports) {
- vert_map[report_id].insert(v);
- }
- }
-
- // Several vertices may share a suffix, so we collect the set of
- // suffixes first to avoid repeating work.
- if (g[v].suffix) {
- suffixes.insert(g[v].suffix);
- }
- }
-
- for (const auto &suffix : suffixes) {
- for (const auto &report_id : all_reports(suffix)) {
- suffix_map[report_id].insert(suffix);
- live_reports.insert(report_id);
- }
- }
-
- for (const auto &outfix : build.outfixes) {
- for (const auto &report_id : all_reports(outfix)) {
- outfix_map[report_id].insert(&outfix);
- live_reports.insert(report_id);
- }
- }
-
- if (build.mpv_outfix) {
- auto *mpv = build.mpv_outfix->mpv();
- for (const auto &puff : mpv->puffettes) {
- puff_map[puff.report].insert(&puff);
- live_reports.insert(puff.report);
- }
- for (const auto &puff : mpv->triggered_puffettes) {
- puff_map[puff.report].insert(&puff);
- live_reports.insert(puff.report);
- }
- }
-
+#include "util/compile_context.h"
+#include "util/boundary_reports.h"
+#include "util/make_unique.h"
+#include "util/report_manager.h"
+
+using namespace std;
+
+namespace ue2 {
+
+static
+bool requiresDedupe(const NGHolder &h, const flat_set<ReportID> &reports,
+ const Grey &grey) {
+ /* TODO: tighten */
+ NFAVertex seen_vert = NGHolder::null_vertex();
+
+ for (auto v : inv_adjacent_vertices_range(h.accept, h)) {
+ if (has_intersection(h[v].reports, reports)) {
+ if (seen_vert != NGHolder::null_vertex()) {
+ return true;
+ }
+ seen_vert = v;
+ }
+ }
+
+ for (auto v : inv_adjacent_vertices_range(h.acceptEod, h)) {
+ if (has_intersection(h[v].reports, reports)) {
+ if (seen_vert != NGHolder::null_vertex()) {
+ return true;
+ }
+ seen_vert = v;
+ }
+ }
+
+ if (seen_vert) {
+ /* if the reporting vertex is part of of a terminal repeat, the
+ * construction process may reform the graph splitting it into two
+ * vertices (pos, cyclic) and hence require dedupe */
+ vector<GraphRepeatInfo> repeats;
+ findRepeats(h, grey.minExtBoundedRepeatSize, &repeats);
+ for (const auto &repeat : repeats) {
+ if (find(repeat.vertices.begin(), repeat.vertices.end(),
+ seen_vert) != repeat.vertices.end()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+class RoseDedupeAuxImpl : public RoseDedupeAux {
+public:
+ explicit RoseDedupeAuxImpl(const RoseBuildImpl &build_in);
+ bool requiresDedupeSupport(
+ const flat_set<ReportID> &reports) const override;
+
+private:
+ bool hasSafeMultiReports(const flat_set<ReportID> &reports) const;
+
+ const RoseBuildImpl &build;
+ map<ReportID, set<RoseVertex>> vert_map; //!< ordinary literals
+ map<ReportID, set<RoseVertex>> sb_vert_map; //!< small block literals
+ map<ReportID, set<suffix_id>> suffix_map;
+ map<ReportID, set<const OutfixInfo *>> outfix_map;
+ map<ReportID, set<const raw_puff *>> puff_map;
+
+ unordered_set<ReportID> live_reports; //!< all live internal reports.
+};
+
+unique_ptr<RoseDedupeAux> RoseBuildImpl::generateDedupeAux() const {
+ return ue2::make_unique<RoseDedupeAuxImpl>(*this);
+}
+
+RoseDedupeAux::~RoseDedupeAux() = default;
+
+RoseDedupeAuxImpl::RoseDedupeAuxImpl(const RoseBuildImpl &build_in)
+ : build(build_in) {
+ const RoseGraph &g = build.g;
+
+ set<suffix_id> suffixes;
+
+ for (auto v : vertices_range(g)) {
+ insert(&live_reports, g[v].reports);
+
+ // Literals in the small block table are "shadow" copies of literals in
+ // the other tables that do not run in the same runtime invocation.
+ // Dedupe key assignment will be taken care of by the real literals.
+ if (build.hasLiteralInTable(v, ROSE_ANCHORED_SMALL_BLOCK)) {
+ for (const auto &report_id : g[v].reports) {
+ sb_vert_map[report_id].insert(v);
+ }
+ } else {
+ for (const auto &report_id : g[v].reports) {
+ vert_map[report_id].insert(v);
+ }
+ }
+
+ // Several vertices may share a suffix, so we collect the set of
+ // suffixes first to avoid repeating work.
+ if (g[v].suffix) {
+ suffixes.insert(g[v].suffix);
+ }
+ }
+
+ for (const auto &suffix : suffixes) {
+ for (const auto &report_id : all_reports(suffix)) {
+ suffix_map[report_id].insert(suffix);
+ live_reports.insert(report_id);
+ }
+ }
+
+ for (const auto &outfix : build.outfixes) {
+ for (const auto &report_id : all_reports(outfix)) {
+ outfix_map[report_id].insert(&outfix);
+ live_reports.insert(report_id);
+ }
+ }
+
+ if (build.mpv_outfix) {
+ auto *mpv = build.mpv_outfix->mpv();
+ for (const auto &puff : mpv->puffettes) {
+ puff_map[puff.report].insert(&puff);
+ live_reports.insert(puff.report);
+ }
+ for (const auto &puff : mpv->triggered_puffettes) {
+ puff_map[puff.report].insert(&puff);
+ live_reports.insert(puff.report);
+ }
+ }
+
for (const auto &report_id : build.smwr.all_reports()) {
live_reports.insert(report_id);
}
- // Collect live reports from boundary reports.
- insert(&live_reports, build.boundary.report_at_0);
- insert(&live_reports, build.boundary.report_at_0_eod);
- insert(&live_reports, build.boundary.report_at_eod);
-
- DEBUG_PRINTF("%zu of %zu reports are live\n", live_reports.size(),
- build.rm.numReports());
-}
-
-static
-vector<CharReach> makePath(const rose_literal_id &lit) {
- vector<CharReach> path(begin(lit.s), end(lit.s));
- for (u32 i = 0; i < lit.delay; i++) {
- path.push_back(CharReach::dot());
- }
- return path;
-}
-
-/**
- * \brief True if one of the given literals overlaps with the suffix of
- * another, meaning that they could arrive at the same offset.
- */
-static
-bool literalsCouldRace(const rose_literal_id &lit1,
- const rose_literal_id &lit2) {
- DEBUG_PRINTF("compare %s (delay %u) and %s (delay %u)\n",
- dumpString(lit1.s).c_str(), lit1.delay,
- dumpString(lit2.s).c_str(), lit2.delay);
-
- // Add dots on the end of each literal for delay.
- const auto v1 = makePath(lit1);
- const auto v2 = makePath(lit2);
-
- // See if the smaller path is a suffix of the larger path.
- const auto *smaller = v1.size() < v2.size() ? &v1 : &v2;
- const auto *bigger = v1.size() < v2.size() ? &v2 : &v1;
- auto r = mismatch(smaller->rbegin(), smaller->rend(), bigger->rbegin(),
- overlaps);
- return r.first == smaller->rend();
-}
-
-bool RoseDedupeAuxImpl::hasSafeMultiReports(
- const flat_set<ReportID> &reports) const {
- if (reports.size() <= 1) {
- return true;
- }
-
- /* We have more than one ReportID corresponding to the external ID that is
- * presented to the user. These may differ in offset adjustment, bounds
- * checks, etc. */
-
- /* TODO: work out if these differences will actually cause problems */
-
- /* One common case where we know we don't have a problem is if there are
- * precisely two reports, one for the main Rose path and one for the
- * "small block matcher" path. */
- if (reports.size() == 2) {
- ReportID id1 = *reports.begin();
- ReportID id2 = *reports.rbegin();
-
- bool has_verts_1 = contains(vert_map, id1);
- bool has_verts_2 = contains(vert_map, id2);
- bool has_sb_verts_1 = contains(sb_vert_map, id1);
- bool has_sb_verts_2 = contains(sb_vert_map, id2);
-
- if (has_verts_1 != has_verts_2 && has_sb_verts_1 != has_sb_verts_2) {
- DEBUG_PRINTF("two reports, one full and one small block: ok\n");
- return true;
- }
- }
-
- DEBUG_PRINTF("more than one report\n");
- return false;
-}
-
-bool RoseDedupeAuxImpl::requiresDedupeSupport(
- const flat_set<ReportID> &reports_in) const {
- /* TODO: this could be expanded to check for offset or character
- constraints */
-
- // We don't want to consider dead reports (tracked by ReportManager but no
- // longer used) for the purposes of assigning dupe keys.
- flat_set<ReportID> reports;
- for (auto id : reports_in) {
- if (contains(live_reports, id)) {
- reports.insert(id);
- }
- }
-
- DEBUG_PRINTF("live reports: %s\n", as_string_list(reports).c_str());
-
- const RoseGraph &g = build.g;
-
- bool has_suffix = false;
- bool has_outfix = false;
-
- if (!hasSafeMultiReports(reports)) {
- DEBUG_PRINTF("multiple reports not safe\n");
- return true;
- }
-
- set<RoseVertex> roles;
- set<suffix_id> suffixes;
- set<const OutfixInfo *> outfixes;
- set<const raw_puff *> puffettes;
- for (ReportID r : reports) {
- if (contains(vert_map, r)) {
- insert(&roles, vert_map.at(r));
- }
- if (contains(suffix_map, r)) {
- insert(&suffixes, suffix_map.at(r));
- }
-
- if (contains(outfix_map, r)) {
- insert(&outfixes, outfix_map.at(r));
- }
-
- if (contains(puff_map, r)) {
- insert(&puffettes, puff_map.at(r));
- }
- }
-
- /* roles */
-
- map<u32, u32> lits; // Literal ID -> count of occurrences.
-
- const bool has_role = !roles.empty();
- for (auto v : roles) {
- for (const auto &lit : g[v].literals) {
- lits[lit]++;
- }
- if (g[v].eod_accept) {
- // Literals plugged into this EOD accept must be taken into account
- // as well.
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- for (const auto &lit : g[u].literals) {
- lits[lit]++;
- }
- }
- }
- }
-
- /* literals */
-
- for (const auto &m : lits) {
- if (m.second > 1) {
- DEBUG_PRINTF("lit %u used by >1 reporting roles\n", m.first);
- return true;
- }
- }
-
- for (auto it = begin(lits); it != end(lits); ++it) {
- const auto &lit1 = build.literals.at(it->first);
- for (auto jt = next(it); jt != end(lits); ++jt) {
- const auto &lit2 = build.literals.at(jt->first);
- if (literalsCouldRace(lit1, lit2)) {
- DEBUG_PRINTF("literals could race\n");
- return true;
- }
- }
- }
-
- /* suffixes */
-
- for (const auto &suffix : suffixes) {
- if (has_suffix || has_role) {
- return true; /* scope for badness */
- }
-
- has_suffix = true;
-
- /* some lesser suffix engines (nfas, haig, castle) can raise multiple
- * matches for a report id at the same offset if there are multiple
- * report states live. */
- if (suffix.haig()) {
- return true;
- }
- if (suffix.graph() &&
- requiresDedupe(*suffix.graph(), reports, build.cc.grey)) {
- return true;
- }
- if (suffix.castle() && requiresDedupe(*suffix.castle(), reports)) {
- return true;
- }
- }
-
- /* outfixes */
-
- for (const auto &outfix_ptr : outfixes) {
- assert(outfix_ptr);
- const OutfixInfo &out = *outfix_ptr;
-
- if (has_outfix || has_role || has_suffix) {
- return true;
- }
- has_outfix = true;
-
- if (out.haig()) {
- return true; /* haig may report matches with different SOM at the
- same offset */
- }
-
- if (out.holder() &&
- requiresDedupe(*out.holder(), reports, build.cc.grey)) {
- return true;
- }
- }
-
- /* mpv */
- for (UNUSED const auto &puff : puffettes) {
- if (has_outfix || has_role || has_suffix) {
- return true;
- }
- has_outfix = true;
- }
-
- /* boundary */
- if (has_intersection(build.boundary.report_at_eod, reports)) {
- if (has_outfix || has_role || has_suffix) {
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace ue2
+ // Collect live reports from boundary reports.
+ insert(&live_reports, build.boundary.report_at_0);
+ insert(&live_reports, build.boundary.report_at_0_eod);
+ insert(&live_reports, build.boundary.report_at_eod);
+
+ DEBUG_PRINTF("%zu of %zu reports are live\n", live_reports.size(),
+ build.rm.numReports());
+}
+
+static
+vector<CharReach> makePath(const rose_literal_id &lit) {
+ vector<CharReach> path(begin(lit.s), end(lit.s));
+ for (u32 i = 0; i < lit.delay; i++) {
+ path.push_back(CharReach::dot());
+ }
+ return path;
+}
+
+/**
+ * \brief True if one of the given literals overlaps with the suffix of
+ * another, meaning that they could arrive at the same offset.
+ */
+static
+bool literalsCouldRace(const rose_literal_id &lit1,
+ const rose_literal_id &lit2) {
+ DEBUG_PRINTF("compare %s (delay %u) and %s (delay %u)\n",
+ dumpString(lit1.s).c_str(), lit1.delay,
+ dumpString(lit2.s).c_str(), lit2.delay);
+
+ // Add dots on the end of each literal for delay.
+ const auto v1 = makePath(lit1);
+ const auto v2 = makePath(lit2);
+
+ // See if the smaller path is a suffix of the larger path.
+ const auto *smaller = v1.size() < v2.size() ? &v1 : &v2;
+ const auto *bigger = v1.size() < v2.size() ? &v2 : &v1;
+ auto r = mismatch(smaller->rbegin(), smaller->rend(), bigger->rbegin(),
+ overlaps);
+ return r.first == smaller->rend();
+}
+
+bool RoseDedupeAuxImpl::hasSafeMultiReports(
+ const flat_set<ReportID> &reports) const {
+ if (reports.size() <= 1) {
+ return true;
+ }
+
+ /* We have more than one ReportID corresponding to the external ID that is
+ * presented to the user. These may differ in offset adjustment, bounds
+ * checks, etc. */
+
+ /* TODO: work out if these differences will actually cause problems */
+
+ /* One common case where we know we don't have a problem is if there are
+ * precisely two reports, one for the main Rose path and one for the
+ * "small block matcher" path. */
+ if (reports.size() == 2) {
+ ReportID id1 = *reports.begin();
+ ReportID id2 = *reports.rbegin();
+
+ bool has_verts_1 = contains(vert_map, id1);
+ bool has_verts_2 = contains(vert_map, id2);
+ bool has_sb_verts_1 = contains(sb_vert_map, id1);
+ bool has_sb_verts_2 = contains(sb_vert_map, id2);
+
+ if (has_verts_1 != has_verts_2 && has_sb_verts_1 != has_sb_verts_2) {
+ DEBUG_PRINTF("two reports, one full and one small block: ok\n");
+ return true;
+ }
+ }
+
+ DEBUG_PRINTF("more than one report\n");
+ return false;
+}
+
+bool RoseDedupeAuxImpl::requiresDedupeSupport(
+ const flat_set<ReportID> &reports_in) const {
+ /* TODO: this could be expanded to check for offset or character
+ constraints */
+
+ // We don't want to consider dead reports (tracked by ReportManager but no
+ // longer used) for the purposes of assigning dupe keys.
+ flat_set<ReportID> reports;
+ for (auto id : reports_in) {
+ if (contains(live_reports, id)) {
+ reports.insert(id);
+ }
+ }
+
+ DEBUG_PRINTF("live reports: %s\n", as_string_list(reports).c_str());
+
+ const RoseGraph &g = build.g;
+
+ bool has_suffix = false;
+ bool has_outfix = false;
+
+ if (!hasSafeMultiReports(reports)) {
+ DEBUG_PRINTF("multiple reports not safe\n");
+ return true;
+ }
+
+ set<RoseVertex> roles;
+ set<suffix_id> suffixes;
+ set<const OutfixInfo *> outfixes;
+ set<const raw_puff *> puffettes;
+ for (ReportID r : reports) {
+ if (contains(vert_map, r)) {
+ insert(&roles, vert_map.at(r));
+ }
+ if (contains(suffix_map, r)) {
+ insert(&suffixes, suffix_map.at(r));
+ }
+
+ if (contains(outfix_map, r)) {
+ insert(&outfixes, outfix_map.at(r));
+ }
+
+ if (contains(puff_map, r)) {
+ insert(&puffettes, puff_map.at(r));
+ }
+ }
+
+ /* roles */
+
+ map<u32, u32> lits; // Literal ID -> count of occurrences.
+
+ const bool has_role = !roles.empty();
+ for (auto v : roles) {
+ for (const auto &lit : g[v].literals) {
+ lits[lit]++;
+ }
+ if (g[v].eod_accept) {
+ // Literals plugged into this EOD accept must be taken into account
+ // as well.
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ for (const auto &lit : g[u].literals) {
+ lits[lit]++;
+ }
+ }
+ }
+ }
+
+ /* literals */
+
+ for (const auto &m : lits) {
+ if (m.second > 1) {
+ DEBUG_PRINTF("lit %u used by >1 reporting roles\n", m.first);
+ return true;
+ }
+ }
+
+ for (auto it = begin(lits); it != end(lits); ++it) {
+ const auto &lit1 = build.literals.at(it->first);
+ for (auto jt = next(it); jt != end(lits); ++jt) {
+ const auto &lit2 = build.literals.at(jt->first);
+ if (literalsCouldRace(lit1, lit2)) {
+ DEBUG_PRINTF("literals could race\n");
+ return true;
+ }
+ }
+ }
+
+ /* suffixes */
+
+ for (const auto &suffix : suffixes) {
+ if (has_suffix || has_role) {
+ return true; /* scope for badness */
+ }
+
+ has_suffix = true;
+
+ /* some lesser suffix engines (nfas, haig, castle) can raise multiple
+ * matches for a report id at the same offset if there are multiple
+ * report states live. */
+ if (suffix.haig()) {
+ return true;
+ }
+ if (suffix.graph() &&
+ requiresDedupe(*suffix.graph(), reports, build.cc.grey)) {
+ return true;
+ }
+ if (suffix.castle() && requiresDedupe(*suffix.castle(), reports)) {
+ return true;
+ }
+ }
+
+ /* outfixes */
+
+ for (const auto &outfix_ptr : outfixes) {
+ assert(outfix_ptr);
+ const OutfixInfo &out = *outfix_ptr;
+
+ if (has_outfix || has_role || has_suffix) {
+ return true;
+ }
+ has_outfix = true;
+
+ if (out.haig()) {
+ return true; /* haig may report matches with different SOM at the
+ same offset */
+ }
+
+ if (out.holder() &&
+ requiresDedupe(*out.holder(), reports, build.cc.grey)) {
+ return true;
+ }
+ }
+
+ /* mpv */
+ for (UNUSED const auto &puff : puffettes) {
+ if (has_outfix || has_role || has_suffix) {
+ return true;
+ }
+ has_outfix = true;
+ }
+
+ /* boundary */
+ if (has_intersection(build.boundary.report_at_eod, reports)) {
+ if (has_outfix || has_role || has_suffix) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_dump.h b/contrib/libs/hyperscan/src/rose/rose_build_dump.h
index 0c92a23cc34..d4c620a3e62 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_dump.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_dump.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,53 +29,53 @@
#ifndef ROSE_BUILD_DUMP_H
#define ROSE_BUILD_DUMP_H
-#include "ue2common.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
+#include "ue2common.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
struct RoseEngine;
namespace ue2 {
-class RoseBuildImpl;
+class RoseBuildImpl;
struct Grey;
-struct hwlmLiteral;
-struct LitFragment;
-struct left_id;
-struct suffix_id;
+struct hwlmLiteral;
+struct LitFragment;
+struct left_id;
+struct suffix_id;
#ifdef DUMP_SUPPORT
// Dump the Rose graph in graphviz representation.
-void dumpRoseGraph(const RoseBuildImpl &build, const char *filename);
-
-void dumpRose(const RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments,
- const std::map<left_id, u32> &leftfix_queue_map,
- const std::map<suffix_id, u32> &suffix_queue_map,
- const RoseEngine *t);
-
-void dumpMatcherLiterals(const std::vector<hwlmLiteral> &lits,
- const std::string &name, const Grey &grey);
-
+void dumpRoseGraph(const RoseBuildImpl &build, const char *filename);
+
+void dumpRose(const RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments,
+ const std::map<left_id, u32> &leftfix_queue_map,
+ const std::map<suffix_id, u32> &suffix_queue_map,
+ const RoseEngine *t);
+
+void dumpMatcherLiterals(const std::vector<hwlmLiteral> &lits,
+ const std::string &name, const Grey &grey);
+
#else
static UNUSED
-void dumpRoseGraph(const RoseBuildImpl &, const char *) {
+void dumpRoseGraph(const RoseBuildImpl &, const char *) {
+}
+
+static UNUSED
+void dumpRose(const RoseBuildImpl &, const std::vector<LitFragment> &,
+ const std::map<left_id, u32> &, const std::map<suffix_id, u32> &,
+ const RoseEngine *) {
}
static UNUSED
-void dumpRose(const RoseBuildImpl &, const std::vector<LitFragment> &,
- const std::map<left_id, u32> &, const std::map<suffix_id, u32> &,
- const RoseEngine *) {
+void dumpMatcherLiterals(const std::vector<hwlmLiteral> &, const std::string &,
+ const Grey &) {
}
-static UNUSED
-void dumpMatcherLiterals(const std::vector<hwlmLiteral> &, const std::string &,
- const Grey &) {
-}
-
#endif
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.cpp b/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.cpp
index dc924183757..d39572070fb 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.cpp
@@ -1,117 +1,117 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_engine_blob.h"
-
-#include "rose_build_lookaround.h"
-#include "util/charreach_util.h"
-
-using namespace std;
-
-namespace ue2 {
-
-u32 lookaround_info::get_offset_of(const vector<vector<CharReach>> &reaches,
- RoseEngineBlob &blob) {
- assert(reaches.size() != 1);
-
- // Check the cache.
- auto it = multi_cache.find(reaches);
- if (it != multi_cache.end()) {
- DEBUG_PRINTF("reusing reach at idx %u\n", it->second);
- return it->second;
- }
-
- vector<u8> raw_reach(reaches.size() * MULTI_REACH_BITVECTOR_LEN);
- size_t off = 0;
- for (const auto &m : reaches) {
- u8 u = 0;
- assert(m.size() == MAX_LOOKAROUND_PATHS);
- for (size_t i = 0; i < m.size(); i++) {
- if (m[i].none()) {
- u |= (u8)1U << i;
- }
- }
- fill_n(raw_reach.data() + off, MULTI_REACH_BITVECTOR_LEN, u);
-
- for (size_t i = 0; i < m.size(); i++) {
- const CharReach &cr = m[i];
- if (cr.none()) {
- continue;
- }
-
- for (size_t c = cr.find_first(); c != cr.npos;
- c = cr.find_next(c)) {
- raw_reach[c + off] |= (u8)1U << i;
- }
- }
-
- off += MULTI_REACH_BITVECTOR_LEN;
- }
-
- u32 reach_idx = blob.add_range(raw_reach);
- DEBUG_PRINTF("adding reach at idx %u\n", reach_idx);
- multi_cache.emplace(reaches, reach_idx);
-
- return reach_idx;
-}
-
-u32 lookaround_info::get_offset_of(const vector<CharReach> &reach,
- RoseEngineBlob &blob) {
- if (contains(rcache, reach)) {
- u32 offset = rcache[reach];
- DEBUG_PRINTF("reusing reach at idx %u\n", offset);
- return offset;
- }
-
- vector<u8> raw_reach(reach.size() * REACH_BITVECTOR_LEN);
- size_t off = 0;
- for (const auto &cr : reach) {
- assert(cr.any()); // Should be at least one character!
- fill_bitvector(cr, raw_reach.data() + off);
- off += REACH_BITVECTOR_LEN;
- }
-
- u32 offset = blob.add_range(raw_reach);
- rcache.emplace(reach, offset);
- return offset;
-}
-
-u32 lookaround_info::get_offset_of(const vector<s8> &look,
- RoseEngineBlob &blob) {
- if (contains(lcache, look)) {
- u32 offset = lcache[look];
- DEBUG_PRINTF("reusing look at idx %u\n", offset);
- return offset;
- }
-
- u32 offset = blob.add_range(look);
- lcache.emplace(look, offset);
- return offset;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_engine_blob.h"
+
+#include "rose_build_lookaround.h"
+#include "util/charreach_util.h"
+
+using namespace std;
+
+namespace ue2 {
+
+u32 lookaround_info::get_offset_of(const vector<vector<CharReach>> &reaches,
+ RoseEngineBlob &blob) {
+ assert(reaches.size() != 1);
+
+ // Check the cache.
+ auto it = multi_cache.find(reaches);
+ if (it != multi_cache.end()) {
+ DEBUG_PRINTF("reusing reach at idx %u\n", it->second);
+ return it->second;
+ }
+
+ vector<u8> raw_reach(reaches.size() * MULTI_REACH_BITVECTOR_LEN);
+ size_t off = 0;
+ for (const auto &m : reaches) {
+ u8 u = 0;
+ assert(m.size() == MAX_LOOKAROUND_PATHS);
+ for (size_t i = 0; i < m.size(); i++) {
+ if (m[i].none()) {
+ u |= (u8)1U << i;
+ }
+ }
+ fill_n(raw_reach.data() + off, MULTI_REACH_BITVECTOR_LEN, u);
+
+ for (size_t i = 0; i < m.size(); i++) {
+ const CharReach &cr = m[i];
+ if (cr.none()) {
+ continue;
+ }
+
+ for (size_t c = cr.find_first(); c != cr.npos;
+ c = cr.find_next(c)) {
+ raw_reach[c + off] |= (u8)1U << i;
+ }
+ }
+
+ off += MULTI_REACH_BITVECTOR_LEN;
+ }
+
+ u32 reach_idx = blob.add_range(raw_reach);
+ DEBUG_PRINTF("adding reach at idx %u\n", reach_idx);
+ multi_cache.emplace(reaches, reach_idx);
+
+ return reach_idx;
+}
+
+u32 lookaround_info::get_offset_of(const vector<CharReach> &reach,
+ RoseEngineBlob &blob) {
+ if (contains(rcache, reach)) {
+ u32 offset = rcache[reach];
+ DEBUG_PRINTF("reusing reach at idx %u\n", offset);
+ return offset;
+ }
+
+ vector<u8> raw_reach(reach.size() * REACH_BITVECTOR_LEN);
+ size_t off = 0;
+ for (const auto &cr : reach) {
+ assert(cr.any()); // Should be at least one character!
+ fill_bitvector(cr, raw_reach.data() + off);
+ off += REACH_BITVECTOR_LEN;
+ }
+
+ u32 offset = blob.add_range(raw_reach);
+ rcache.emplace(reach, offset);
+ return offset;
+}
+
+u32 lookaround_info::get_offset_of(const vector<s8> &look,
+ RoseEngineBlob &blob) {
+ if (contains(lcache, look)) {
+ u32 offset = lcache[look];
+ DEBUG_PRINTF("reusing look at idx %u\n", offset);
+ return offset;
+ }
+
+ u32 offset = blob.add_range(look);
+ lcache.emplace(look, offset);
+ return offset;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.h b/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.h
index a7707852a73..da4e355de20 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_engine_blob.h
@@ -1,176 +1,176 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_ENGINE_BLOB_H
-#define ROSE_BUILD_ENGINE_BLOB_H
-
-#include "rose_internal.h"
-
-#include "ue2common.h"
-#include "util/alloc.h"
-#include "util/bytecode_ptr.h"
-#include "util/charreach.h"
-#include "util/container.h"
-#include "util/hash.h"
-#include "util/multibit_build.h"
-#include "util/noncopyable.h"
-#include "util/verify_types.h"
-#include "util/unordered.h"
-
-#include <type_traits>
-#include <vector>
-
-namespace ue2 {
-
-class RoseEngineBlob;
-
-struct lookaround_info : noncopyable {
- u32 get_offset_of(const std::vector<std::vector<CharReach>> &look,
- RoseEngineBlob &blob);
- u32 get_offset_of(const std::vector<CharReach> &reach,
- RoseEngineBlob &blob);
- u32 get_offset_of(const std::vector<s8> &look, RoseEngineBlob &blob);
-
-private:
- using Path = std::vector<CharReach>;
- ue2_unordered_map<std::vector<Path>, u32> multi_cache;
- ue2_unordered_map<std::vector<s8>, u32> lcache;
- ue2_unordered_map<Path, u32> rcache;
-};
-
-class RoseEngineBlob : noncopyable {
-public:
- /** \brief Base offset of engine_blob in the Rose engine bytecode. */
- static constexpr u32 base_offset = ROUNDUP_CL(sizeof(RoseEngine));
-
- bool empty() const {
- return blob.empty();
- }
-
- size_t size() const {
- return blob.size();
- }
-
- u32 add(const void *a, const size_t len, const size_t align) {
- pad(align);
-
- size_t rv = base_offset + blob.size();
- assert(rv >= base_offset);
- DEBUG_PRINTF("write %zu bytes at offset %zu\n", len, rv);
-
- assert(ISALIGNED_N(blob.size(), align));
-
- blob.resize(blob.size() + len);
- memcpy(&blob.back() - len + 1, a, len);
-
- return verify_u32(rv);
- }
-
- template<typename T>
- u32 add(const bytecode_ptr<T> &a) {
- return add(a.get(), a.size(), a.align());
- }
-
- template<typename T>
- u32 add(const T &a) {
- static_assert(std::is_pod<T>::value, "should be pod");
- return add(&a, sizeof(a), alignof(T));
- }
-
- template<typename T>
- u32 add(const T &a, const size_t len) {
- static_assert(std::is_pod<T>::value, "should be pod");
- return add(&a, len, alignof(T));
- }
-
- template<typename Iter>
- u32 add(Iter b, const Iter &e) {
- using value_type = typename std::iterator_traits<Iter>::value_type;
- static_assert(std::is_pod<value_type>::value, "should be pod");
-
- if (b == e) {
- return 0;
- }
-
- u32 offset = add(*b);
- for (++b; b != e; ++b) {
- add(*b);
- }
-
- return offset;
- }
-
- template<typename Range>
- u32 add_range(const Range &range) {
- return add(begin(range), end(range));
- }
-
- u32 add_iterator(const std::vector<mmbit_sparse_iter> &iter) {
- auto cache_it = cached_iters.find(iter);
- if (cache_it != cached_iters.end()) {
- u32 offset = cache_it->second;
- DEBUG_PRINTF("cache hit for iter at %u\n", offset);
- return offset;
- }
-
- u32 offset = add(iter.begin(), iter.end());
- cached_iters.emplace(iter, offset);
- return offset;
- }
-
- void write_bytes(RoseEngine *engine) {
- copy_bytes((char *)engine + base_offset, blob);
- }
-
- lookaround_info lookaround_cache;
-
-private:
- void pad(size_t align) {
- assert(ISALIGNED_N(base_offset, align));
- size_t s = blob.size();
-
- if (ISALIGNED_N(s, align)) {
- return;
- }
-
- blob.resize(s + align - s % align);
- }
-
- /** \brief Cache of previously-written sparse iterators. */
- ue2_unordered_map<std::vector<mmbit_sparse_iter>, u32> cached_iters;
-
- /**
- * \brief Contents of the Rose bytecode immediately following the
- * RoseEngine.
- */
- std::vector<char, AlignedAllocator<char, 64>> blob;
-};
-
-} // namespace ue2
-
-#endif // ROSE_BUILD_ENGINE_BLOB_H
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_ENGINE_BLOB_H
+#define ROSE_BUILD_ENGINE_BLOB_H
+
+#include "rose_internal.h"
+
+#include "ue2common.h"
+#include "util/alloc.h"
+#include "util/bytecode_ptr.h"
+#include "util/charreach.h"
+#include "util/container.h"
+#include "util/hash.h"
+#include "util/multibit_build.h"
+#include "util/noncopyable.h"
+#include "util/verify_types.h"
+#include "util/unordered.h"
+
+#include <type_traits>
+#include <vector>
+
+namespace ue2 {
+
+class RoseEngineBlob;
+
+struct lookaround_info : noncopyable {
+ u32 get_offset_of(const std::vector<std::vector<CharReach>> &look,
+ RoseEngineBlob &blob);
+ u32 get_offset_of(const std::vector<CharReach> &reach,
+ RoseEngineBlob &blob);
+ u32 get_offset_of(const std::vector<s8> &look, RoseEngineBlob &blob);
+
+private:
+ using Path = std::vector<CharReach>;
+ ue2_unordered_map<std::vector<Path>, u32> multi_cache;
+ ue2_unordered_map<std::vector<s8>, u32> lcache;
+ ue2_unordered_map<Path, u32> rcache;
+};
+
+class RoseEngineBlob : noncopyable {
+public:
+ /** \brief Base offset of engine_blob in the Rose engine bytecode. */
+ static constexpr u32 base_offset = ROUNDUP_CL(sizeof(RoseEngine));
+
+ bool empty() const {
+ return blob.empty();
+ }
+
+ size_t size() const {
+ return blob.size();
+ }
+
+ u32 add(const void *a, const size_t len, const size_t align) {
+ pad(align);
+
+ size_t rv = base_offset + blob.size();
+ assert(rv >= base_offset);
+ DEBUG_PRINTF("write %zu bytes at offset %zu\n", len, rv);
+
+ assert(ISALIGNED_N(blob.size(), align));
+
+ blob.resize(blob.size() + len);
+ memcpy(&blob.back() - len + 1, a, len);
+
+ return verify_u32(rv);
+ }
+
+ template<typename T>
+ u32 add(const bytecode_ptr<T> &a) {
+ return add(a.get(), a.size(), a.align());
+ }
+
+ template<typename T>
+ u32 add(const T &a) {
+ static_assert(std::is_pod<T>::value, "should be pod");
+ return add(&a, sizeof(a), alignof(T));
+ }
+
+ template<typename T>
+ u32 add(const T &a, const size_t len) {
+ static_assert(std::is_pod<T>::value, "should be pod");
+ return add(&a, len, alignof(T));
+ }
+
+ template<typename Iter>
+ u32 add(Iter b, const Iter &e) {
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ static_assert(std::is_pod<value_type>::value, "should be pod");
+
+ if (b == e) {
+ return 0;
+ }
+
+ u32 offset = add(*b);
+ for (++b; b != e; ++b) {
+ add(*b);
+ }
+
+ return offset;
+ }
+
+ template<typename Range>
+ u32 add_range(const Range &range) {
+ return add(begin(range), end(range));
+ }
+
+ u32 add_iterator(const std::vector<mmbit_sparse_iter> &iter) {
+ auto cache_it = cached_iters.find(iter);
+ if (cache_it != cached_iters.end()) {
+ u32 offset = cache_it->second;
+ DEBUG_PRINTF("cache hit for iter at %u\n", offset);
+ return offset;
+ }
+
+ u32 offset = add(iter.begin(), iter.end());
+ cached_iters.emplace(iter, offset);
+ return offset;
+ }
+
+ void write_bytes(RoseEngine *engine) {
+ copy_bytes((char *)engine + base_offset, blob);
+ }
+
+ lookaround_info lookaround_cache;
+
+private:
+ void pad(size_t align) {
+ assert(ISALIGNED_N(base_offset, align));
+ size_t s = blob.size();
+
+ if (ISALIGNED_N(s, align)) {
+ return;
+ }
+
+ blob.resize(s + align - s % align);
+ }
+
+ /** \brief Cache of previously-written sparse iterators. */
+ ue2_unordered_map<std::vector<mmbit_sparse_iter>, u32> cached_iters;
+
+ /**
+ * \brief Contents of the Rose bytecode immediately following the
+ * RoseEngine.
+ */
+ std::vector<char, AlignedAllocator<char, 64>> blob;
+};
+
+} // namespace ue2
+
+#endif // ROSE_BUILD_ENGINE_BLOB_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_exclusive.cpp b/contrib/libs/hyperscan/src/rose/rose_build_exclusive.cpp
index 1cb3f0e50a9..6a7c1c15a3e 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_exclusive.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_exclusive.cpp
@@ -1,447 +1,447 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_exclusive.h"
-
-#include "ue2common.h"
-#include "rose_build_merge.h"
-#include "nfa/castlecompile.h"
-#include "nfagraph/ng_execute.h"
-#include "nfagraph/ng_holder.h"
-#include "nfagraph/ng_util.h"
-#include "util/clique.h"
-#include "util/compile_context.h"
-#include "util/container.h"
-#include "util/flat_containers.h"
-#include "util/graph.h"
-#include "util/make_unique.h"
-
-using namespace std;
-
-namespace ue2 {
-
-template<typename role_id>
-struct RoleChunk {
- vector<RoleInfo<role_id>> roles;
-};
-
-static
-CharReach getReachability(const NGHolder &h) {
- CharReach cr;
- for (const auto &v : vertices_range(h)) {
- if (!is_special(v, h)) {
- cr |= h[v].char_reach;
- }
- }
- return cr;
-}
-
-template<typename role_id>
-static
-vector<RoleChunk<role_id>> divideIntoChunks(const RoseBuildImpl &build,
- set<RoleInfo<role_id>> &roleInfoSet) {
- u32 chunkSize = build.cc.grey.tamaChunkSize;
- u32 cnt = 1;
- vector<RoleChunk<role_id>> chunks;
- RoleChunk<role_id> roleChunk;
- for (const auto &roleInfo : roleInfoSet) {
- if (cnt == chunkSize) {
- cnt -= chunkSize;
- chunks.push_back(roleChunk);
- roleChunk.roles.clear();
- }
- roleChunk.roles.push_back(roleInfo);
- cnt++;
- }
-
- if (cnt > 1) {
- chunks.push_back(roleChunk);
- }
-
- return chunks;
-}
-
-/* add prefix literals to engine graph */
-static
-bool addPrefixLiterals(NGHolder &h, unordered_set<u32> &tailId,
- const vector<vector<CharReach>> &triggers) {
- DEBUG_PRINTF("add literals to graph\n");
-
- NFAVertex start = h.start;
- vector<NFAVertex> heads;
- vector<NFAVertex> tails;
- for (const auto &lit : triggers) {
- NFAVertex last = start;
- if (lit.empty()) {
- return false;
- }
- u32 i = 0;
- for (const auto &c : lit) {
- DEBUG_PRINTF("lit:%s \n", c.to_string().c_str());
- NFAVertex u = add_vertex(h);
- h[u].char_reach = c;
- if (!i++) {
- heads.push_back(u);
- last = u;
- continue;
- }
- add_edge(last, u, h);
- last = u;
- }
- tails.push_back(last);
- tailId.insert(h[last].index);
- }
-
- for (auto v : adjacent_vertices_range(start, h)) {
- if (v != h.startDs) {
- for (auto &t : tails) {
- add_edge(t, v, h);
- }
- }
- }
-
- clear_out_edges(start, h);
- add_edge(h.start, h.start, h);
- for (auto &t : heads) {
- add_edge(start, t, h);
- }
-
- DEBUG_PRINTF("literals addition done\n");
- return true;
-}
-
-/* check if one literal is suffix of another */
-static
-bool isSuffix(const vector<vector<CharReach>> &triggers1,
- const vector<vector<CharReach>> &triggers2) {
- // literal suffix test
- for (const auto &lit1 : triggers1) {
- for (const auto &lit2 : triggers2) {
- const size_t len = min(lit1.size(), lit2.size());
- if (equal(lit1.rbegin(), lit1.rbegin() + len,
- lit2.rbegin(), overlaps)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/* prepare initial infix or suffix graph used for exclusive analysis */
-template<typename role_id>
-static
-u32 prepareRoleGraph(NGHolder &h, const role_id &s1) {
- u32 num = 0;
- if (s1.castle()) {
- num = num_vertices(h);
- NFAVertex u = add_vertex(h);
- h[u].char_reach = s1.castle()->reach();
- add_edge(h.startDs, u, h);
- // add self loop to repeat characters
- add_edge(u, u, h);
- } else if (s1.graph()) {
- const NGHolder &g = *s1.graph();
- cloneHolder(h, g);
- num = num_vertices(h);
- } else {
- // only infixes and suffixes with graph properties are possible
- // candidates, already filtered out other cases before
- // exclusive analysis
- assert(0);
- }
-
- return num;
-}
-
-/* get a subset of literal if reset character is found */
-static
-vector<CharReach> findStartPos(const CharReach &cr1,
- const vector<CharReach> &lit) {
- auto it = lit.rbegin(), ite = lit.rend();
- u32 pos = lit.size();
- for (; it != ite; it++) {
- if (!overlaps(cr1, *it)) {
- break;
- }
- pos--;
- }
-
- return vector<CharReach> (lit.begin() + pos, lit.end());
-}
-
-template<typename role_id>
-static
-bool isExclusive(const NGHolder &h,
- const u32 num, unordered_set<u32> &tailId,
- map<u32, unordered_set<u32>> &skipList,
- const RoleInfo<role_id> &role1,
- const RoleInfo<role_id> &role2) {
- const u32 id1 = role1.id;
- const u32 id2 = role2.id;
-
- if (contains(skipList, id1) && contains(skipList[id1], id2)) {
- return false;
- }
-
- const auto &triggers1 = role1.literals;
- const auto &triggers2 = role2.literals;
- if (isSuffix(triggers1, triggers2)) {
- skipList[id2].insert(id1);
- return false;
- }
-
- DEBUG_PRINTF("role id2:%u\n", id2);
- const auto &cr1 = role1.cr;
- if (overlaps(cr1, role2.last_cr)) {
- CharReach cr = cr1 | role1.prefix_cr;
- flat_set<NFAVertex> states;
- for (const auto &lit : triggers2) {
- auto lit1 = findStartPos(cr, lit);
- if (lit1.empty()) {
- continue;
- }
-
- states.clear();
-
- if (lit1.size() < lit.size()) {
- // Only starts.
- states.insert(h.start);
- states.insert(h.startDs);
- } else {
- // All vertices.
- insert(&states, vertices(h));
- }
-
- auto activeStates = execute_graph(h, lit1, states);
- // Check if only literal states are on
- for (const auto &s : activeStates) {
- if ((!is_any_start(s, h) && h[s].index <= num) ||
- contains(tailId, h[s].index)) {
- skipList[id2].insert(id1);
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-template<typename role_id>
-static
-unordered_set<u32> checkExclusivity(const NGHolder &h,
- const u32 num, unordered_set<u32> &tailId,
- map<u32, unordered_set<u32>> &skipList,
- const RoleInfo<role_id> &role1,
- const RoleChunk<role_id> &roleChunk) {
- unordered_set<u32> info;
- const u32 id1 = role1.id;
- for (const auto &role2 : roleChunk.roles) {
- const u32 id2 = role2.id;
- if (id1 != id2 && isExclusive(h, num, tailId, skipList,
- role1, role2)) {
- info.insert(id2);
- }
- }
-
- return info;
-}
-
-static
-void findCliques(const map<u32, set<u32>> &exclusiveGroups,
- vector<vector<u32>> &exclusive_roles) {
- if (exclusiveGroups.empty()) {
- return;
- }
- // Construct the exclusivity graph
- map<u32, CliqueVertex> vertex_map;
- unique_ptr<CliqueGraph> cg = std::make_unique<CliqueGraph>();
-
- // Add vertices representing infixes/suffixes
- for (const auto &e : exclusiveGroups) {
- const u32 id = e.first;
- CliqueVertex v1 = add_vertex(CliqueVertexProps(id), *cg);
- vertex_map[id] = v1;
- }
-
- // Wire exclusive pairs
- for (const auto &e1 : exclusiveGroups) {
- const u32 literalId1 = e1.first;
- CliqueVertex lv = vertex_map[literalId1];
- const set<u32> &exclusiveSet = e1.second;
- for (const auto &e2 : exclusiveGroups) {
- const u32 literalId2 = e2.first;
- if (literalId1 < literalId2 &&
- contains(exclusiveSet, literalId2)) {
- add_edge(lv, vertex_map[literalId2], *cg);
- DEBUG_PRINTF("Wire %u:%u\n", literalId1, literalId2);
- }
- }
- }
-
- // Find clique groups
- const auto &clique = removeClique(*cg);
- for (const auto &i : clique) {
- DEBUG_PRINTF("cliq:%zu\n", i.size());
- if (i.size() > 1) {
- exclusive_roles.push_back(i);
- }
- }
- DEBUG_PRINTF("Clique graph size:%zu\n", exclusive_roles.size());
-}
-
-static
-map<u32, set<u32>> findExclusiveGroups(const RoseBuildImpl &build,
- const map<u32, unordered_set<u32>> &exclusiveInfo,
- const map<u32, vector<RoseVertex>> &vertex_map,
- const bool is_infix) {
- map<u32, set<u32>> exclusiveGroups;
- for (const auto &e : exclusiveInfo) {
- u32 i = e.first;
- const auto &s = e.second;
- set<u32> group;
- set<RoseVertex> q1(vertex_map.at(i).begin(),
- vertex_map.at(i).end());
- DEBUG_PRINTF("vertex set:%zu\n", q1.size());
- for (const auto &val : s) {
- set<RoseVertex> q2(vertex_map.at(val).begin(),
- vertex_map.at(val).end());
- if (contains(exclusiveInfo.at(val), i) &&
- (!is_infix || mergeableRoseVertices(build, q1, q2))) {
- group.insert(val);
- }
- }
- if (!group.empty()) {
- exclusiveGroups[i] = group;
- }
- }
-
- return exclusiveGroups;
-}
-
-template<typename role_id>
-static
-bool setTriggerLiterals(RoleInfo<role_id> &roleInfo,
- const map<u32, vector<vector<CharReach>>> &triggers) {
- u32 minLiteralLen = ~0U;
- for (const auto &tr : triggers) {
- for (const auto &lit : tr.second) {
- if (lit.empty()) {
- return false;
- }
- minLiteralLen = min(minLiteralLen, (u32)lit.size());
- roleInfo.last_cr |= lit.back();
- for (const auto &c : lit) {
- roleInfo.prefix_cr |= c;
- }
- roleInfo.literals.push_back(lit);
- }
- }
-
- if (roleInfo.role.graph()) {
- const NGHolder &g = *roleInfo.role.graph();
- roleInfo.cr = getReachability(g);
- } else if (roleInfo.role.castle()) {
- roleInfo.cr = roleInfo.role.castle()->reach();
- }
-
- // test the score of this engine
- roleInfo.score = 256 - roleInfo.cr.count() + minLiteralLen;
- if (roleInfo.score < 20) {
- return false;
- }
-
- return true;
-}
-
-bool setTriggerLiteralsInfix(RoleInfo<left_id> &roleInfo,
- const map<u32, vector<vector<CharReach>>> &triggers) {
- return setTriggerLiterals(roleInfo, triggers);
-}
-
-bool setTriggerLiteralsSuffix(RoleInfo<suffix_id> &roleInfo,
- const map<u32, vector<vector<CharReach>>> &triggers) {
- return setTriggerLiterals(roleInfo, triggers);
-}
-
-template<typename role_id>
-static
-void exclusiveAnalysis(const RoseBuildImpl &build,
- const map<u32, vector<RoseVertex>> &vertex_map,
- set<RoleInfo<role_id>> &roleInfoSet,
- vector<vector<u32>> &exclusive_roles, const bool is_infix) {
- const auto &chunks = divideIntoChunks(build, roleInfoSet);
- DEBUG_PRINTF("Exclusivity analysis entry\n");
- map<u32, unordered_set<u32>> exclusiveInfo;
-
- for (const auto &roleChunk : chunks) {
- map<u32, unordered_set<u32>> skipList;
- for (const auto &role1 : roleChunk.roles) {
- const u32 id1 = role1.id;
- const role_id &s1 = role1.role;
- const auto &triggers1 = role1.literals;
-
- NGHolder h;
- u32 num = prepareRoleGraph(h, s1);
- DEBUG_PRINTF("role id1:%u\n", id1);
- unordered_set<u32> tailId;
- if (!addPrefixLiterals(h, tailId, triggers1)) {
- continue;
- }
-
- exclusiveInfo[id1] = checkExclusivity(h, num, tailId,
- skipList, role1, roleChunk);
- }
- }
-
- // Create final candidate exclusive groups
- const auto exclusiveGroups =
- findExclusiveGroups(build, exclusiveInfo, vertex_map, is_infix);
- exclusiveInfo.clear();
-
- // Find cliques for each exclusive groups
- findCliques(exclusiveGroups, exclusive_roles);
-}
-
-void exclusiveAnalysisInfix(const RoseBuildImpl &build,
- const map<u32, vector<RoseVertex>> &vertex_map,
- set<RoleInfo<left_id>> &roleInfoSet,
- vector<vector<u32>> &exclusive_roles) {
- exclusiveAnalysis(build, vertex_map, roleInfoSet, exclusive_roles,
- true);
-}
-
-void exclusiveAnalysisSuffix(const RoseBuildImpl &build,
- const map<u32, vector<RoseVertex>> &vertex_map,
- set<RoleInfo<suffix_id>> &roleInfoSet,
- vector<vector<u32>> &exclusive_roles) {
- exclusiveAnalysis(build, vertex_map, roleInfoSet, exclusive_roles,
- false);
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_exclusive.h"
+
+#include "ue2common.h"
+#include "rose_build_merge.h"
+#include "nfa/castlecompile.h"
+#include "nfagraph/ng_execute.h"
+#include "nfagraph/ng_holder.h"
+#include "nfagraph/ng_util.h"
+#include "util/clique.h"
+#include "util/compile_context.h"
+#include "util/container.h"
+#include "util/flat_containers.h"
+#include "util/graph.h"
+#include "util/make_unique.h"
+
+using namespace std;
+
+namespace ue2 {
+
+template<typename role_id>
+struct RoleChunk {
+ vector<RoleInfo<role_id>> roles;
+};
+
+static
+CharReach getReachability(const NGHolder &h) {
+ CharReach cr;
+ for (const auto &v : vertices_range(h)) {
+ if (!is_special(v, h)) {
+ cr |= h[v].char_reach;
+ }
+ }
+ return cr;
+}
+
+template<typename role_id>
+static
+vector<RoleChunk<role_id>> divideIntoChunks(const RoseBuildImpl &build,
+ set<RoleInfo<role_id>> &roleInfoSet) {
+ u32 chunkSize = build.cc.grey.tamaChunkSize;
+ u32 cnt = 1;
+ vector<RoleChunk<role_id>> chunks;
+ RoleChunk<role_id> roleChunk;
+ for (const auto &roleInfo : roleInfoSet) {
+ if (cnt == chunkSize) {
+ cnt -= chunkSize;
+ chunks.push_back(roleChunk);
+ roleChunk.roles.clear();
+ }
+ roleChunk.roles.push_back(roleInfo);
+ cnt++;
+ }
+
+ if (cnt > 1) {
+ chunks.push_back(roleChunk);
+ }
+
+ return chunks;
+}
+
+/* add prefix literals to engine graph */
+static
+bool addPrefixLiterals(NGHolder &h, unordered_set<u32> &tailId,
+ const vector<vector<CharReach>> &triggers) {
+ DEBUG_PRINTF("add literals to graph\n");
+
+ NFAVertex start = h.start;
+ vector<NFAVertex> heads;
+ vector<NFAVertex> tails;
+ for (const auto &lit : triggers) {
+ NFAVertex last = start;
+ if (lit.empty()) {
+ return false;
+ }
+ u32 i = 0;
+ for (const auto &c : lit) {
+ DEBUG_PRINTF("lit:%s \n", c.to_string().c_str());
+ NFAVertex u = add_vertex(h);
+ h[u].char_reach = c;
+ if (!i++) {
+ heads.push_back(u);
+ last = u;
+ continue;
+ }
+ add_edge(last, u, h);
+ last = u;
+ }
+ tails.push_back(last);
+ tailId.insert(h[last].index);
+ }
+
+ for (auto v : adjacent_vertices_range(start, h)) {
+ if (v != h.startDs) {
+ for (auto &t : tails) {
+ add_edge(t, v, h);
+ }
+ }
+ }
+
+ clear_out_edges(start, h);
+ add_edge(h.start, h.start, h);
+ for (auto &t : heads) {
+ add_edge(start, t, h);
+ }
+
+ DEBUG_PRINTF("literals addition done\n");
+ return true;
+}
+
+/* check if one literal is suffix of another */
+static
+bool isSuffix(const vector<vector<CharReach>> &triggers1,
+ const vector<vector<CharReach>> &triggers2) {
+ // literal suffix test
+ for (const auto &lit1 : triggers1) {
+ for (const auto &lit2 : triggers2) {
+ const size_t len = min(lit1.size(), lit2.size());
+ if (equal(lit1.rbegin(), lit1.rbegin() + len,
+ lit2.rbegin(), overlaps)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* prepare initial infix or suffix graph used for exclusive analysis */
+template<typename role_id>
+static
+u32 prepareRoleGraph(NGHolder &h, const role_id &s1) {
+ u32 num = 0;
+ if (s1.castle()) {
+ num = num_vertices(h);
+ NFAVertex u = add_vertex(h);
+ h[u].char_reach = s1.castle()->reach();
+ add_edge(h.startDs, u, h);
+ // add self loop to repeat characters
+ add_edge(u, u, h);
+ } else if (s1.graph()) {
+ const NGHolder &g = *s1.graph();
+ cloneHolder(h, g);
+ num = num_vertices(h);
+ } else {
+ // only infixes and suffixes with graph properties are possible
+ // candidates, already filtered out other cases before
+ // exclusive analysis
+ assert(0);
+ }
+
+ return num;
+}
+
+/* get a subset of literal if reset character is found */
+static
+vector<CharReach> findStartPos(const CharReach &cr1,
+ const vector<CharReach> &lit) {
+ auto it = lit.rbegin(), ite = lit.rend();
+ u32 pos = lit.size();
+ for (; it != ite; it++) {
+ if (!overlaps(cr1, *it)) {
+ break;
+ }
+ pos--;
+ }
+
+ return vector<CharReach> (lit.begin() + pos, lit.end());
+}
+
+template<typename role_id>
+static
+bool isExclusive(const NGHolder &h,
+ const u32 num, unordered_set<u32> &tailId,
+ map<u32, unordered_set<u32>> &skipList,
+ const RoleInfo<role_id> &role1,
+ const RoleInfo<role_id> &role2) {
+ const u32 id1 = role1.id;
+ const u32 id2 = role2.id;
+
+ if (contains(skipList, id1) && contains(skipList[id1], id2)) {
+ return false;
+ }
+
+ const auto &triggers1 = role1.literals;
+ const auto &triggers2 = role2.literals;
+ if (isSuffix(triggers1, triggers2)) {
+ skipList[id2].insert(id1);
+ return false;
+ }
+
+ DEBUG_PRINTF("role id2:%u\n", id2);
+ const auto &cr1 = role1.cr;
+ if (overlaps(cr1, role2.last_cr)) {
+ CharReach cr = cr1 | role1.prefix_cr;
+ flat_set<NFAVertex> states;
+ for (const auto &lit : triggers2) {
+ auto lit1 = findStartPos(cr, lit);
+ if (lit1.empty()) {
+ continue;
+ }
+
+ states.clear();
+
+ if (lit1.size() < lit.size()) {
+ // Only starts.
+ states.insert(h.start);
+ states.insert(h.startDs);
+ } else {
+ // All vertices.
+ insert(&states, vertices(h));
+ }
+
+ auto activeStates = execute_graph(h, lit1, states);
+ // Check if only literal states are on
+ for (const auto &s : activeStates) {
+ if ((!is_any_start(s, h) && h[s].index <= num) ||
+ contains(tailId, h[s].index)) {
+ skipList[id2].insert(id1);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+template<typename role_id>
+static
+unordered_set<u32> checkExclusivity(const NGHolder &h,
+ const u32 num, unordered_set<u32> &tailId,
+ map<u32, unordered_set<u32>> &skipList,
+ const RoleInfo<role_id> &role1,
+ const RoleChunk<role_id> &roleChunk) {
+ unordered_set<u32> info;
+ const u32 id1 = role1.id;
+ for (const auto &role2 : roleChunk.roles) {
+ const u32 id2 = role2.id;
+ if (id1 != id2 && isExclusive(h, num, tailId, skipList,
+ role1, role2)) {
+ info.insert(id2);
+ }
+ }
+
+ return info;
+}
+
+static
+void findCliques(const map<u32, set<u32>> &exclusiveGroups,
+ vector<vector<u32>> &exclusive_roles) {
+ if (exclusiveGroups.empty()) {
+ return;
+ }
+ // Construct the exclusivity graph
+ map<u32, CliqueVertex> vertex_map;
+ unique_ptr<CliqueGraph> cg = std::make_unique<CliqueGraph>();
+
+ // Add vertices representing infixes/suffixes
+ for (const auto &e : exclusiveGroups) {
+ const u32 id = e.first;
+ CliqueVertex v1 = add_vertex(CliqueVertexProps(id), *cg);
+ vertex_map[id] = v1;
+ }
+
+ // Wire exclusive pairs
+ for (const auto &e1 : exclusiveGroups) {
+ const u32 literalId1 = e1.first;
+ CliqueVertex lv = vertex_map[literalId1];
+ const set<u32> &exclusiveSet = e1.second;
+ for (const auto &e2 : exclusiveGroups) {
+ const u32 literalId2 = e2.first;
+ if (literalId1 < literalId2 &&
+ contains(exclusiveSet, literalId2)) {
+ add_edge(lv, vertex_map[literalId2], *cg);
+ DEBUG_PRINTF("Wire %u:%u\n", literalId1, literalId2);
+ }
+ }
+ }
+
+ // Find clique groups
+ const auto &clique = removeClique(*cg);
+ for (const auto &i : clique) {
+ DEBUG_PRINTF("cliq:%zu\n", i.size());
+ if (i.size() > 1) {
+ exclusive_roles.push_back(i);
+ }
+ }
+ DEBUG_PRINTF("Clique graph size:%zu\n", exclusive_roles.size());
+}
+
+static
+map<u32, set<u32>> findExclusiveGroups(const RoseBuildImpl &build,
+ const map<u32, unordered_set<u32>> &exclusiveInfo,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ const bool is_infix) {
+ map<u32, set<u32>> exclusiveGroups;
+ for (const auto &e : exclusiveInfo) {
+ u32 i = e.first;
+ const auto &s = e.second;
+ set<u32> group;
+ set<RoseVertex> q1(vertex_map.at(i).begin(),
+ vertex_map.at(i).end());
+ DEBUG_PRINTF("vertex set:%zu\n", q1.size());
+ for (const auto &val : s) {
+ set<RoseVertex> q2(vertex_map.at(val).begin(),
+ vertex_map.at(val).end());
+ if (contains(exclusiveInfo.at(val), i) &&
+ (!is_infix || mergeableRoseVertices(build, q1, q2))) {
+ group.insert(val);
+ }
+ }
+ if (!group.empty()) {
+ exclusiveGroups[i] = group;
+ }
+ }
+
+ return exclusiveGroups;
+}
+
+template<typename role_id>
+static
+bool setTriggerLiterals(RoleInfo<role_id> &roleInfo,
+ const map<u32, vector<vector<CharReach>>> &triggers) {
+ u32 minLiteralLen = ~0U;
+ for (const auto &tr : triggers) {
+ for (const auto &lit : tr.second) {
+ if (lit.empty()) {
+ return false;
+ }
+ minLiteralLen = min(minLiteralLen, (u32)lit.size());
+ roleInfo.last_cr |= lit.back();
+ for (const auto &c : lit) {
+ roleInfo.prefix_cr |= c;
+ }
+ roleInfo.literals.push_back(lit);
+ }
+ }
+
+ if (roleInfo.role.graph()) {
+ const NGHolder &g = *roleInfo.role.graph();
+ roleInfo.cr = getReachability(g);
+ } else if (roleInfo.role.castle()) {
+ roleInfo.cr = roleInfo.role.castle()->reach();
+ }
+
+ // test the score of this engine
+ roleInfo.score = 256 - roleInfo.cr.count() + minLiteralLen;
+ if (roleInfo.score < 20) {
+ return false;
+ }
+
+ return true;
+}
+
+bool setTriggerLiteralsInfix(RoleInfo<left_id> &roleInfo,
+ const map<u32, vector<vector<CharReach>>> &triggers) {
+ return setTriggerLiterals(roleInfo, triggers);
+}
+
+bool setTriggerLiteralsSuffix(RoleInfo<suffix_id> &roleInfo,
+ const map<u32, vector<vector<CharReach>>> &triggers) {
+ return setTriggerLiterals(roleInfo, triggers);
+}
+
+template<typename role_id>
+static
+void exclusiveAnalysis(const RoseBuildImpl &build,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ set<RoleInfo<role_id>> &roleInfoSet,
+ vector<vector<u32>> &exclusive_roles, const bool is_infix) {
+ const auto &chunks = divideIntoChunks(build, roleInfoSet);
+ DEBUG_PRINTF("Exclusivity analysis entry\n");
+ map<u32, unordered_set<u32>> exclusiveInfo;
+
+ for (const auto &roleChunk : chunks) {
+ map<u32, unordered_set<u32>> skipList;
+ for (const auto &role1 : roleChunk.roles) {
+ const u32 id1 = role1.id;
+ const role_id &s1 = role1.role;
+ const auto &triggers1 = role1.literals;
+
+ NGHolder h;
+ u32 num = prepareRoleGraph(h, s1);
+ DEBUG_PRINTF("role id1:%u\n", id1);
+ unordered_set<u32> tailId;
+ if (!addPrefixLiterals(h, tailId, triggers1)) {
+ continue;
+ }
+
+ exclusiveInfo[id1] = checkExclusivity(h, num, tailId,
+ skipList, role1, roleChunk);
+ }
+ }
+
+ // Create final candidate exclusive groups
+ const auto exclusiveGroups =
+ findExclusiveGroups(build, exclusiveInfo, vertex_map, is_infix);
+ exclusiveInfo.clear();
+
+ // Find cliques for each exclusive groups
+ findCliques(exclusiveGroups, exclusive_roles);
+}
+
+void exclusiveAnalysisInfix(const RoseBuildImpl &build,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ set<RoleInfo<left_id>> &roleInfoSet,
+ vector<vector<u32>> &exclusive_roles) {
+ exclusiveAnalysis(build, vertex_map, roleInfoSet, exclusive_roles,
+ true);
+}
+
+void exclusiveAnalysisSuffix(const RoseBuildImpl &build,
+ const map<u32, vector<RoseVertex>> &vertex_map,
+ set<RoleInfo<suffix_id>> &roleInfoSet,
+ vector<vector<u32>> &exclusive_roles) {
+ exclusiveAnalysis(build, vertex_map, roleInfoSet, exclusive_roles,
+ false);
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_exclusive.h b/contrib/libs/hyperscan/src/rose/rose_build_exclusive.h
index fb4659efb05..3269dce612c 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_exclusive.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_exclusive.h
@@ -1,127 +1,127 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief exclusive analysis for infix and suffix engines.
- * Two engines are considered as exclusive if they can never be alive
- * at the same time. This analysis takes advantage of the property of
- * triggering literal + engine graph. If the triggering literals of
- * two engines can make all the states dead in each other's graph,
- * then they are exclusive.
- */
-#ifndef ROSE_BUILD_EXCLUSIVE_H
-#define ROSE_BUILD_EXCLUSIVE_H
-
-#include "ue2common.h"
-
-#include "rose_build_impl.h"
-#include "util/alloc.h"
-#include "util/charreach.h"
-
-#include <map>
-#include <set>
-#include <vector>
-
-namespace ue2 {
-
-/** \brief role info structure for exclusive analysis */
-template<typename role_id>
-struct RoleInfo {
- RoleInfo(role_id role_in, u32 id_in) : role(role_in), id(id_in) {}
- bool operator==(const RoleInfo &b) const {
- return id == b.id;
- }
- bool operator!=(const RoleInfo &b) const { return !(*this == b); }
- bool operator<(const RoleInfo &b) const {
- const RoleInfo &a = *this;
- if (a.score != b.score) {
- return a.score > b.score;
- }
- ORDER_CHECK(id);
- return false;
- }
-
- std::vector<std::vector<CharReach>> literals; // prefix literals
- CharReach prefix_cr; // reach of prefix literals
- CharReach last_cr; // reach of the last character of literals
- CharReach cr; // reach of engine graph
- const role_id role; // infix or suffix info
- const u32 id; // infix or suffix id
- u32 score = ~0U; // score for exclusive analysis
-};
-
-/**
- * \brief add triggering literals to infix info.
- */
-bool setTriggerLiteralsInfix(RoleInfo<left_id> &roleInfo,
- const std::map<u32, std::vector<std::vector<CharReach>>> &triggers);
-
-/**
- * \brief add triggering literals to suffix info.
- */
-bool setTriggerLiteralsSuffix(RoleInfo<suffix_id> &roleInfo,
- const std::map<u32, std::vector<std::vector<CharReach>>> &triggers);
-
-/**
- * Exclusive analysis for infix engines.
- *
- * @param build rose build info mainly used to set exclusive chunk size here
- * @param vertex_map mapping between engine id and rose vertices
- * related to this engine
- * @param roleInfoSet structure contains role properties including infix info,
- * triggering literals and literal reachabilities.
- * Used for exclusive analysis.
- * @param exclusive_roles output mapping between engine id and its exclusive
- * group id
- */
-void exclusiveAnalysisInfix(const RoseBuildImpl &build,
- const std::map<u32, std::vector<RoseVertex>> &vertex_map,
- std::set<RoleInfo<left_id>> &roleInfoSet,
- std::vector<std::vector<u32>> &exclusive_roles);
-
-/**
- * Exclusive analysis for suffix engines.
- *
- * @param build rose build info mainly used to set exclusive chunk size here
- * @param vertex_map mapping between engine id and rose vertices
- * related to this engine
- * @param roleInfoSet structure contains role properties including suffix info,
- * triggering literals and literal reachabilities.
- * Used for exclusive analysis.
- * @param exclusive_roles output mapping between engine id and its exclusive
- * group id
- */
-void exclusiveAnalysisSuffix(const RoseBuildImpl &build,
- const std::map<u32, std::vector<RoseVertex>> &vertex_map,
- std::set<RoleInfo<suffix_id>> &roleInfoSet,
- std::vector<std::vector<u32>> &exclusive_roles);
-
-} // namespace ue2
-
-#endif //ROSE_BUILD_EXCLUSIVE_H
-
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief exclusive analysis for infix and suffix engines.
+ * Two engines are considered as exclusive if they can never be alive
+ * at the same time. This analysis takes advantage of the property of
+ * triggering literal + engine graph. If the triggering literals of
+ * two engines can make all the states dead in each other's graph,
+ * then they are exclusive.
+ */
+#ifndef ROSE_BUILD_EXCLUSIVE_H
+#define ROSE_BUILD_EXCLUSIVE_H
+
+#include "ue2common.h"
+
+#include "rose_build_impl.h"
+#include "util/alloc.h"
+#include "util/charreach.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+namespace ue2 {
+
+/** \brief role info structure for exclusive analysis */
+template<typename role_id>
+struct RoleInfo {
+ RoleInfo(role_id role_in, u32 id_in) : role(role_in), id(id_in) {}
+ bool operator==(const RoleInfo &b) const {
+ return id == b.id;
+ }
+ bool operator!=(const RoleInfo &b) const { return !(*this == b); }
+ bool operator<(const RoleInfo &b) const {
+ const RoleInfo &a = *this;
+ if (a.score != b.score) {
+ return a.score > b.score;
+ }
+ ORDER_CHECK(id);
+ return false;
+ }
+
+ std::vector<std::vector<CharReach>> literals; // prefix literals
+ CharReach prefix_cr; // reach of prefix literals
+ CharReach last_cr; // reach of the last character of literals
+ CharReach cr; // reach of engine graph
+ const role_id role; // infix or suffix info
+ const u32 id; // infix or suffix id
+ u32 score = ~0U; // score for exclusive analysis
+};
+
+/**
+ * \brief add triggering literals to infix info.
+ */
+bool setTriggerLiteralsInfix(RoleInfo<left_id> &roleInfo,
+ const std::map<u32, std::vector<std::vector<CharReach>>> &triggers);
+
+/**
+ * \brief add triggering literals to suffix info.
+ */
+bool setTriggerLiteralsSuffix(RoleInfo<suffix_id> &roleInfo,
+ const std::map<u32, std::vector<std::vector<CharReach>>> &triggers);
+
+/**
+ * Exclusive analysis for infix engines.
+ *
+ * @param build rose build info mainly used to set exclusive chunk size here
+ * @param vertex_map mapping between engine id and rose vertices
+ * related to this engine
+ * @param roleInfoSet structure contains role properties including infix info,
+ * triggering literals and literal reachabilities.
+ * Used for exclusive analysis.
+ * @param exclusive_roles output mapping between engine id and its exclusive
+ * group id
+ */
+void exclusiveAnalysisInfix(const RoseBuildImpl &build,
+ const std::map<u32, std::vector<RoseVertex>> &vertex_map,
+ std::set<RoleInfo<left_id>> &roleInfoSet,
+ std::vector<std::vector<u32>> &exclusive_roles);
+
+/**
+ * Exclusive analysis for suffix engines.
+ *
+ * @param build rose build info mainly used to set exclusive chunk size here
+ * @param vertex_map mapping between engine id and rose vertices
+ * related to this engine
+ * @param roleInfoSet structure contains role properties including suffix info,
+ * triggering literals and literal reachabilities.
+ * Used for exclusive analysis.
+ * @param exclusive_roles output mapping between engine id and its exclusive
+ * group id
+ */
+void exclusiveAnalysisSuffix(const RoseBuildImpl &build,
+ const std::map<u32, std::vector<RoseVertex>> &vertex_map,
+ std::set<RoleInfo<suffix_id>> &roleInfoSet,
+ std::vector<std::vector<u32>> &exclusive_roles);
+
+} // namespace ue2
+
+#endif //ROSE_BUILD_EXCLUSIVE_H
+
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_groups.cpp b/contrib/libs/hyperscan/src/rose/rose_build_groups.cpp
index 5e4206943f3..209889e558b 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_groups.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_groups.cpp
@@ -1,707 +1,707 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose build: code for analysing literal groups.
- */
-
-#include "rose_build_groups.h"
-
-#include "util/boundary_reports.h"
-#include "util/compile_context.h"
-#include "util/report_manager.h"
-
-#include <queue>
-#include <vector>
-
-#include <boost/graph/topological_sort.hpp>
-#include <boost/range/adaptor/map.hpp>
-#include <boost/range/adaptor/reversed.hpp>
-
-using namespace std;
-using boost::adaptors::map_keys;
-
-namespace ue2 {
-
-#define ROSE_LONG_LITERAL_LEN 8
-
-static
-bool superStrong(const rose_literal_id &lit) {
- if (lit.s.length() < ROSE_LONG_LITERAL_LEN) {
- return false;
- }
-
- const u32 EXPECTED_FDR_BUCKET_LENGTH = 8;
-
- assert(lit.s.length() >= EXPECTED_FDR_BUCKET_LENGTH);
- size_t len = lit.s.length();
- const string &s = lit.s.get_string();
-
- for (size_t i = 1; i < EXPECTED_FDR_BUCKET_LENGTH; i++) {
- if (s[len - 1 - i] != s[len - 1]) {
- return true; /* we have at least some variation in the tail */
- }
- }
- DEBUG_PRINTF("lit '%s' is not superstrong due to tail\n",
- escapeString(s).c_str());
- return false;
-}
-
-static
-bool eligibleForAlwaysOnGroup(const RoseBuildImpl &build, u32 id) {
- auto eligble = [&](RoseVertex v) {
- return build.isRootSuccessor(v)
- && (!build.g[v].left || !isAnchored(build.g[v].left));
- };
-
- if (any_of_in(build.literal_info[id].vertices, eligble)) {
- return true;
- }
-
- for (u32 delayed_id : build.literal_info[id].delayed_ids) {
- if (any_of_in(build.literal_info[delayed_id].vertices, eligble)) {
- return true;
- }
- }
-
- return false;
-}
-
-static
-bool requires_group_assignment(const rose_literal_id &lit,
- const rose_literal_info &info) {
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose build: code for analysing literal groups.
+ */
+
+#include "rose_build_groups.h"
+
+#include "util/boundary_reports.h"
+#include "util/compile_context.h"
+#include "util/report_manager.h"
+
+#include <queue>
+#include <vector>
+
+#include <boost/graph/topological_sort.hpp>
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/adaptor/reversed.hpp>
+
+using namespace std;
+using boost::adaptors::map_keys;
+
+namespace ue2 {
+
+#define ROSE_LONG_LITERAL_LEN 8
+
+static
+bool superStrong(const rose_literal_id &lit) {
+ if (lit.s.length() < ROSE_LONG_LITERAL_LEN) {
+ return false;
+ }
+
+ const u32 EXPECTED_FDR_BUCKET_LENGTH = 8;
+
+ assert(lit.s.length() >= EXPECTED_FDR_BUCKET_LENGTH);
+ size_t len = lit.s.length();
+ const string &s = lit.s.get_string();
+
+ for (size_t i = 1; i < EXPECTED_FDR_BUCKET_LENGTH; i++) {
+ if (s[len - 1 - i] != s[len - 1]) {
+ return true; /* we have at least some variation in the tail */
+ }
+ }
+ DEBUG_PRINTF("lit '%s' is not superstrong due to tail\n",
+ escapeString(s).c_str());
+ return false;
+}
+
+static
+bool eligibleForAlwaysOnGroup(const RoseBuildImpl &build, u32 id) {
+ auto eligble = [&](RoseVertex v) {
+ return build.isRootSuccessor(v)
+ && (!build.g[v].left || !isAnchored(build.g[v].left));
+ };
+
+ if (any_of_in(build.literal_info[id].vertices, eligble)) {
+ return true;
+ }
+
+ for (u32 delayed_id : build.literal_info[id].delayed_ids) {
+ if (any_of_in(build.literal_info[delayed_id].vertices, eligble)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static
+bool requires_group_assignment(const rose_literal_id &lit,
+ const rose_literal_info &info) {
if (lit.delay) { /* we will check the shadow's leader */
- return false;
- }
-
- if (lit.table == ROSE_ANCHORED || lit.table == ROSE_EVENT) {
- return false;
- }
-
- // If we already have a group applied, skip.
- if (info.group_mask) {
- return false;
- }
-
- if (info.vertices.empty() && info.delayed_ids.empty()) {
- DEBUG_PRINTF("literal is good for nothing\n");
- return false;
- }
-
- return true;
-}
-
-static
-rose_group calcLocalGroup(const RoseVertex v, const RoseGraph &g,
- const deque<rose_literal_info> &literal_info,
- const bool small_literal_count) {
- rose_group local_group = 0;
-
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- /* In small cases, ensure that siblings have the same rose parentage to
- * allow rose squashing. In larger cases, don't do this as groups are
- * probably too scarce. */
- for (auto w : adjacent_vertices_range(u, g)) {
- if (!small_literal_count || g[v].left == g[w].left) {
- for (u32 lit_id : g[w].literals) {
- local_group |= literal_info[lit_id].group_mask;
- }
- } else {
- DEBUG_PRINTF("not sibling different mother %zu %zu\n",
- g[v].index, g[w].index);
- }
- }
- }
-
- return local_group;
-}
-
-/* group constants */
-#define MAX_LIGHT_LITERAL_CASE 200 /* allow rose to affect group decisions below
- * this */
-
-static
-flat_set<RoseVertex> getAssociatedVertices(const RoseBuildImpl &build, u32 id) {
- flat_set<RoseVertex> out;
- const auto &info = build.literal_info[id];
- insert(&out, info.vertices);
- for (const auto &delayed : info.delayed_ids) {
- insert(&out, build.literal_info[delayed].vertices);
- }
- return out;
-}
-
-static
-u32 next_available_group(u32 counter, u32 min_start_group) {
- counter++;
- if (counter == ROSE_GROUPS_MAX) {
- DEBUG_PRINTF("resetting groups\n");
- counter = min_start_group;
- }
-
- return counter;
-}
-
-static
-void allocateGroupForBoundary(RoseBuildImpl &build, u32 group_always_on,
- map<u8, u32> &groupCount) {
- /* Boundary reports at zero will always fired and forgotten, no need to
- * worry about preventing the stream being marked as exhausted */
- if (build.boundary.report_at_eod.empty()) {
- return;
- }
-
- /* Group based stream exhaustion is only done at stream boundaries */
- if (!build.cc.streaming) {
- return;
- }
-
- DEBUG_PRINTF("allocating %u as boundary group id\n", group_always_on);
-
- build.boundary_group_mask = 1ULL << group_always_on;
- groupCount[group_always_on]++;
-}
-
-static
-void allocateGroupForEvent(RoseBuildImpl &build, u32 group_always_on,
- map<u8, u32> &groupCount, u32 *counter) {
- if (build.eod_event_literal_id == MO_INVALID_IDX) {
- return;
- }
-
- /* Group based stream exhaustion is only done at stream boundaries */
- if (!build.cc.streaming) {
- return;
- }
-
- rose_literal_info &info = build.literal_info[build.eod_event_literal_id];
-
- if (info.vertices.empty()) {
- return;
- }
-
- bool new_group = !groupCount[group_always_on];
- for (RoseVertex v : info.vertices) {
- if (build.g[v].left && !isAnchored(build.g[v].left)) {
- new_group = false;
- }
- }
-
- u32 group;
- if (!new_group) {
- group = group_always_on;
- } else {
- group = *counter;
- *counter += 1;
- }
-
- DEBUG_PRINTF("allocating %u as eod event group id\n", *counter);
- info.group_mask = 1ULL << group;
- groupCount[group]++;
-}
-
-void assignGroupsToLiterals(RoseBuildImpl &build) {
- auto &literals = build.literals;
- auto &literal_info = build.literal_info;
-
- bool small_literal_count = literal_info.size() <= MAX_LIGHT_LITERAL_CASE;
-
- map<u8, u32> groupCount; /* group index to number of members */
-
- u32 counter = 0;
- u32 group_always_on = 0;
-
- // First pass: handle always on literals.
- for (u32 id = 0; id < literals.size(); id++) {
- const rose_literal_id &lit = literals.at(id);
- rose_literal_info &info = literal_info[id];
-
- if (!requires_group_assignment(lit, info)) {
- continue;
- }
-
- // If this literal has a root role, we always have to search for it
- // anyway, so it goes in the always-on group.
- /* We could end up squashing it if it is followed by a .* */
- if (eligibleForAlwaysOnGroup(build, id)) {
- info.group_mask = 1ULL << group_always_on;
- groupCount[group_always_on]++;
- continue;
- }
- }
-
- u32 group_long_lit;
- if (groupCount[group_always_on]) {
- DEBUG_PRINTF("%u always on literals\n", groupCount[group_always_on]);
- group_long_lit = group_always_on;
- counter++;
- } else {
- group_long_lit = counter;
- counter++;
- }
-
- allocateGroupForBoundary(build, group_always_on, groupCount);
- allocateGroupForEvent(build, group_always_on, groupCount, &counter);
-
- u32 min_start_group = counter;
- priority_queue<tuple<s32, s32, u32>> pq;
-
- // Second pass: the other literals.
- for (u32 id = 0; id < literals.size(); id++) {
- const rose_literal_id &lit = literals.at(id);
- rose_literal_info &info = literal_info[id];
-
- if (!requires_group_assignment(lit, info)) {
- continue;
- }
-
- assert(!eligibleForAlwaysOnGroup(build, id));
- pq.emplace(-(s32)info.vertices.size(), -(s32)lit.s.length(), id);
- }
- vector<u32> long_lits;
- while (!pq.empty()) {
- u32 id = get<2>(pq.top());
- pq.pop();
- UNUSED const rose_literal_id &lit = literals.at(id);
- DEBUG_PRINTF("assigning groups to lit %u (v %zu l %zu)\n", id,
- literal_info[id].vertices.size(), lit.s.length());
-
- u8 group_id = 0;
- rose_group group = ~0ULL;
- for (auto v : getAssociatedVertices(build, id)) {
- rose_group local_group = calcLocalGroup(v, build.g, literal_info,
- small_literal_count);
- group &= local_group;
- if (!group) {
- break;
- }
- }
-
- if (group == ~0ULL) {
- goto boring;
- }
-
- group &= ~((1ULL << min_start_group) - 1); /* ensure the purity of the
- * always_on groups */
- if (!group) {
- goto boring;
- }
-
- group_id = ctz64(group);
-
- /* TODO: fairness */
- DEBUG_PRINTF("picking sibling group %hhd\n", group_id);
- literal_info[id].group_mask = 1ULL << group_id;
- groupCount[group_id]++;
-
- continue;
-
- boring:
- /* long literals will either be stuck in a mega group or spread around
- * depending on availability */
- if (superStrong(lit)) {
- long_lits.push_back(id);
- continue;
- }
-
- // Other literals are assigned to our remaining groups round-robin.
- group_id = counter;
-
- DEBUG_PRINTF("picking boring group %hhd\n", group_id);
- literal_info[id].group_mask = 1ULL << group_id;
- groupCount[group_id]++;
- counter = next_available_group(counter, min_start_group);
- }
-
- /* spread long literals out amongst unused groups if any, otherwise stick
- * them in the always on the group */
-
- if (groupCount[counter]) {
- DEBUG_PRINTF("sticking long literals in the image of the always on\n");
- for (u32 lit_id : long_lits) {
- literal_info[lit_id].group_mask = 1ULL << group_long_lit;
- groupCount[group_long_lit]++;
- }
- } else {
- u32 min_long_counter = counter;
- DEBUG_PRINTF("base long lit group = %u\n", min_long_counter);
- for (u32 lit_id : long_lits) {
- u8 group_id = counter;
- literal_info[lit_id].group_mask = 1ULL << group_id;
- groupCount[group_id]++;
- counter = next_available_group(counter, min_long_counter);
- }
- }
- /* assign delayed literals to the same group as their parent */
- for (u32 id = 0; id < literals.size(); id++) {
- const rose_literal_id &lit = literals.at(id);
-
- if (!lit.delay) {
- continue;
- }
-
- u32 parent = literal_info[id].undelayed_id;
- DEBUG_PRINTF("%u is shadow picking up groups from %u\n", id, parent);
- assert(literal_info[parent].undelayed_id == parent);
- assert(literal_info[parent].group_mask);
- literal_info[id].group_mask = literal_info[parent].group_mask;
- /* don't increment the group count - these don't really exist */
- }
-
- DEBUG_PRINTF("populate group to literal mapping\n");
- for (u32 id = 0; id < literals.size(); id++) {
- rose_group groups = literal_info[id].group_mask;
- while (groups) {
- u32 group_id = findAndClearLSB_64(&groups);
- build.group_to_literal[group_id].insert(id);
- }
- }
-
- /* find how many groups we allocated */
- for (u32 i = 0; i < ROSE_GROUPS_MAX; i++) {
- if (groupCount[i]) {
- build.group_end = max(build.group_end, i + 1);
- }
- }
-}
-
-rose_group RoseBuildImpl::getGroups(RoseVertex v) const {
- rose_group groups = 0;
-
- for (u32 id : g[v].literals) {
- u32 lit_id = literal_info.at(id).undelayed_id;
-
- rose_group mygroups = literal_info[lit_id].group_mask;
- groups |= mygroups;
- }
-
- return groups;
-}
-
-/** \brief Get the groups of the successor literals of a given vertex. */
-rose_group RoseBuildImpl::getSuccGroups(RoseVertex start) const {
- rose_group initialGroups = 0;
-
- for (auto v : adjacent_vertices_range(start, g)) {
- initialGroups |= getGroups(v);
- }
-
- return initialGroups;
-}
-
-/**
- * The groups that a role sets are determined by the union of its successor
- * literals. Requires the literals already have had groups assigned.
- */
-void assignGroupsToRoles(RoseBuildImpl &build) {
- auto &g = build.g;
-
- /* Note: if there is a succ literal in the sidematcher, its successors
- * literals must be added instead */
- for (auto v : vertices_range(g)) {
- if (build.isAnyStart(v)) {
- continue;
- }
-
- const rose_group succ_groups = build.getSuccGroups(v);
- g[v].groups |= succ_groups;
-
- auto ghost_it = build.ghost.find(v);
- if (ghost_it != end(build.ghost)) {
- /* delayed roles need to supply their groups to the ghost role */
- g[ghost_it->second].groups |= succ_groups;
- }
-
- DEBUG_PRINTF("vertex %zu: groups=%llx\n", g[v].index, g[v].groups);
- }
-}
-
-/**
- * \brief Returns a mapping from each graph vertex v to the intersection of the
- * groups switched on by all of the paths leading up to (and including) v from
- * the start vertexes.
- */
-unordered_map<RoseVertex, rose_group>
-getVertexGroupMap(const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
- vector<RoseVertex> v_order;
- v_order.reserve(num_vertices(g));
-
- boost::topological_sort(g, back_inserter(v_order));
-
- unordered_map<RoseVertex, rose_group> vertex_group_map;
- vertex_group_map.reserve(num_vertices(g));
-
- const rose_group initial_groups = build.getInitialGroups();
-
- for (const auto &v : boost::adaptors::reverse(v_order)) {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
-
- if (build.isAnyStart(v)) {
- DEBUG_PRINTF("start vertex, groups=0x%llx\n", initial_groups);
- vertex_group_map.emplace(v, initial_groups);
- continue;
- }
-
- // To get to this vertex, we must have come through a predecessor, and
- // everyone who isn't a start vertex has one.
- assert(in_degree(v, g) > 0);
- rose_group pred_groups = ~rose_group{0};
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- DEBUG_PRINTF("pred %zu\n", g[u].index);
- assert(contains(vertex_group_map, u));
- pred_groups &= vertex_group_map.at(u);
- }
-
- DEBUG_PRINTF("pred_groups=0x%llx\n", pred_groups);
- DEBUG_PRINTF("g[v].groups=0x%llx\n", g[v].groups);
-
- rose_group v_groups = pred_groups | g[v].groups;
- DEBUG_PRINTF("v_groups=0x%llx\n", v_groups);
-
- vertex_group_map.emplace(v, v_groups);
- }
-
- return vertex_group_map;
-}
-
-/**
- * \brief Find the set of groups that can be squashed anywhere in the graph,
- * either by a literal or by a leftfix.
- */
-rose_group getSquashableGroups(const RoseBuildImpl &build) {
- rose_group squashable_groups = 0;
- for (const auto &info : build.literal_info) {
- if (info.squash_group) {
- DEBUG_PRINTF("lit squash mask 0x%llx\n", info.group_mask);
- squashable_groups |= info.group_mask;
- }
- }
- for (const auto &m : build.rose_squash_masks) {
- DEBUG_PRINTF("left squash mask 0x%llx\n", ~m.second);
- squashable_groups |= ~m.second;
- }
-
- DEBUG_PRINTF("squashable groups=0x%llx\n", squashable_groups);
- assert(!(squashable_groups & build.boundary_group_mask));
- return squashable_groups;
-}
-
-/**
- * \brief True if every vertex associated with a group also belongs to
- * lit_info.
- */
-static
-bool coversGroup(const RoseBuildImpl &build,
- const rose_literal_info &lit_info) {
- if (lit_info.vertices.empty()) {
- DEBUG_PRINTF("no vertices - does not cover\n");
- return false;
- }
-
- if (!lit_info.group_mask) {
- DEBUG_PRINTF("no group - does not cover\n");
- return false; /* no group (not a floating lit?) */
- }
-
- assert(popcount64(lit_info.group_mask) == 1);
-
- /* for each lit in group, ensure that vertices are a subset of lit_info's */
- rose_group groups = lit_info.group_mask;
- while (groups) {
- u32 group_id = findAndClearLSB_64(&groups);
- for (u32 id : build.group_to_literal.at(group_id)) {
- DEBUG_PRINTF(" checking against friend %u\n", id);
- if (!is_subset_of(build.literal_info[id].vertices,
- lit_info.vertices)) {
- DEBUG_PRINTF("fail\n");
- return false;
- }
- }
- }
-
- DEBUG_PRINTF("ok\n");
- return true;
-}
-
-static
-bool isGroupSquasher(const RoseBuildImpl &build, const u32 id /* literal id */,
- rose_group forbidden_squash_group) {
- const RoseGraph &g = build.g;
-
- const rose_literal_info &lit_info = build.literal_info.at(id);
-
- DEBUG_PRINTF("checking if %u '%s' is a group squasher %016llx\n", id,
- dumpString(build.literals.at(id).s).c_str(),
- lit_info.group_mask);
-
- if (build.literals.at(id).table == ROSE_EVENT) {
- DEBUG_PRINTF("event literal\n");
- return false;
- }
-
- if (!coversGroup(build, lit_info)) {
- DEBUG_PRINTF("does not cover group\n");
- return false;
- }
-
- if (lit_info.group_mask & forbidden_squash_group) {
- /* probably a delayed lit */
- DEBUG_PRINTF("skipping as involves a forbidden group\n");
- return false;
- }
-
- // Single-vertex, less constrained case than the multiple-vertex one below.
- if (lit_info.vertices.size() == 1) {
- const RoseVertex &v = *lit_info.vertices.begin();
-
- if (build.hasDelayPred(v)) { /* due to rebuild issues */
- return false;
- }
-
- /* there are two ways to be a group squasher:
- * 1) only care about the first accepted match
- * 2) can only match once after a pred match
- *
- * (2) requires analysis of the infix before v and is not implemented,
- * TODO
- */
-
- /* Case 1 */
-
- // Can't squash cases with accepts unless they are all
- // simple-exhaustible.
- if (any_of_in(g[v].reports, [&](ReportID report) {
- return !isSimpleExhaustible(build.rm.getReport(report));
- })) {
- DEBUG_PRINTF("can't squash reporter\n");
- return false;
- }
-
- /* Can't squash cases with a suffix without analysis of the suffix.
- * TODO: look at suffixes */
- if (g[v].suffix) {
- return false;
- }
-
- // Out-edges must have inf max bound, + no other shenanigans */
- for (const auto &e : out_edges_range(v, g)) {
- if (g[e].maxBound != ROSE_BOUND_INF) {
- return false;
- }
-
- if (g[target(e, g)].left) {
- return false; /* is an infix rose trigger, TODO: analysis */
- }
- }
-
- DEBUG_PRINTF("%u is a path 1 group squasher\n", id);
- return true;
-
- /* note: we could also squash the groups of its preds (if nobody else is
- * using them. TODO. */
- }
-
- // Multiple-vertex case
- for (auto v : lit_info.vertices) {
- assert(!build.isAnyStart(v));
-
- // Can't squash cases with accepts
- if (!g[v].reports.empty()) {
- return false;
- }
-
- // Suffixes and leftfixes are out too as first literal may not match
- // for everyone.
- if (!g[v].isBoring()) {
- return false;
- }
-
- /* TODO: checks are solid but we should explain */
- if (build.hasDelayPred(v) || build.hasAnchoredTablePred(v)) {
- return false;
- }
-
- // Out-edges must have inf max bound and not directly lead to another
- // vertex with this group, e.g. 'foobar.*foobar'.
- for (const auto &e : out_edges_range(v, g)) {
- if (g[e].maxBound != ROSE_BOUND_INF) {
- return false;
- }
- RoseVertex t = target(e, g);
-
- if (g[t].left) {
- return false; /* is an infix rose trigger */
- }
-
- for (u32 lit_id : g[t].literals) {
- if (build.literal_info[lit_id].group_mask &
- lit_info.group_mask) {
- return false;
- }
- }
- }
-
- // In-edges must all be dot-stars with no overlap at all, as overlap
- // also causes history to be used.
- /* Different tables are already forbidden by previous checks */
- for (const auto &e : in_edges_range(v, g)) {
- if (!(g[e].minBound == 0 && g[e].maxBound == ROSE_BOUND_INF)) {
- return false;
- }
-
- // Check overlap, if source was a literal.
- RoseVertex u = source(e, g);
- if (build.maxLiteralOverlap(u, v)) {
- return false;
- }
- }
- }
-
- DEBUG_PRINTF("literal %u is a multi-vertex group squasher\n", id);
- return true;
-}
-
-void findGroupSquashers(RoseBuildImpl &build) {
- rose_group forbidden_squash_group = build.boundary_group_mask;
- for (u32 id = 0; id < build.literals.size(); id++) {
- const auto &lit = build.literals.at(id);
- if (lit.delay) {
- forbidden_squash_group |= build.literal_info[id].group_mask;
- }
- }
-
- for (u32 id = 0; id < build.literal_info.size(); id++) {
- if (isGroupSquasher(build, id, forbidden_squash_group)) {
- build.literal_info[id].squash_group = true;
- }
- }
-}
-
-} // namespace ue2
+ return false;
+ }
+
+ if (lit.table == ROSE_ANCHORED || lit.table == ROSE_EVENT) {
+ return false;
+ }
+
+ // If we already have a group applied, skip.
+ if (info.group_mask) {
+ return false;
+ }
+
+ if (info.vertices.empty() && info.delayed_ids.empty()) {
+ DEBUG_PRINTF("literal is good for nothing\n");
+ return false;
+ }
+
+ return true;
+}
+
+static
+rose_group calcLocalGroup(const RoseVertex v, const RoseGraph &g,
+ const deque<rose_literal_info> &literal_info,
+ const bool small_literal_count) {
+ rose_group local_group = 0;
+
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ /* In small cases, ensure that siblings have the same rose parentage to
+ * allow rose squashing. In larger cases, don't do this as groups are
+ * probably too scarce. */
+ for (auto w : adjacent_vertices_range(u, g)) {
+ if (!small_literal_count || g[v].left == g[w].left) {
+ for (u32 lit_id : g[w].literals) {
+ local_group |= literal_info[lit_id].group_mask;
+ }
+ } else {
+ DEBUG_PRINTF("not sibling different mother %zu %zu\n",
+ g[v].index, g[w].index);
+ }
+ }
+ }
+
+ return local_group;
+}
+
+/* group constants */
+#define MAX_LIGHT_LITERAL_CASE 200 /* allow rose to affect group decisions below
+ * this */
+
+static
+flat_set<RoseVertex> getAssociatedVertices(const RoseBuildImpl &build, u32 id) {
+ flat_set<RoseVertex> out;
+ const auto &info = build.literal_info[id];
+ insert(&out, info.vertices);
+ for (const auto &delayed : info.delayed_ids) {
+ insert(&out, build.literal_info[delayed].vertices);
+ }
+ return out;
+}
+
+static
+u32 next_available_group(u32 counter, u32 min_start_group) {
+ counter++;
+ if (counter == ROSE_GROUPS_MAX) {
+ DEBUG_PRINTF("resetting groups\n");
+ counter = min_start_group;
+ }
+
+ return counter;
+}
+
+static
+void allocateGroupForBoundary(RoseBuildImpl &build, u32 group_always_on,
+ map<u8, u32> &groupCount) {
+ /* Boundary reports at zero will always fired and forgotten, no need to
+ * worry about preventing the stream being marked as exhausted */
+ if (build.boundary.report_at_eod.empty()) {
+ return;
+ }
+
+ /* Group based stream exhaustion is only done at stream boundaries */
+ if (!build.cc.streaming) {
+ return;
+ }
+
+ DEBUG_PRINTF("allocating %u as boundary group id\n", group_always_on);
+
+ build.boundary_group_mask = 1ULL << group_always_on;
+ groupCount[group_always_on]++;
+}
+
+static
+void allocateGroupForEvent(RoseBuildImpl &build, u32 group_always_on,
+ map<u8, u32> &groupCount, u32 *counter) {
+ if (build.eod_event_literal_id == MO_INVALID_IDX) {
+ return;
+ }
+
+ /* Group based stream exhaustion is only done at stream boundaries */
+ if (!build.cc.streaming) {
+ return;
+ }
+
+ rose_literal_info &info = build.literal_info[build.eod_event_literal_id];
+
+ if (info.vertices.empty()) {
+ return;
+ }
+
+ bool new_group = !groupCount[group_always_on];
+ for (RoseVertex v : info.vertices) {
+ if (build.g[v].left && !isAnchored(build.g[v].left)) {
+ new_group = false;
+ }
+ }
+
+ u32 group;
+ if (!new_group) {
+ group = group_always_on;
+ } else {
+ group = *counter;
+ *counter += 1;
+ }
+
+ DEBUG_PRINTF("allocating %u as eod event group id\n", *counter);
+ info.group_mask = 1ULL << group;
+ groupCount[group]++;
+}
+
+void assignGroupsToLiterals(RoseBuildImpl &build) {
+ auto &literals = build.literals;
+ auto &literal_info = build.literal_info;
+
+ bool small_literal_count = literal_info.size() <= MAX_LIGHT_LITERAL_CASE;
+
+ map<u8, u32> groupCount; /* group index to number of members */
+
+ u32 counter = 0;
+ u32 group_always_on = 0;
+
+ // First pass: handle always on literals.
+ for (u32 id = 0; id < literals.size(); id++) {
+ const rose_literal_id &lit = literals.at(id);
+ rose_literal_info &info = literal_info[id];
+
+ if (!requires_group_assignment(lit, info)) {
+ continue;
+ }
+
+ // If this literal has a root role, we always have to search for it
+ // anyway, so it goes in the always-on group.
+ /* We could end up squashing it if it is followed by a .* */
+ if (eligibleForAlwaysOnGroup(build, id)) {
+ info.group_mask = 1ULL << group_always_on;
+ groupCount[group_always_on]++;
+ continue;
+ }
+ }
+
+ u32 group_long_lit;
+ if (groupCount[group_always_on]) {
+ DEBUG_PRINTF("%u always on literals\n", groupCount[group_always_on]);
+ group_long_lit = group_always_on;
+ counter++;
+ } else {
+ group_long_lit = counter;
+ counter++;
+ }
+
+ allocateGroupForBoundary(build, group_always_on, groupCount);
+ allocateGroupForEvent(build, group_always_on, groupCount, &counter);
+
+ u32 min_start_group = counter;
+ priority_queue<tuple<s32, s32, u32>> pq;
+
+ // Second pass: the other literals.
+ for (u32 id = 0; id < literals.size(); id++) {
+ const rose_literal_id &lit = literals.at(id);
+ rose_literal_info &info = literal_info[id];
+
+ if (!requires_group_assignment(lit, info)) {
+ continue;
+ }
+
+ assert(!eligibleForAlwaysOnGroup(build, id));
+ pq.emplace(-(s32)info.vertices.size(), -(s32)lit.s.length(), id);
+ }
+ vector<u32> long_lits;
+ while (!pq.empty()) {
+ u32 id = get<2>(pq.top());
+ pq.pop();
+ UNUSED const rose_literal_id &lit = literals.at(id);
+ DEBUG_PRINTF("assigning groups to lit %u (v %zu l %zu)\n", id,
+ literal_info[id].vertices.size(), lit.s.length());
+
+ u8 group_id = 0;
+ rose_group group = ~0ULL;
+ for (auto v : getAssociatedVertices(build, id)) {
+ rose_group local_group = calcLocalGroup(v, build.g, literal_info,
+ small_literal_count);
+ group &= local_group;
+ if (!group) {
+ break;
+ }
+ }
+
+ if (group == ~0ULL) {
+ goto boring;
+ }
+
+ group &= ~((1ULL << min_start_group) - 1); /* ensure the purity of the
+ * always_on groups */
+ if (!group) {
+ goto boring;
+ }
+
+ group_id = ctz64(group);
+
+ /* TODO: fairness */
+ DEBUG_PRINTF("picking sibling group %hhd\n", group_id);
+ literal_info[id].group_mask = 1ULL << group_id;
+ groupCount[group_id]++;
+
+ continue;
+
+ boring:
+ /* long literals will either be stuck in a mega group or spread around
+ * depending on availability */
+ if (superStrong(lit)) {
+ long_lits.push_back(id);
+ continue;
+ }
+
+ // Other literals are assigned to our remaining groups round-robin.
+ group_id = counter;
+
+ DEBUG_PRINTF("picking boring group %hhd\n", group_id);
+ literal_info[id].group_mask = 1ULL << group_id;
+ groupCount[group_id]++;
+ counter = next_available_group(counter, min_start_group);
+ }
+
+ /* spread long literals out amongst unused groups if any, otherwise stick
+ * them in the always on the group */
+
+ if (groupCount[counter]) {
+ DEBUG_PRINTF("sticking long literals in the image of the always on\n");
+ for (u32 lit_id : long_lits) {
+ literal_info[lit_id].group_mask = 1ULL << group_long_lit;
+ groupCount[group_long_lit]++;
+ }
+ } else {
+ u32 min_long_counter = counter;
+ DEBUG_PRINTF("base long lit group = %u\n", min_long_counter);
+ for (u32 lit_id : long_lits) {
+ u8 group_id = counter;
+ literal_info[lit_id].group_mask = 1ULL << group_id;
+ groupCount[group_id]++;
+ counter = next_available_group(counter, min_long_counter);
+ }
+ }
+ /* assign delayed literals to the same group as their parent */
+ for (u32 id = 0; id < literals.size(); id++) {
+ const rose_literal_id &lit = literals.at(id);
+
+ if (!lit.delay) {
+ continue;
+ }
+
+ u32 parent = literal_info[id].undelayed_id;
+ DEBUG_PRINTF("%u is shadow picking up groups from %u\n", id, parent);
+ assert(literal_info[parent].undelayed_id == parent);
+ assert(literal_info[parent].group_mask);
+ literal_info[id].group_mask = literal_info[parent].group_mask;
+ /* don't increment the group count - these don't really exist */
+ }
+
+ DEBUG_PRINTF("populate group to literal mapping\n");
+ for (u32 id = 0; id < literals.size(); id++) {
+ rose_group groups = literal_info[id].group_mask;
+ while (groups) {
+ u32 group_id = findAndClearLSB_64(&groups);
+ build.group_to_literal[group_id].insert(id);
+ }
+ }
+
+ /* find how many groups we allocated */
+ for (u32 i = 0; i < ROSE_GROUPS_MAX; i++) {
+ if (groupCount[i]) {
+ build.group_end = max(build.group_end, i + 1);
+ }
+ }
+}
+
+rose_group RoseBuildImpl::getGroups(RoseVertex v) const {
+ rose_group groups = 0;
+
+ for (u32 id : g[v].literals) {
+ u32 lit_id = literal_info.at(id).undelayed_id;
+
+ rose_group mygroups = literal_info[lit_id].group_mask;
+ groups |= mygroups;
+ }
+
+ return groups;
+}
+
+/** \brief Get the groups of the successor literals of a given vertex. */
+rose_group RoseBuildImpl::getSuccGroups(RoseVertex start) const {
+ rose_group initialGroups = 0;
+
+ for (auto v : adjacent_vertices_range(start, g)) {
+ initialGroups |= getGroups(v);
+ }
+
+ return initialGroups;
+}
+
+/**
+ * The groups that a role sets are determined by the union of its successor
+ * literals. Requires the literals already have had groups assigned.
+ */
+void assignGroupsToRoles(RoseBuildImpl &build) {
+ auto &g = build.g;
+
+ /* Note: if there is a succ literal in the sidematcher, its successors
+ * literals must be added instead */
+ for (auto v : vertices_range(g)) {
+ if (build.isAnyStart(v)) {
+ continue;
+ }
+
+ const rose_group succ_groups = build.getSuccGroups(v);
+ g[v].groups |= succ_groups;
+
+ auto ghost_it = build.ghost.find(v);
+ if (ghost_it != end(build.ghost)) {
+ /* delayed roles need to supply their groups to the ghost role */
+ g[ghost_it->second].groups |= succ_groups;
+ }
+
+ DEBUG_PRINTF("vertex %zu: groups=%llx\n", g[v].index, g[v].groups);
+ }
+}
+
+/**
+ * \brief Returns a mapping from each graph vertex v to the intersection of the
+ * groups switched on by all of the paths leading up to (and including) v from
+ * the start vertexes.
+ */
+unordered_map<RoseVertex, rose_group>
+getVertexGroupMap(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+ vector<RoseVertex> v_order;
+ v_order.reserve(num_vertices(g));
+
+ boost::topological_sort(g, back_inserter(v_order));
+
+ unordered_map<RoseVertex, rose_group> vertex_group_map;
+ vertex_group_map.reserve(num_vertices(g));
+
+ const rose_group initial_groups = build.getInitialGroups();
+
+ for (const auto &v : boost::adaptors::reverse(v_order)) {
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
+
+ if (build.isAnyStart(v)) {
+ DEBUG_PRINTF("start vertex, groups=0x%llx\n", initial_groups);
+ vertex_group_map.emplace(v, initial_groups);
+ continue;
+ }
+
+ // To get to this vertex, we must have come through a predecessor, and
+ // everyone who isn't a start vertex has one.
+ assert(in_degree(v, g) > 0);
+ rose_group pred_groups = ~rose_group{0};
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ DEBUG_PRINTF("pred %zu\n", g[u].index);
+ assert(contains(vertex_group_map, u));
+ pred_groups &= vertex_group_map.at(u);
+ }
+
+ DEBUG_PRINTF("pred_groups=0x%llx\n", pred_groups);
+ DEBUG_PRINTF("g[v].groups=0x%llx\n", g[v].groups);
+
+ rose_group v_groups = pred_groups | g[v].groups;
+ DEBUG_PRINTF("v_groups=0x%llx\n", v_groups);
+
+ vertex_group_map.emplace(v, v_groups);
+ }
+
+ return vertex_group_map;
+}
+
+/**
+ * \brief Find the set of groups that can be squashed anywhere in the graph,
+ * either by a literal or by a leftfix.
+ */
+rose_group getSquashableGroups(const RoseBuildImpl &build) {
+ rose_group squashable_groups = 0;
+ for (const auto &info : build.literal_info) {
+ if (info.squash_group) {
+ DEBUG_PRINTF("lit squash mask 0x%llx\n", info.group_mask);
+ squashable_groups |= info.group_mask;
+ }
+ }
+ for (const auto &m : build.rose_squash_masks) {
+ DEBUG_PRINTF("left squash mask 0x%llx\n", ~m.second);
+ squashable_groups |= ~m.second;
+ }
+
+ DEBUG_PRINTF("squashable groups=0x%llx\n", squashable_groups);
+ assert(!(squashable_groups & build.boundary_group_mask));
+ return squashable_groups;
+}
+
+/**
+ * \brief True if every vertex associated with a group also belongs to
+ * lit_info.
+ */
+static
+bool coversGroup(const RoseBuildImpl &build,
+ const rose_literal_info &lit_info) {
+ if (lit_info.vertices.empty()) {
+ DEBUG_PRINTF("no vertices - does not cover\n");
+ return false;
+ }
+
+ if (!lit_info.group_mask) {
+ DEBUG_PRINTF("no group - does not cover\n");
+ return false; /* no group (not a floating lit?) */
+ }
+
+ assert(popcount64(lit_info.group_mask) == 1);
+
+ /* for each lit in group, ensure that vertices are a subset of lit_info's */
+ rose_group groups = lit_info.group_mask;
+ while (groups) {
+ u32 group_id = findAndClearLSB_64(&groups);
+ for (u32 id : build.group_to_literal.at(group_id)) {
+ DEBUG_PRINTF(" checking against friend %u\n", id);
+ if (!is_subset_of(build.literal_info[id].vertices,
+ lit_info.vertices)) {
+ DEBUG_PRINTF("fail\n");
+ return false;
+ }
+ }
+ }
+
+ DEBUG_PRINTF("ok\n");
+ return true;
+}
+
+static
+bool isGroupSquasher(const RoseBuildImpl &build, const u32 id /* literal id */,
+ rose_group forbidden_squash_group) {
+ const RoseGraph &g = build.g;
+
+ const rose_literal_info &lit_info = build.literal_info.at(id);
+
+ DEBUG_PRINTF("checking if %u '%s' is a group squasher %016llx\n", id,
+ dumpString(build.literals.at(id).s).c_str(),
+ lit_info.group_mask);
+
+ if (build.literals.at(id).table == ROSE_EVENT) {
+ DEBUG_PRINTF("event literal\n");
+ return false;
+ }
+
+ if (!coversGroup(build, lit_info)) {
+ DEBUG_PRINTF("does not cover group\n");
+ return false;
+ }
+
+ if (lit_info.group_mask & forbidden_squash_group) {
+ /* probably a delayed lit */
+ DEBUG_PRINTF("skipping as involves a forbidden group\n");
+ return false;
+ }
+
+ // Single-vertex, less constrained case than the multiple-vertex one below.
+ if (lit_info.vertices.size() == 1) {
+ const RoseVertex &v = *lit_info.vertices.begin();
+
+ if (build.hasDelayPred(v)) { /* due to rebuild issues */
+ return false;
+ }
+
+ /* there are two ways to be a group squasher:
+ * 1) only care about the first accepted match
+ * 2) can only match once after a pred match
+ *
+ * (2) requires analysis of the infix before v and is not implemented,
+ * TODO
+ */
+
+ /* Case 1 */
+
+ // Can't squash cases with accepts unless they are all
+ // simple-exhaustible.
+ if (any_of_in(g[v].reports, [&](ReportID report) {
+ return !isSimpleExhaustible(build.rm.getReport(report));
+ })) {
+ DEBUG_PRINTF("can't squash reporter\n");
+ return false;
+ }
+
+ /* Can't squash cases with a suffix without analysis of the suffix.
+ * TODO: look at suffixes */
+ if (g[v].suffix) {
+ return false;
+ }
+
+ // Out-edges must have inf max bound, + no other shenanigans */
+ for (const auto &e : out_edges_range(v, g)) {
+ if (g[e].maxBound != ROSE_BOUND_INF) {
+ return false;
+ }
+
+ if (g[target(e, g)].left) {
+ return false; /* is an infix rose trigger, TODO: analysis */
+ }
+ }
+
+ DEBUG_PRINTF("%u is a path 1 group squasher\n", id);
+ return true;
+
+ /* note: we could also squash the groups of its preds (if nobody else is
+ * using them. TODO. */
+ }
+
+ // Multiple-vertex case
+ for (auto v : lit_info.vertices) {
+ assert(!build.isAnyStart(v));
+
+ // Can't squash cases with accepts
+ if (!g[v].reports.empty()) {
+ return false;
+ }
+
+ // Suffixes and leftfixes are out too as first literal may not match
+ // for everyone.
+ if (!g[v].isBoring()) {
+ return false;
+ }
+
+ /* TODO: checks are solid but we should explain */
+ if (build.hasDelayPred(v) || build.hasAnchoredTablePred(v)) {
+ return false;
+ }
+
+ // Out-edges must have inf max bound and not directly lead to another
+ // vertex with this group, e.g. 'foobar.*foobar'.
+ for (const auto &e : out_edges_range(v, g)) {
+ if (g[e].maxBound != ROSE_BOUND_INF) {
+ return false;
+ }
+ RoseVertex t = target(e, g);
+
+ if (g[t].left) {
+ return false; /* is an infix rose trigger */
+ }
+
+ for (u32 lit_id : g[t].literals) {
+ if (build.literal_info[lit_id].group_mask &
+ lit_info.group_mask) {
+ return false;
+ }
+ }
+ }
+
+ // In-edges must all be dot-stars with no overlap at all, as overlap
+ // also causes history to be used.
+ /* Different tables are already forbidden by previous checks */
+ for (const auto &e : in_edges_range(v, g)) {
+ if (!(g[e].minBound == 0 && g[e].maxBound == ROSE_BOUND_INF)) {
+ return false;
+ }
+
+ // Check overlap, if source was a literal.
+ RoseVertex u = source(e, g);
+ if (build.maxLiteralOverlap(u, v)) {
+ return false;
+ }
+ }
+ }
+
+ DEBUG_PRINTF("literal %u is a multi-vertex group squasher\n", id);
+ return true;
+}
+
+void findGroupSquashers(RoseBuildImpl &build) {
+ rose_group forbidden_squash_group = build.boundary_group_mask;
+ for (u32 id = 0; id < build.literals.size(); id++) {
+ const auto &lit = build.literals.at(id);
+ if (lit.delay) {
+ forbidden_squash_group |= build.literal_info[id].group_mask;
+ }
+ }
+
+ for (u32 id = 0; id < build.literal_info.size(); id++) {
+ if (isGroupSquasher(build, id, forbidden_squash_group)) {
+ build.literal_info[id].squash_group = true;
+ }
+ }
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_groups.h b/contrib/libs/hyperscan/src/rose/rose_build_groups.h
index d35080b62e2..ada64b809fe 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_groups.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_groups.h
@@ -1,57 +1,57 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose build: code for analysing literal groups.
- */
-
-#ifndef ROSE_BUILD_GROUPS_H
-#define ROSE_BUILD_GROUPS_H
-
-#include "rose_build_impl.h"
-
-#include <unordered_map>
-
-namespace ue2 {
-
-std::unordered_map<RoseVertex, rose_group>
-getVertexGroupMap(const RoseBuildImpl &build);
-
-rose_group getSquashableGroups(const RoseBuildImpl &build);
-
-void assignGroupsToLiterals(RoseBuildImpl &build);
-
-void assignGroupsToRoles(RoseBuildImpl &build);
-
-void findGroupSquashers(RoseBuildImpl &build);
-
-} // namespace ue2
-
-#endif // ROSE_BUILD_GROUPS_H
-
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose build: code for analysing literal groups.
+ */
+
+#ifndef ROSE_BUILD_GROUPS_H
+#define ROSE_BUILD_GROUPS_H
+
+#include "rose_build_impl.h"
+
+#include <unordered_map>
+
+namespace ue2 {
+
+std::unordered_map<RoseVertex, rose_group>
+getVertexGroupMap(const RoseBuildImpl &build);
+
+rose_group getSquashableGroups(const RoseBuildImpl &build);
+
+void assignGroupsToLiterals(RoseBuildImpl &build);
+
+void assignGroupsToRoles(RoseBuildImpl &build);
+
+void findGroupSquashers(RoseBuildImpl &build);
+
+} // namespace ue2
+
+#endif // ROSE_BUILD_GROUPS_H
+
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_impl.h b/contrib/libs/hyperscan/src/rose/rose_build_impl.h
index 9ff3c658658..7780848b1b6 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_impl.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_impl.h
@@ -26,32 +26,32 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ROSE_BUILD_IMPL_H
-#define ROSE_BUILD_IMPL_H
+#ifndef ROSE_BUILD_IMPL_H
+#define ROSE_BUILD_IMPL_H
#include "rose_build.h"
#include "rose_build_util.h"
-#include "rose_common.h"
+#include "rose_common.h"
#include "rose_graph.h"
#include "nfa/mpvcompile.h"
#include "nfa/goughcompile.h"
#include "nfa/nfa_internal.h"
#include "nfagraph/ng_holder.h"
#include "nfagraph/ng_revacc.h"
-#include "util/bytecode_ptr.h"
-#include "util/flat_containers.h"
-#include "util/hash.h"
+#include "util/bytecode_ptr.h"
+#include "util/flat_containers.h"
+#include "util/hash.h"
#include "util/order_check.h"
#include "util/queue_index_factory.h"
-#include "util/ue2string.h"
-#include "util/unordered.h"
-#include "util/verify_types.h"
+#include "util/ue2string.h"
+#include "util/unordered.h"
+#include "util/verify_types.h"
#include <deque>
#include <map>
#include <string>
#include <vector>
-#include <boost/variant.hpp>
+#include <boost/variant.hpp>
struct RoseEngine;
@@ -59,36 +59,36 @@ namespace ue2 {
#define ROSE_GROUPS_MAX 64
-#define ROSE_LONG_LITERAL_THRESHOLD_MIN 33
-
-/**
- * \brief The largest allowable "short" literal fragment which can be given to
- * a literal matcher directly.
- *
- * Literals longer than this will be truncated to their suffix and confirmed in
- * the Rose interpreter, either as "medium length" literals which can be
- * confirmed from history, or "long literals" which make use of the streaming
- * table support.
- */
-#define ROSE_SHORT_LITERAL_LEN_MAX 8
-
+#define ROSE_LONG_LITERAL_THRESHOLD_MIN 33
+
+/**
+ * \brief The largest allowable "short" literal fragment which can be given to
+ * a literal matcher directly.
+ *
+ * Literals longer than this will be truncated to their suffix and confirmed in
+ * the Rose interpreter, either as "medium length" literals which can be
+ * confirmed from history, or "long literals" which make use of the streaming
+ * table support.
+ */
+#define ROSE_SHORT_LITERAL_LEN_MAX 8
+
struct BoundaryReports;
struct CastleProto;
struct CompileContext;
class ReportManager;
-class SmallWriteBuild;
+class SmallWriteBuild;
class SomSlotManager;
struct suffix_id {
suffix_id(const RoseSuffixInfo &in)
: g(in.graph.get()), c(in.castle.get()), d(in.rdfa.get()),
- h(in.haig.get()), t(in.tamarama.get()),
- dfa_min_width(in.dfa_min_width),
+ h(in.haig.get()), t(in.tamarama.get()),
+ dfa_min_width(in.dfa_min_width),
dfa_max_width(in.dfa_max_width) {
assert(!g || g->kind == NFA_SUFFIX);
}
bool operator==(const suffix_id &b) const {
- bool rv = g == b.g && c == b.c && h == b.h && d == b.d && t == b.t;
+ bool rv = g == b.g && c == b.c && h == b.h && d == b.d && t == b.t;
assert(!rv || dfa_min_width == b.dfa_min_width);
assert(!rv || dfa_max_width == b.dfa_max_width);
return rv;
@@ -100,7 +100,7 @@ struct suffix_id {
ORDER_CHECK(c);
ORDER_CHECK(d);
ORDER_CHECK(h);
- ORDER_CHECK(t);
+ ORDER_CHECK(t);
return false;
}
@@ -132,22 +132,22 @@ struct suffix_id {
}
return c;
}
- TamaProto *tamarama() {
- if (!d && !h) {
- assert(dfa_min_width == depth(0));
- assert(dfa_max_width == depth::infinity());
- }
- return t;
- }
- const TamaProto *tamarama() const {
- if (!d && !h) {
- assert(dfa_min_width == depth(0));
- assert(dfa_max_width == depth::infinity());
- }
- return t;
- }
-
-
+ TamaProto *tamarama() {
+ if (!d && !h) {
+ assert(dfa_min_width == depth(0));
+ assert(dfa_max_width == depth::infinity());
+ }
+ return t;
+ }
+ const TamaProto *tamarama() const {
+ if (!d && !h) {
+ assert(dfa_min_width == depth(0));
+ assert(dfa_max_width == depth::infinity());
+ }
+ return t;
+ }
+
+
raw_som_dfa *haig() { return h; }
const raw_som_dfa *haig() const { return h; }
raw_dfa *dfa() { return d; }
@@ -160,7 +160,7 @@ private:
CastleProto *c;
raw_dfa *d;
raw_som_dfa *h;
- TamaProto *t;
+ TamaProto *t;
depth dfa_min_width;
depth dfa_max_width;
@@ -185,7 +185,7 @@ struct left_id {
: g(in.graph.get()), c(in.castle.get()), d(in.dfa.get()),
h(in.haig.get()), dfa_min_width(in.dfa_min_width),
dfa_max_width(in.dfa_max_width) {
- assert(!g || !has_managed_reports(*g));
+ assert(!g || !has_managed_reports(*g));
}
bool operator==(const left_id &b) const {
bool rv = g == b.g && c == b.c && h == b.h && d == b.d;
@@ -254,15 +254,15 @@ private:
};
std::set<u32> all_tops(const left_id &r);
-std::set<ReportID> all_reports(const left_id &left);
+std::set<ReportID> all_reports(const left_id &left);
bool isAnchored(const left_id &r);
depth findMinWidth(const left_id &r);
depth findMaxWidth(const left_id &r);
u32 num_tops(const left_id &r);
struct rose_literal_info {
- flat_set<u32> delayed_ids;
- flat_set<RoseVertex> vertices;
+ flat_set<u32> delayed_ids;
+ flat_set<RoseVertex> vertices;
rose_group group_mask = 0;
u32 undelayed_id = MO_INVALID_IDX;
bool squash_group = false;
@@ -290,26 +290,26 @@ struct rose_literal_id {
u32 distinctiveness;
size_t elength(void) const { return s.length() + delay; }
- size_t elength_including_mask(void) const {
- size_t mask_len = msk.size();
- for (u8 c : msk) {
- if (!c) {
- mask_len--;
- } else {
- break;
- }
- }
- return MAX(mask_len, s.length()) + delay;
- }
-
- bool operator==(const rose_literal_id &b) const {
- return s == b.s && msk == b.msk && cmp == b.cmp && table == b.table &&
- delay == b.delay && distinctiveness == b.distinctiveness;
- }
-
- size_t hash() const {
- return hash_all(s, msk, cmp, table, delay, distinctiveness);
- }
+ size_t elength_including_mask(void) const {
+ size_t mask_len = msk.size();
+ for (u8 c : msk) {
+ if (!c) {
+ mask_len--;
+ } else {
+ break;
+ }
+ }
+ return MAX(mask_len, s.length()) + delay;
+ }
+
+ bool operator==(const rose_literal_id &b) const {
+ return s == b.s && msk == b.msk && cmp == b.cmp && table == b.table &&
+ delay == b.delay && distinctiveness == b.distinctiveness;
+ }
+
+ size_t hash() const {
+ return hash_all(s, msk, cmp, table, delay, distinctiveness);
+ }
};
static inline
@@ -323,55 +323,55 @@ bool operator<(const rose_literal_id &a, const rose_literal_id &b) {
return 0;
}
-class RoseLiteralMap {
- /**
- * \brief Main storage for literals.
- *
- * Note that this cannot be a vector, as the present code relies on
- * iterator stability when iterating over this list and adding to it inside
- * the loop.
- */
- std::deque<rose_literal_id> lits;
-
- /** \brief Quick-lookup index from literal -> index in lits. */
- ue2_unordered_map<rose_literal_id, u32> lits_index;
-
-public:
- std::pair<u32, bool> insert(const rose_literal_id &lit) {
- auto it = lits_index.find(lit);
- if (it != lits_index.end()) {
- return {it->second, false};
- }
- u32 id = verify_u32(lits.size());
- lits.push_back(lit);
- lits_index.emplace(lit, id);
- return {id, true};
- }
-
- // Erase the last num elements.
- void erase_back(size_t num) {
- assert(num <= lits.size());
- for (size_t i = 0; i < num; i++) {
- lits_index.erase(lits.back());
- lits.pop_back();
- }
- assert(lits.size() == lits_index.size());
- }
-
- const rose_literal_id &at(u32 id) const {
- assert(id < lits.size());
- return lits.at(id);
- }
-
- using const_iterator = decltype(lits)::const_iterator;
- const_iterator begin() const { return lits.begin(); }
- const_iterator end() const { return lits.end(); }
-
- size_t size() const {
- return lits.size();
- }
-};
-
+class RoseLiteralMap {
+ /**
+ * \brief Main storage for literals.
+ *
+ * Note that this cannot be a vector, as the present code relies on
+ * iterator stability when iterating over this list and adding to it inside
+ * the loop.
+ */
+ std::deque<rose_literal_id> lits;
+
+ /** \brief Quick-lookup index from literal -> index in lits. */
+ ue2_unordered_map<rose_literal_id, u32> lits_index;
+
+public:
+ std::pair<u32, bool> insert(const rose_literal_id &lit) {
+ auto it = lits_index.find(lit);
+ if (it != lits_index.end()) {
+ return {it->second, false};
+ }
+ u32 id = verify_u32(lits.size());
+ lits.push_back(lit);
+ lits_index.emplace(lit, id);
+ return {id, true};
+ }
+
+ // Erase the last num elements.
+ void erase_back(size_t num) {
+ assert(num <= lits.size());
+ for (size_t i = 0; i < num; i++) {
+ lits_index.erase(lits.back());
+ lits.pop_back();
+ }
+ assert(lits.size() == lits_index.size());
+ }
+
+ const rose_literal_id &at(u32 id) const {
+ assert(id < lits.size());
+ return lits.at(id);
+ }
+
+ using const_iterator = decltype(lits)::const_iterator;
+ const_iterator begin() const { return lits.begin(); }
+ const_iterator end() const { return lits.end(); }
+
+ size_t size() const {
+ return lits.size();
+ }
+};
+
struct simple_anchored_info {
simple_anchored_info(u32 min_b, u32 max_b, const ue2_literal &lit)
: min_bound(min_b), max_bound(max_b), literal(lit) {}
@@ -390,99 +390,99 @@ bool operator<(const simple_anchored_info &a, const simple_anchored_info &b) {
return 0;
}
-struct MpvProto {
- bool empty() const {
- return puffettes.empty() && triggered_puffettes.empty();
+struct MpvProto {
+ bool empty() const {
+ return puffettes.empty() && triggered_puffettes.empty();
}
- void reset() {
- puffettes.clear();
- triggered_puffettes.clear();
+ void reset() {
+ puffettes.clear();
+ triggered_puffettes.clear();
}
- std::vector<raw_puff> puffettes;
- std::vector<raw_puff> triggered_puffettes;
-};
+ std::vector<raw_puff> puffettes;
+ std::vector<raw_puff> triggered_puffettes;
+};
+
+struct OutfixInfo {
+ template<class T>
+ explicit OutfixInfo(std::unique_ptr<T> x) : proto(std::move(x)) {}
+
+ explicit OutfixInfo(MpvProto mpv_in) : proto(std::move(mpv_in)) {}
-struct OutfixInfo {
- template<class T>
- explicit OutfixInfo(std::unique_ptr<T> x) : proto(std::move(x)) {}
-
- explicit OutfixInfo(MpvProto mpv_in) : proto(std::move(mpv_in)) {}
-
u32 get_queue(QueueIndexFactory &qif);
- u32 get_queue() const {
- assert(queue != ~0U);
- return queue;
- }
-
+ u32 get_queue() const {
+ assert(queue != ~0U);
+ return queue;
+ }
+
bool is_nonempty_mpv() const {
- auto *m = boost::get<MpvProto>(&proto);
- return m && !m->empty();
+ auto *m = boost::get<MpvProto>(&proto);
+ return m && !m->empty();
}
bool is_dead() const {
- auto *m = boost::get<MpvProto>(&proto);
- if (m) {
- return m->empty();
- }
- return boost::get<boost::blank>(&proto) != nullptr;
+ auto *m = boost::get<MpvProto>(&proto);
+ if (m) {
+ return m->empty();
+ }
+ return boost::get<boost::blank>(&proto) != nullptr;
}
void clear() {
- proto = boost::blank();
- }
-
- // Convenience accessor functions.
-
- NGHolder *holder() {
- auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
- return up ? up->get() : nullptr;
- }
- raw_dfa *rdfa() {
- auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
- return up ? up->get() : nullptr;
- }
- raw_som_dfa *haig() {
- auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
- return up ? up->get() : nullptr;
- }
- MpvProto *mpv() {
- return boost::get<MpvProto>(&proto);
- }
-
- // Convenience const accessor functions.
-
- const NGHolder *holder() const {
- auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
- return up ? up->get() : nullptr;
- }
- const raw_dfa *rdfa() const {
- auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
- return up ? up->get() : nullptr;
- }
- const raw_som_dfa *haig() const {
- auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
- return up ? up->get() : nullptr;
- }
- const MpvProto *mpv() const {
- return boost::get<MpvProto>(&proto);
- }
-
- /**
- * \brief Variant wrapping the various engine types. If this is
- * boost::blank, it means that this outfix is unused (dead).
- */
- boost::variant<
- boost::blank,
- std::unique_ptr<NGHolder>,
- std::unique_ptr<raw_dfa>,
- std::unique_ptr<raw_som_dfa>,
- MpvProto> proto = boost::blank();
-
+ proto = boost::blank();
+ }
+
+ // Convenience accessor functions.
+
+ NGHolder *holder() {
+ auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ raw_dfa *rdfa() {
+ auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ raw_som_dfa *haig() {
+ auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ MpvProto *mpv() {
+ return boost::get<MpvProto>(&proto);
+ }
+
+ // Convenience const accessor functions.
+
+ const NGHolder *holder() const {
+ auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ const raw_dfa *rdfa() const {
+ auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ const raw_som_dfa *haig() const {
+ auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
+ return up ? up->get() : nullptr;
+ }
+ const MpvProto *mpv() const {
+ return boost::get<MpvProto>(&proto);
+ }
+
+ /**
+ * \brief Variant wrapping the various engine types. If this is
+ * boost::blank, it means that this outfix is unused (dead).
+ */
+ boost::variant<
+ boost::blank,
+ std::unique_ptr<NGHolder>,
+ std::unique_ptr<raw_dfa>,
+ std::unique_ptr<raw_som_dfa>,
+ MpvProto> proto = boost::blank();
+
RevAccInfo rev_info;
u32 maxBAWidth = 0; //!< max bi-anchored width
- depth minWidth{depth::infinity()};
- depth maxWidth{0};
+ depth minWidth{depth::infinity()};
+ depth maxWidth{0};
u64a maxOffset = 0;
bool in_sbmatcher = false; //!< handled by small-block matcher.
@@ -495,16 +495,16 @@ std::set<ReportID> all_reports(const OutfixInfo &outfix);
// Concrete impl class
class RoseBuildImpl : public RoseBuild {
public:
- RoseBuildImpl(ReportManager &rm, SomSlotManager &ssm, SmallWriteBuild &smwr,
+ RoseBuildImpl(ReportManager &rm, SomSlotManager &ssm, SmallWriteBuild &smwr,
const CompileContext &cc, const BoundaryReports &boundary);
~RoseBuildImpl() override;
// Adds a single literal.
void add(bool anchored, bool eod, const ue2_literal &lit,
- const flat_set<ReportID> &ids) override;
+ const flat_set<ReportID> &ids) override;
- bool addRose(const RoseInGraph &ig, bool prefilter) override;
+ bool addRose(const RoseInGraph &ig, bool prefilter) override;
bool addSombeRose(const RoseInGraph &ig) override;
bool addOutfix(const NGHolder &h) override;
@@ -515,20 +515,20 @@ public:
// Returns true if we were able to add it as a mask
bool add(bool anchored, const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports) override;
+ const flat_set<ReportID> &reports) override;
bool addAnchoredAcyclic(const NGHolder &graph) override;
bool validateMask(const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool anchored,
+ const flat_set<ReportID> &reports, bool anchored,
bool eod) const override;
void addMask(const std::vector<CharReach> &mask,
- const flat_set<ReportID> &reports, bool anchored,
+ const flat_set<ReportID> &reports, bool anchored,
bool eod) override;
// Construct a runtime implementation.
- bytecode_ptr<RoseEngine> buildRose(u32 minWidth) override;
- bytecode_ptr<RoseEngine> buildFinalEngine(u32 minWidth);
+ bytecode_ptr<RoseEngine> buildRose(u32 minWidth) override;
+ bytecode_ptr<RoseEngine> buildFinalEngine(u32 minWidth);
void setSom() override { hasSom = true; }
@@ -625,8 +625,8 @@ public:
* overlap calculation in history assignment. */
std::map<u32, rose_literal_id> anchoredLitSuffix;
- ue2_unordered_set<left_id> transient;
- ue2_unordered_map<left_id, rose_group> rose_squash_masks;
+ ue2_unordered_set<left_id> transient;
+ ue2_unordered_map<left_id, rose_group> rose_squash_masks;
std::vector<OutfixInfo> outfixes;
@@ -639,33 +639,33 @@ public:
u32 max_rose_anchored_floating_overlap;
- rose_group boundary_group_mask = 0;
+ rose_group boundary_group_mask = 0;
QueueIndexFactory qif;
ReportManager &rm;
SomSlotManager &ssm;
- SmallWriteBuild &smwr;
+ SmallWriteBuild &smwr;
const BoundaryReports &boundary;
private:
ReportID next_nfa_report;
};
-size_t calcLongLitThreshold(const RoseBuildImpl &build,
- const size_t historyRequired);
-
+size_t calcLongLitThreshold(const RoseBuildImpl &build,
+ const size_t historyRequired);
+
// Free functions, in rose_build_misc.cpp
bool hasAnchHistorySucc(const RoseGraph &g, RoseVertex v);
bool hasLastByteHistorySucc(const RoseGraph &g, RoseVertex v);
size_t maxOverlap(const rose_literal_id &a, const rose_literal_id &b);
-ue2_literal findNonOverlappingTail(const std::set<ue2_literal> &lits,
- const ue2_literal &s);
+ue2_literal findNonOverlappingTail(const std::set<ue2_literal> &lits,
+ const ue2_literal &s);
#ifndef NDEBUG
-bool roseHasTops(const RoseBuildImpl &build, RoseVertex v);
-bool hasOrphanedTops(const RoseBuildImpl &build);
+bool roseHasTops(const RoseBuildImpl &build, RoseVertex v);
+bool hasOrphanedTops(const RoseBuildImpl &build);
#endif
u64a findMaxOffset(const std::set<ReportID> &reports, const ReportManager &rm);
@@ -676,10 +676,10 @@ u64a findMaxOffset(const std::set<ReportID> &reports, const ReportManager &rm);
void normaliseLiteralMask(const ue2_literal &s, std::vector<u8> &msk,
std::vector<u8> &cmp);
-u32 findMinOffset(const RoseBuildImpl &build, u32 lit_id);
-u32 findMaxOffset(const RoseBuildImpl &build, u32 lit_id);
+u32 findMinOffset(const RoseBuildImpl &build, u32 lit_id);
+u32 findMaxOffset(const RoseBuildImpl &build, u32 lit_id);
-bool canEagerlyReportAtEod(const RoseBuildImpl &build, const RoseEdge &e);
+bool canEagerlyReportAtEod(const RoseBuildImpl &build, const RoseEdge &e);
#ifndef NDEBUG
bool canImplementGraphs(const RoseBuildImpl &tbi);
@@ -687,22 +687,22 @@ bool canImplementGraphs(const RoseBuildImpl &tbi);
} // namespace ue2
-namespace std {
-
-template<>
-struct hash<ue2::left_id> {
- size_t operator()(const ue2::left_id &l) const {
- return l.hash();
- }
-};
-
-template<>
-struct hash<ue2::suffix_id> {
- size_t operator()(const ue2::suffix_id &s) const {
- return s.hash();
- }
-};
-
-} // namespace std
-
-#endif /* ROSE_BUILD_IMPL_H */
+namespace std {
+
+template<>
+struct hash<ue2::left_id> {
+ size_t operator()(const ue2::left_id &l) const {
+ return l.hash();
+ }
+};
+
+template<>
+struct hash<ue2::suffix_id> {
+ size_t operator()(const ue2::suffix_id &s) const {
+ return s.hash();
+ }
+};
+
+} // namespace std
+
+#endif /* ROSE_BUILD_IMPL_H */
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_infix.cpp b/contrib/libs/hyperscan/src/rose/rose_build_infix.cpp
index 1efe27964b7..80e12542360 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_infix.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_infix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,12 +36,12 @@
#include "rose/rose_build_impl.h"
#include "util/container.h"
#include "util/dump_charclass.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/graph.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include "util/ue2string.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <algorithm>
#include <set>
@@ -53,7 +53,7 @@ namespace ue2 {
static
bool couldEndLiteral(const ue2_literal &s, NFAVertex initial,
const NGHolder &h) {
- flat_set<NFAVertex> curr, next;
+ flat_set<NFAVertex> curr, next;
curr.insert(initial);
for (auto it = s.rbegin(), ite = s.rend(); it != ite; ++it) {
@@ -84,10 +84,10 @@ bool couldEndLiteral(const ue2_literal &s, NFAVertex initial,
return true;
}
-using EdgeCache = ue2_unordered_set<pair<NFAVertex, NFAVertex>>;
-
+using EdgeCache = ue2_unordered_set<pair<NFAVertex, NFAVertex>>;
+
static
-void contractVertex(NGHolder &g, NFAVertex v, EdgeCache &all_edges) {
+void contractVertex(NGHolder &g, NFAVertex v, EdgeCache &all_edges) {
for (auto u : inv_adjacent_vertices_range(v, g)) {
if (u == v) {
continue; // self-edge
@@ -111,9 +111,9 @@ void contractVertex(NGHolder &g, NFAVertex v, EdgeCache &all_edges) {
}
static
-u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &lits) {
+u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &lits) {
DEBUG_PRINTF("h=%p, %zu literals\n", &h, lits.size());
- //dumpGraph("infix.dot", h);
+ //dumpGraph("infix.dot", h);
// Indices of vertices that could terminate any of the literals in 'lits'.
set<u32> terms;
@@ -147,9 +147,9 @@ u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &lits) {
cloneHolder(g, h);
vector<NFAVertex> dead;
- // The set of all edges in the graph is used for existence checks in
- // contractVertex.
- EdgeCache all_edges;
+ // The set of all edges in the graph is used for existence checks in
+ // contractVertex.
+ EdgeCache all_edges;
for (const auto &e : edges_range(g)) {
all_edges.emplace(source(e, g), target(e, g));
}
@@ -167,7 +167,7 @@ u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &lits) {
}
remove_vertices(dead, g);
- //dumpGraph("relaxed.dot", g);
+ //dumpGraph("relaxed.dot", g);
depth maxWidth = findMaxWidth(g);
DEBUG_PRINTF("maxWidth=%s\n", maxWidth.str().c_str());
@@ -261,11 +261,11 @@ u32 findMaxInfixMatches(const left_id &left, const set<ue2_literal> &lits) {
return findMaxInfixMatches(*left.castle(), lits);
}
if (left.graph()) {
- if (!onlyOneTop(*left.graph())) {
- DEBUG_PRINTF("more than one top!n");
- return NO_MATCH_LIMIT;
- }
- return findMaxLiteralMatches(*left.graph(), lits);
+ if (!onlyOneTop(*left.graph())) {
+ DEBUG_PRINTF("more than one top!n");
+ return NO_MATCH_LIMIT;
+ }
+ return findMaxLiteralMatches(*left.graph(), lits);
}
return NO_MATCH_LIMIT;
@@ -282,7 +282,7 @@ void findCountingMiracleInfo(const left_id &left, const vector<u8> &stopTable,
const NGHolder &g = *left.graph();
- auto cyclics = find_vertices_in_cycles(g);
+ auto cyclics = find_vertices_in_cycles(g);
if (!proper_out_degree(g.startDs, g)) {
cyclics.erase(g.startDs);
@@ -290,7 +290,7 @@ void findCountingMiracleInfo(const left_id &left, const vector<u8> &stopTable,
CharReach cyclic_cr;
for (NFAVertex v : cyclics) {
- DEBUG_PRINTF("considering %zu ||=%zu\n", g[v].index,
+ DEBUG_PRINTF("considering %zu ||=%zu\n", g[v].index,
g[v].char_reach.count());
cyclic_cr |= g[v].char_reach;
}
@@ -318,7 +318,7 @@ void findCountingMiracleInfo(const left_id &left, const vector<u8> &stopTable,
lits.insert(ue2_literal(c, false));
}
- u32 count = findMaxLiteralMatches(*left.graph(), lits);
+ u32 count = findMaxLiteralMatches(*left.graph(), lits);
DEBUG_PRINTF("counting miracle %u\n", count + 1);
if (count && count < 50) {
*cm_count = count + 1;
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_instructions.cpp b/contrib/libs/hyperscan/src/rose/rose_build_instructions.cpp
index 3dbbe747c2e..f96221b2479 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_instructions.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_instructions.cpp
@@ -1,167 +1,167 @@
-/*
+/*
* Copyright (c) 2017-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_instructions.h"
-
-#include "rose_build_engine_blob.h"
-#include "util/multibit_build.h"
-#include "util/verify_types.h"
-
-#include <algorithm>
-
-using namespace std;
-
-namespace ue2 {
-/* Destructors to avoid weak vtables. */
-
-RoseInstruction::~RoseInstruction() = default;
-RoseInstrCatchUp::~RoseInstrCatchUp() = default;
-RoseInstrCatchUpMpv::~RoseInstrCatchUpMpv() = default;
-RoseInstrSomZero::~RoseInstrSomZero() = default;
-RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default;
-RoseInstrMatcherEod::~RoseInstrMatcherEod() = default;
-RoseInstrEnd::~RoseInstrEnd() = default;
-RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default;
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_instructions.h"
+
+#include "rose_build_engine_blob.h"
+#include "util/multibit_build.h"
+#include "util/verify_types.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace ue2 {
+/* Destructors to avoid weak vtables. */
+
+RoseInstruction::~RoseInstruction() = default;
+RoseInstrCatchUp::~RoseInstrCatchUp() = default;
+RoseInstrCatchUpMpv::~RoseInstrCatchUpMpv() = default;
+RoseInstrSomZero::~RoseInstrSomZero() = default;
+RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default;
+RoseInstrMatcherEod::~RoseInstrMatcherEod() = default;
+RoseInstrEnd::~RoseInstrEnd() = default;
+RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default;
RoseInstrFlushCombination::~RoseInstrFlushCombination() = default;
RoseInstrLastFlushCombination::~RoseInstrLastFlushCombination() = default;
-
-using OffsetMap = RoseInstruction::OffsetMap;
-
-static
-u32 calc_jump(const OffsetMap &offset_map, const RoseInstruction *from,
- const RoseInstruction *to) {
- DEBUG_PRINTF("computing relative jump from %p to %p\n", from, to);
- assert(from && contains(offset_map, from));
- assert(to && contains(offset_map, to));
-
- u32 from_offset = offset_map.at(from);
- u32 to_offset = offset_map.at(to);
- DEBUG_PRINTF("offsets: %u -> %u\n", from_offset, to_offset);
- assert(from_offset <= to_offset);
-
- return to_offset - from_offset;
-}
-
-void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
- inst->anch_id = anch_id;
- inst->done_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->min_offset = min_offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
-}
-
-void RoseInstrCheckOnlyEod::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckBounds::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->min_bound = min_bound;
- inst->max_bound = max_bound;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckNotHandled::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->key = key;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckSingleLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->offset = offset;
- inst->reach_index = blob.lookaround_cache.get_offset_of({reach}, blob);
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- vector<s8> look_offsets;
- vector<CharReach> reaches;
- for (const auto &le : look) {
- look_offsets.push_back(le.offset);
- reaches.push_back(le.reach);
- }
- inst->look_index = blob.lookaround_cache.get_offset_of(look_offsets, blob);
- inst->reach_index = blob.lookaround_cache.get_offset_of(reaches, blob);
- inst->count = verify_u32(look.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMask::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->and_mask = and_mask;
- inst->cmp_mask = cmp_mask;
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMask32::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(and_mask), end(and_mask), inst->and_mask);
- copy(begin(cmp_mask), end(cmp_mask), inst->cmp_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
+
+using OffsetMap = RoseInstruction::OffsetMap;
+
+static
+u32 calc_jump(const OffsetMap &offset_map, const RoseInstruction *from,
+ const RoseInstruction *to) {
+ DEBUG_PRINTF("computing relative jump from %p to %p\n", from, to);
+ assert(from && contains(offset_map, from));
+ assert(to && contains(offset_map, to));
+
+ u32 from_offset = offset_map.at(from);
+ u32 to_offset = offset_map.at(to);
+ DEBUG_PRINTF("offsets: %u -> %u\n", from_offset, to_offset);
+ assert(from_offset <= to_offset);
+
+ return to_offset - from_offset;
+}
+
+void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+ inst->anch_id = anch_id;
+ inst->done_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->min_offset = min_offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrCheckOnlyEod::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckBounds::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->min_bound = min_bound;
+ inst->max_bound = max_bound;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckNotHandled::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->key = key;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckSingleLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->offset = offset;
+ inst->reach_index = blob.lookaround_cache.get_offset_of({reach}, blob);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ vector<s8> look_offsets;
+ vector<CharReach> reaches;
+ for (const auto &le : look) {
+ look_offsets.push_back(le.offset);
+ reaches.push_back(le.reach);
+ }
+ inst->look_index = blob.lookaround_cache.get_offset_of(look_offsets, blob);
+ inst->reach_index = blob.lookaround_cache.get_offset_of(reaches, blob);
+ inst->count = verify_u32(look.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMask::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->and_mask = and_mask;
+ inst->cmp_mask = cmp_mask;
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMask32::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(and_mask), end(and_mask), inst->and_mask);
+ copy(begin(cmp_mask), end(cmp_mask), inst->cmp_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
void RoseInstrCheckMask64::write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const {
RoseInstrBase::write(dest, blob, offset_map);
@@ -173,71 +173,71 @@ void RoseInstrCheckMask64::write(void *dest, RoseEngineBlob &blob,
inst->fail_jump = calc_jump(offset_map, this, target);
}
-void RoseInstrCheckByte::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->and_mask = and_mask;
- inst->cmp_mask = cmp_mask;
- inst->negation = negation;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti16x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti32x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
-
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti16x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti32x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask_hi), end(bucket_select_mask_hi),
- inst->bucket_select_mask_hi);
- copy(begin(bucket_select_mask_lo), end(bucket_select_mask_lo),
- inst->bucket_select_mask_lo);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
+void RoseInstrCheckByte::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->and_mask = and_mask;
+ inst->cmp_mask = cmp_mask;
+ inst->negation = negation;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti16x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti32x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti16x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti32x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask_hi), end(bucket_select_mask_hi),
+ inst->bucket_select_mask_hi);
+ copy(begin(bucket_select_mask_lo), end(bucket_select_mask_lo),
+ inst->bucket_select_mask_lo);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
void RoseInstrCheckShufti64x8::write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const {
RoseInstrBase::write(dest, blob, offset_map);
@@ -268,432 +268,432 @@ void RoseInstrCheckShufti64x16::write(void *dest, RoseEngineBlob &blob,
inst->fail_jump = calc_jump(offset_map, this, target);
}
-void RoseInstrCheckInfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
- inst->report = report;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckPrefix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
- inst->report = report;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->delay = delay;
- inst->index = index;
-}
-
-void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->distance = distance;
-}
-
-void RoseInstrSomLeftfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
-}
-
-void RoseInstrSomFromReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrTriggerInfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->cancel = cancel;
- inst->queue = queue;
- inst->event = event;
-}
-
-void RoseInstrTriggerSuffix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->event = event;
-}
-
-void RoseInstrDedupe::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrDedupeSom::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrReportChain::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->event = event;
- inst->top_squash_distance = top_squash_distance;
-}
-
-void RoseInstrReportSomInt::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrReportSomAware::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
-}
-
-void RoseInstrReportExhaust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->ekey = ekey;
-}
-
-void RoseInstrReportSom::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
-}
-
-void RoseInstrReportSomExhaust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->ekey = ekey;
-}
-
-void RoseInstrDedupeAndReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrFinalReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
-}
-
-void RoseInstrCheckExhausted::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->ekey = ekey;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMinLength::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->end_adj = end_adj;
- inst->min_length = min_length;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrSetState::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->index = index;
-}
-
-void RoseInstrSetGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
-}
-
-void RoseInstrSquashGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
-}
-
-void RoseInstrCheckState::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->index = index;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
-
- // Resolve and write the multibit sparse iterator and the jump table.
- vector<u32> keys;
- vector<u32> jump_offsets;
- for (const auto &jump : jump_table) {
- keys.push_back(jump.first);
- assert(contains(offset_map, jump.second));
- jump_offsets.push_back(offset_map.at(jump.second));
- }
-
- auto iter = mmbBuildSparseIterator(keys, num_keys);
- assert(!iter.empty());
- inst->iter_offset = blob.add_iterator(iter);
- inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
-
- // Store offsets for corresponding SPARSE_ITER_NEXT operations.
- is_written = true;
- iter_offset = inst->iter_offset;
- jump_table_offset = inst->jump_table;
-}
-
-void RoseInstrSparseIterNext::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->state = state;
- inst->fail_jump = calc_jump(offset_map, this, target);
-
- // Use the same sparse iterator and jump table as the SPARSE_ITER_BEGIN
- // instruction.
- assert(begin);
- assert(contains(offset_map, begin));
- assert(begin->is_written);
- inst->iter_offset = begin->iter_offset;
- inst->jump_table = begin->jump_table_offset;
-}
-
-void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
-
- // Write the multibit sparse iterator.
- auto iter = mmbBuildSparseIterator(keys, num_keys);
- assert(!iter.empty());
- inst->iter_offset = blob.add_iterator(iter);
-}
-
-void RoseInstrEnginesEod::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->iter_offset = iter_offset;
-}
-
-void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrMultipathLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- auto &cache = blob.lookaround_cache;
- vector<s8> look_offsets;
- vector<vector<CharReach>> reaches;
- for (const auto &vle : multi_look) {
- reaches.push_back({});
- bool done_offset = false;
-
- for (const auto &le : vle) {
- reaches.back().push_back(le.reach);
-
- /* empty reaches don't have valid offsets */
- if (!done_offset && le.reach.any()) {
- look_offsets.push_back(le.offset);
- done_offset = true;
- }
- }
- }
- inst->look_index = cache.get_offset_of(look_offsets, blob);
- inst->reach_index = cache.get_offset_of(reaches, blob);
- inst->count = verify_u32(multi_look.size());
- inst->last_start = last_start;
- copy(begin(start_mask), end(start_mask), inst->start_mask);
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMultipathShufti16x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
- copy(begin(bucket_select_mask), begin(bucket_select_mask) + 16,
- inst->bucket_select_mask);
- copy(begin(data_select_mask), begin(data_select_mask) + 16,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMultipathShufti32x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
- copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
- copy(begin(bucket_select_mask), begin(bucket_select_mask) + 32,
- inst->bucket_select_mask);
- copy(begin(data_select_mask), begin(data_select_mask) + 32,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMultipathShufti32x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask_hi), begin(bucket_select_mask_hi) + 32,
- inst->bucket_select_mask_hi);
- copy(begin(bucket_select_mask_lo), begin(bucket_select_mask_lo) + 32,
- inst->bucket_select_mask_lo);
- copy(begin(data_select_mask), begin(data_select_mask) + 32,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
- copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- copy(begin(data_select_mask), end(data_select_mask),
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrIncludedJump::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->child_offset = child_offset;
- inst->squash = squash;
-}
-
+void RoseInstrCheckInfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+ inst->report = report;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckPrefix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+ inst->report = report;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->delay = delay;
+ inst->index = index;
+}
+
+void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->distance = distance;
+}
+
+void RoseInstrSomLeftfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+}
+
+void RoseInstrSomFromReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrTriggerInfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->cancel = cancel;
+ inst->queue = queue;
+ inst->event = event;
+}
+
+void RoseInstrTriggerSuffix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->event = event;
+}
+
+void RoseInstrDedupe::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrDedupeSom::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrReportChain::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->event = event;
+ inst->top_squash_distance = top_squash_distance;
+}
+
+void RoseInstrReportSomInt::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrReportSomAware::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrReportExhaust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->ekey = ekey;
+}
+
+void RoseInstrReportSom::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrReportSomExhaust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->ekey = ekey;
+}
+
+void RoseInstrDedupeAndReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrFinalReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrCheckExhausted::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->ekey = ekey;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMinLength::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->end_adj = end_adj;
+ inst->min_length = min_length;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrSetState::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->index = index;
+}
+
+void RoseInstrSetGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrSquashGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrCheckState::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->index = index;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Resolve and write the multibit sparse iterator and the jump table.
+ vector<u32> keys;
+ vector<u32> jump_offsets;
+ for (const auto &jump : jump_table) {
+ keys.push_back(jump.first);
+ assert(contains(offset_map, jump.second));
+ jump_offsets.push_back(offset_map.at(jump.second));
+ }
+
+ auto iter = mmbBuildSparseIterator(keys, num_keys);
+ assert(!iter.empty());
+ inst->iter_offset = blob.add_iterator(iter);
+ inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
+
+ // Store offsets for corresponding SPARSE_ITER_NEXT operations.
+ is_written = true;
+ iter_offset = inst->iter_offset;
+ jump_table_offset = inst->jump_table;
+}
+
+void RoseInstrSparseIterNext::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->state = state;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Use the same sparse iterator and jump table as the SPARSE_ITER_BEGIN
+ // instruction.
+ assert(begin);
+ assert(contains(offset_map, begin));
+ assert(begin->is_written);
+ inst->iter_offset = begin->iter_offset;
+ inst->jump_table = begin->jump_table_offset;
+}
+
+void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Write the multibit sparse iterator.
+ auto iter = mmbBuildSparseIterator(keys, num_keys);
+ assert(!iter.empty());
+ inst->iter_offset = blob.add_iterator(iter);
+}
+
+void RoseInstrEnginesEod::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->iter_offset = iter_offset;
+}
+
+void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrMultipathLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ auto &cache = blob.lookaround_cache;
+ vector<s8> look_offsets;
+ vector<vector<CharReach>> reaches;
+ for (const auto &vle : multi_look) {
+ reaches.push_back({});
+ bool done_offset = false;
+
+ for (const auto &le : vle) {
+ reaches.back().push_back(le.reach);
+
+ /* empty reaches don't have valid offsets */
+ if (!done_offset && le.reach.any()) {
+ look_offsets.push_back(le.offset);
+ done_offset = true;
+ }
+ }
+ }
+ inst->look_index = cache.get_offset_of(look_offsets, blob);
+ inst->reach_index = cache.get_offset_of(reaches, blob);
+ inst->count = verify_u32(multi_look.size());
+ inst->last_start = last_start;
+ copy(begin(start_mask), end(start_mask), inst->start_mask);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti16x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
+ copy(begin(bucket_select_mask), begin(bucket_select_mask) + 16,
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), begin(data_select_mask) + 16,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti32x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
+ copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
+ copy(begin(bucket_select_mask), begin(bucket_select_mask) + 32,
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), begin(data_select_mask) + 32,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti32x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask_hi), begin(bucket_select_mask_hi) + 32,
+ inst->bucket_select_mask_hi);
+ copy(begin(bucket_select_mask_lo), begin(bucket_select_mask_lo) + 32,
+ inst->bucket_select_mask_lo);
+ copy(begin(data_select_mask), begin(data_select_mask) + 32,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
+ copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), end(data_select_mask),
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrIncludedJump::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->child_offset = child_offset;
+ inst->squash = squash;
+}
+
void RoseInstrSetLogical::write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const {
RoseInstrBase::write(dest, blob, offset_map);
auto *inst = static_cast<impl_type *>(dest);
inst->lkey = lkey;
inst->offset_adjust = offset_adjust;
-}
+}
void RoseInstrSetCombination::write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const {
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_instructions.h b/contrib/libs/hyperscan/src/rose/rose_build_instructions.h
index ee2acddd48f..f18f4a47152 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_instructions.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_instructions.h
@@ -1,524 +1,524 @@
-/*
+/*
* Copyright (c) 2017-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Concrete classes for interpreter instructions.
- *
- * Note: this header should only be included in files which need to deal with
- * the details of actual instructions. It is expected that most will only
- * require access to the RoseInstruction API exposed in rose_build_program.h
- */
-
-#ifndef ROSE_BUILD_INSTRUCTIONS_H
-#define ROSE_BUILD_INSTRUCTIONS_H
-
-#include "rose_build_lookaround.h"
-#include "rose_build_program.h"
-#include "util/hash.h"
-#include "util/verify_types.h"
-
-namespace ue2 {
-
-/**
- * \brief Abstract base class representing a single Rose instruction.
- */
-class RoseInstruction {
-public:
- virtual ~RoseInstruction();
-
- /** \brief Opcode used for the instruction in the bytecode. */
- virtual RoseInstructionCode code() const = 0;
-
- /**
- * \brief Simple hash used for program equivalence.
- *
- * Note that pointers (jumps, for example) should not be used when
- * calculating the hash: they will be converted to instruction offsets when
- * compared later.
- */
- virtual size_t hash() const = 0;
-
- /** \brief Length of the bytecode instruction in bytes. */
- virtual size_t byte_length() const = 0;
-
- using OffsetMap = std::unordered_map<const RoseInstruction *, u32>;
-
- /**
- * \brief Writes a concrete implementation of this instruction.
- *
- * Other data that this instruction depends on is written directly into the
- * blob, while the instruction structure itself (of size given by
- * the byte_length() function) is written to dest.
- */
- virtual void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const = 0;
-
- /**
- * \brief Update a target pointer.
- *
- * If this instruction contains any reference to the old target, replace it
- * with the new one.
- */
- virtual void update_target(const RoseInstruction *old_target,
- const RoseInstruction *new_target) = 0;
-
- /**
- * \brief True if these instructions are equivalent within their own
- * programs.
- *
- * Checks that any pointers to other instructions point to the same
- * offsets.
- */
- bool equiv(const RoseInstruction &other, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return equiv_impl(other, offsets, other_offsets);
- }
-
-private:
- virtual bool equiv_impl(const RoseInstruction &other,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const = 0;
-};
-
-/**
- * \brief Templated implementation class to handle boring boilerplate code.
- */
-template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
-class RoseInstrBase : public RoseInstruction {
-protected:
- static constexpr RoseInstructionCode opcode = Opcode;
- using impl_type = ImplType;
-
-public:
- RoseInstructionCode code() const override { return opcode; }
-
- size_t byte_length() const override {
- return sizeof(impl_type);
- }
-
- /**
- * Note: this implementation simply zeroes the destination region and
- * writes in the correct opcode. This is sufficient for trivial
- * instructions, but instructions with data members will want to override
- * it.
- */
- void write(void *dest, RoseEngineBlob &,
- const RoseInstruction::OffsetMap &) const override {
- assert(dest != nullptr);
- assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN));
-
- impl_type *inst = static_cast<impl_type *>(dest);
- memset(inst, 0, sizeof(impl_type));
- inst->code = verify_u8(opcode);
- }
-
-private:
- bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const override {
- const auto *ri_that = dynamic_cast<const RoseInstrType *>(&other);
- if (!ri_that) {
- return false;
- }
- const auto *ri_this = dynamic_cast<const RoseInstrType *>(this);
- assert(ri_this);
- return ri_this->equiv_to(*ri_that, offsets, other_offsets);
- }
-};
-
-template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
-constexpr RoseInstructionCode
- RoseInstrBase<Opcode, ImplType, RoseInstrType>::opcode;
-
-/**
- * \brief Refinement of RoseInstrBase to use for instructions that have
- * just a single target member, called "target".
- */
-template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
-class RoseInstrBaseOneTarget
- : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
-public:
- void update_target(const RoseInstruction *old_target,
- const RoseInstruction *new_target) override {
- RoseInstrType *ri = dynamic_cast<RoseInstrType *>(this);
- assert(ri);
- if (ri->target == old_target) {
- ri->target = new_target;
- }
- }
-};
-
-/**
- * \brief Refinement of RoseInstrBase to use for instructions that have no
- * targets.
- */
-template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
-class RoseInstrBaseNoTargets
- : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
-public:
- void update_target(const RoseInstruction *,
- const RoseInstruction *) override {}
-};
-
-/**
- * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that
- * have no members at all, just an opcode.
- */
-template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
-class RoseInstrBaseTrivial
- : public RoseInstrBaseNoTargets<Opcode, ImplType, RoseInstrType> {
-public:
- virtual bool operator==(const RoseInstrType &) const { return true; }
-
- size_t hash() const override {
- return hash_all(Opcode);
- }
-
- bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &,
- const RoseInstruction::OffsetMap &) const {
- return true;
- }
-};
-
-////
-//// Concrete implementation classes start here.
-////
-
-class RoseInstrAnchoredDelay
- : public RoseInstrBaseOneTarget<ROSE_INSTR_ANCHORED_DELAY,
- ROSE_STRUCT_ANCHORED_DELAY,
- RoseInstrAnchoredDelay> {
-public:
- rose_group groups;
- u32 anch_id;
- const RoseInstruction *target;
-
- RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in,
- const RoseInstruction *target_in)
- : groups(groups_in), anch_id(anch_id_in), target(target_in) {}
-
- bool operator==(const RoseInstrAnchoredDelay &ri) const {
- return groups == ri.groups && anch_id == ri.anch_id
- && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, groups, anch_id);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return groups == ri.groups && anch_id == ri.anch_id
- && offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckLitEarly
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LIT_EARLY,
- ROSE_STRUCT_CHECK_LIT_EARLY,
- RoseInstrCheckLitEarly> {
-public:
- u32 min_offset;
- const RoseInstruction *target;
-
- RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in)
- : min_offset(min_offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckLitEarly &ri) const {
- return min_offset == ri.min_offset && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, min_offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return min_offset == ri.min_offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckGroups
- : public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_GROUPS,
- ROSE_STRUCT_CHECK_GROUPS,
- RoseInstrCheckGroups> {
-public:
- rose_group groups;
-
- explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {}
-
- bool operator==(const RoseInstrCheckGroups &ri) const {
- return groups == ri.groups;
- }
-
- size_t hash() const override {
- return hash_all(opcode, groups);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &,
- const OffsetMap &) const {
- return groups == ri.groups;
- }
-};
-
-class RoseInstrCheckOnlyEod
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_ONLY_EOD,
- ROSE_STRUCT_CHECK_ONLY_EOD,
- RoseInstrCheckOnlyEod> {
-public:
- const RoseInstruction *target;
-
- explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in)
- : target(target_in) {}
-
- bool operator==(const RoseInstrCheckOnlyEod &ri) const {
- return target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckBounds
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BOUNDS,
- ROSE_STRUCT_CHECK_BOUNDS,
- RoseInstrCheckBounds> {
-public:
- u64a min_bound;
- u64a max_bound;
- const RoseInstruction *target;
-
- RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in)
- : min_bound(min), max_bound(max), target(target_in) {}
-
- bool operator==(const RoseInstrCheckBounds &ri) const {
- return min_bound == ri.min_bound && max_bound == ri.max_bound &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, min_bound, max_bound);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return min_bound == ri.min_bound && max_bound == ri.max_bound &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckNotHandled
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_NOT_HANDLED,
- ROSE_STRUCT_CHECK_NOT_HANDLED,
- RoseInstrCheckNotHandled> {
-public:
- u32 key;
- const RoseInstruction *target;
-
- RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in)
- : key(key_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckNotHandled &ri) const {
- return key == ri.key && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, key);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return key == ri.key &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckSingleLookaround
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SINGLE_LOOKAROUND,
- ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND,
- RoseInstrCheckSingleLookaround> {
-public:
- s8 offset;
- CharReach reach;
- const RoseInstruction *target;
-
- RoseInstrCheckSingleLookaround(s8 offset_in, CharReach reach_in,
- const RoseInstruction *target_in)
- : offset(offset_in), reach(std::move(reach_in)), target(target_in) {}
-
- bool operator==(const RoseInstrCheckSingleLookaround &ri) const {
- return offset == ri.offset && reach == ri.reach && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, offset, reach);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckSingleLookaround &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return offset == ri.offset && reach == ri.reach &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckLookaround
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
- ROSE_STRUCT_CHECK_LOOKAROUND,
- RoseInstrCheckLookaround> {
-public:
- std::vector<LookEntry> look;
- const RoseInstruction *target;
-
- RoseInstrCheckLookaround(std::vector<LookEntry> look_in,
- const RoseInstruction *target_in)
- : look(std::move(look_in)), target(target_in) {}
-
- bool operator==(const RoseInstrCheckLookaround &ri) const {
- return look == ri.look && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, look);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckLookaround &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return look == ri.look
- && offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMask
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK,
- ROSE_STRUCT_CHECK_MASK,
- RoseInstrCheckMask> {
-public:
- u64a and_mask;
- u64a cmp_mask;
- u64a neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckMask(u64a and_mask_in, u64a cmp_mask_in, u64a neg_mask_in,
- s32 offset_in, const RoseInstruction *target_in)
- : and_mask(and_mask_in), cmp_mask(cmp_mask_in), neg_mask(neg_mask_in),
- offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMask &ri) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMask32
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_32,
- ROSE_STRUCT_CHECK_MASK_32,
- RoseInstrCheckMask32> {
-public:
- std::array<u8, 32> and_mask;
- std::array<u8, 32> cmp_mask;
- u32 neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckMask32(std::array<u8, 32> and_mask_in,
- std::array<u8, 32> cmp_mask_in, u32 neg_mask_in,
- s32 offset_in, const RoseInstruction *target_in)
- : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)),
- neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMask32 &ri) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Concrete classes for interpreter instructions.
+ *
+ * Note: this header should only be included in files which need to deal with
+ * the details of actual instructions. It is expected that most will only
+ * require access to the RoseInstruction API exposed in rose_build_program.h
+ */
+
+#ifndef ROSE_BUILD_INSTRUCTIONS_H
+#define ROSE_BUILD_INSTRUCTIONS_H
+
+#include "rose_build_lookaround.h"
+#include "rose_build_program.h"
+#include "util/hash.h"
+#include "util/verify_types.h"
+
+namespace ue2 {
+
+/**
+ * \brief Abstract base class representing a single Rose instruction.
+ */
+class RoseInstruction {
+public:
+ virtual ~RoseInstruction();
+
+ /** \brief Opcode used for the instruction in the bytecode. */
+ virtual RoseInstructionCode code() const = 0;
+
+ /**
+ * \brief Simple hash used for program equivalence.
+ *
+ * Note that pointers (jumps, for example) should not be used when
+ * calculating the hash: they will be converted to instruction offsets when
+ * compared later.
+ */
+ virtual size_t hash() const = 0;
+
+ /** \brief Length of the bytecode instruction in bytes. */
+ virtual size_t byte_length() const = 0;
+
+ using OffsetMap = std::unordered_map<const RoseInstruction *, u32>;
+
+ /**
+ * \brief Writes a concrete implementation of this instruction.
+ *
+ * Other data that this instruction depends on is written directly into the
+ * blob, while the instruction structure itself (of size given by
+ * the byte_length() function) is written to dest.
+ */
+ virtual void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const = 0;
+
+ /**
+ * \brief Update a target pointer.
+ *
+ * If this instruction contains any reference to the old target, replace it
+ * with the new one.
+ */
+ virtual void update_target(const RoseInstruction *old_target,
+ const RoseInstruction *new_target) = 0;
+
+ /**
+ * \brief True if these instructions are equivalent within their own
+ * programs.
+ *
+ * Checks that any pointers to other instructions point to the same
+ * offsets.
+ */
+ bool equiv(const RoseInstruction &other, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return equiv_impl(other, offsets, other_offsets);
+ }
+
+private:
+ virtual bool equiv_impl(const RoseInstruction &other,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const = 0;
+};
+
+/**
+ * \brief Templated implementation class to handle boring boilerplate code.
+ */
+template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
+class RoseInstrBase : public RoseInstruction {
+protected:
+ static constexpr RoseInstructionCode opcode = Opcode;
+ using impl_type = ImplType;
+
+public:
+ RoseInstructionCode code() const override { return opcode; }
+
+ size_t byte_length() const override {
+ return sizeof(impl_type);
+ }
+
+ /**
+ * Note: this implementation simply zeroes the destination region and
+ * writes in the correct opcode. This is sufficient for trivial
+ * instructions, but instructions with data members will want to override
+ * it.
+ */
+ void write(void *dest, RoseEngineBlob &,
+ const RoseInstruction::OffsetMap &) const override {
+ assert(dest != nullptr);
+ assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN));
+
+ impl_type *inst = static_cast<impl_type *>(dest);
+ memset(inst, 0, sizeof(impl_type));
+ inst->code = verify_u8(opcode);
+ }
+
+private:
+ bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const override {
+ const auto *ri_that = dynamic_cast<const RoseInstrType *>(&other);
+ if (!ri_that) {
+ return false;
+ }
+ const auto *ri_this = dynamic_cast<const RoseInstrType *>(this);
+ assert(ri_this);
+ return ri_this->equiv_to(*ri_that, offsets, other_offsets);
+ }
+};
+
+template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
+constexpr RoseInstructionCode
+ RoseInstrBase<Opcode, ImplType, RoseInstrType>::opcode;
+
+/**
+ * \brief Refinement of RoseInstrBase to use for instructions that have
+ * just a single target member, called "target".
+ */
+template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
+class RoseInstrBaseOneTarget
+ : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
+public:
+ void update_target(const RoseInstruction *old_target,
+ const RoseInstruction *new_target) override {
+ RoseInstrType *ri = dynamic_cast<RoseInstrType *>(this);
+ assert(ri);
+ if (ri->target == old_target) {
+ ri->target = new_target;
+ }
+ }
+};
+
+/**
+ * \brief Refinement of RoseInstrBase to use for instructions that have no
+ * targets.
+ */
+template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
+class RoseInstrBaseNoTargets
+ : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
+public:
+ void update_target(const RoseInstruction *,
+ const RoseInstruction *) override {}
+};
+
+/**
+ * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that
+ * have no members at all, just an opcode.
+ */
+template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
+class RoseInstrBaseTrivial
+ : public RoseInstrBaseNoTargets<Opcode, ImplType, RoseInstrType> {
+public:
+ virtual bool operator==(const RoseInstrType &) const { return true; }
+
+ size_t hash() const override {
+ return hash_all(Opcode);
+ }
+
+ bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &,
+ const RoseInstruction::OffsetMap &) const {
+ return true;
+ }
+};
+
+////
+//// Concrete implementation classes start here.
+////
+
+class RoseInstrAnchoredDelay
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_ANCHORED_DELAY,
+ ROSE_STRUCT_ANCHORED_DELAY,
+ RoseInstrAnchoredDelay> {
+public:
+ rose_group groups;
+ u32 anch_id;
+ const RoseInstruction *target;
+
+ RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in,
+ const RoseInstruction *target_in)
+ : groups(groups_in), anch_id(anch_id_in), target(target_in) {}
+
+ bool operator==(const RoseInstrAnchoredDelay &ri) const {
+ return groups == ri.groups && anch_id == ri.anch_id
+ && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, groups, anch_id);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return groups == ri.groups && anch_id == ri.anch_id
+ && offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckLitEarly
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LIT_EARLY,
+ ROSE_STRUCT_CHECK_LIT_EARLY,
+ RoseInstrCheckLitEarly> {
+public:
+ u32 min_offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in)
+ : min_offset(min_offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckLitEarly &ri) const {
+ return min_offset == ri.min_offset && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, min_offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return min_offset == ri.min_offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckGroups
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_GROUPS,
+ ROSE_STRUCT_CHECK_GROUPS,
+ RoseInstrCheckGroups> {
+public:
+ rose_group groups;
+
+ explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {}
+
+ bool operator==(const RoseInstrCheckGroups &ri) const {
+ return groups == ri.groups;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, groups);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return groups == ri.groups;
+ }
+};
+
+class RoseInstrCheckOnlyEod
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_ONLY_EOD,
+ ROSE_STRUCT_CHECK_ONLY_EOD,
+ RoseInstrCheckOnlyEod> {
+public:
+ const RoseInstruction *target;
+
+ explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in)
+ : target(target_in) {}
+
+ bool operator==(const RoseInstrCheckOnlyEod &ri) const {
+ return target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckBounds
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BOUNDS,
+ ROSE_STRUCT_CHECK_BOUNDS,
+ RoseInstrCheckBounds> {
+public:
+ u64a min_bound;
+ u64a max_bound;
+ const RoseInstruction *target;
+
+ RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in)
+ : min_bound(min), max_bound(max), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckBounds &ri) const {
+ return min_bound == ri.min_bound && max_bound == ri.max_bound &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, min_bound, max_bound);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return min_bound == ri.min_bound && max_bound == ri.max_bound &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckNotHandled
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_NOT_HANDLED,
+ ROSE_STRUCT_CHECK_NOT_HANDLED,
+ RoseInstrCheckNotHandled> {
+public:
+ u32 key;
+ const RoseInstruction *target;
+
+ RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in)
+ : key(key_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckNotHandled &ri) const {
+ return key == ri.key && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, key);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return key == ri.key &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckSingleLookaround
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SINGLE_LOOKAROUND,
+ ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND,
+ RoseInstrCheckSingleLookaround> {
+public:
+ s8 offset;
+ CharReach reach;
+ const RoseInstruction *target;
+
+ RoseInstrCheckSingleLookaround(s8 offset_in, CharReach reach_in,
+ const RoseInstruction *target_in)
+ : offset(offset_in), reach(std::move(reach_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckSingleLookaround &ri) const {
+ return offset == ri.offset && reach == ri.reach && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, offset, reach);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckSingleLookaround &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return offset == ri.offset && reach == ri.reach &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckLookaround
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
+ ROSE_STRUCT_CHECK_LOOKAROUND,
+ RoseInstrCheckLookaround> {
+public:
+ std::vector<LookEntry> look;
+ const RoseInstruction *target;
+
+ RoseInstrCheckLookaround(std::vector<LookEntry> look_in,
+ const RoseInstruction *target_in)
+ : look(std::move(look_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckLookaround &ri) const {
+ return look == ri.look && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, look);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckLookaround &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return look == ri.look
+ && offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMask
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK,
+ ROSE_STRUCT_CHECK_MASK,
+ RoseInstrCheckMask> {
+public:
+ u64a and_mask;
+ u64a cmp_mask;
+ u64a neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMask(u64a and_mask_in, u64a cmp_mask_in, u64a neg_mask_in,
+ s32 offset_in, const RoseInstruction *target_in)
+ : and_mask(and_mask_in), cmp_mask(cmp_mask_in), neg_mask(neg_mask_in),
+ offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMask &ri) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMask32
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_32,
+ ROSE_STRUCT_CHECK_MASK_32,
+ RoseInstrCheckMask32> {
+public:
+ std::array<u8, 32> and_mask;
+ std::array<u8, 32> cmp_mask;
+ u32 neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMask32(std::array<u8, 32> and_mask_in,
+ std::array<u8, 32> cmp_mask_in, u32 neg_mask_in,
+ s32 offset_in, const RoseInstruction *target_in)
+ : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)),
+ neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMask32 &ri) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
class RoseInstrCheckMask64
: public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_64,
ROSE_STRUCT_CHECK_MASK_64,
@@ -556,225 +556,225 @@ public:
}
};
-class RoseInstrCheckByte
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BYTE,
- ROSE_STRUCT_CHECK_BYTE,
- RoseInstrCheckByte> {
-public:
- u8 and_mask;
- u8 cmp_mask;
- u8 negation;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in,
- s32 offset_in, const RoseInstruction *target_in)
- : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in),
- offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckByte &ri) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- negation == ri.negation && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, and_mask, cmp_mask, negation, offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
- negation == ri.negation && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckShufti16x8
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x8,
- ROSE_STRUCT_CHECK_SHUFTI_16x8,
- RoseInstrCheckShufti16x8> {
-public:
- std::array<u8, 32> nib_mask;
- std::array<u8, 16> bucket_select_mask;
- u32 neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckShufti16x8(std::array<u8, 32> nib_mask_in,
- std::array<u8, 16> bucket_select_mask_in,
- u32 neg_mask_in, s32 offset_in,
- const RoseInstruction *target_in)
- : nib_mask(std::move(nib_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckShufti16x8 &ri) const {
- return nib_mask == ri.nib_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, nib_mask, bucket_select_mask, neg_mask, offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return nib_mask == ri.nib_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckShufti32x8
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x8,
- ROSE_STRUCT_CHECK_SHUFTI_32x8,
- RoseInstrCheckShufti32x8> {
-public:
- std::array<u8, 16> hi_mask;
- std::array<u8, 16> lo_mask;
- std::array<u8, 32> bucket_select_mask;
- u32 neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckShufti32x8(std::array<u8, 16> hi_mask_in,
- std::array<u8, 16> lo_mask_in,
- std::array<u8, 32> bucket_select_mask_in,
- u32 neg_mask_in, s32 offset_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckShufti32x8 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
- offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckShufti16x16
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x16,
- ROSE_STRUCT_CHECK_SHUFTI_16x16,
- RoseInstrCheckShufti16x16> {
-public:
- std::array<u8, 32> hi_mask;
- std::array<u8, 32> lo_mask;
- std::array<u8, 32> bucket_select_mask;
- u32 neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckShufti16x16(std::array<u8, 32> hi_mask_in,
- std::array<u8, 32> lo_mask_in,
- std::array<u8, 32> bucket_select_mask_in,
- u32 neg_mask_in, s32 offset_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckShufti16x16 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
- offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckShufti32x16
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x16,
- ROSE_STRUCT_CHECK_SHUFTI_32x16,
- RoseInstrCheckShufti32x16> {
-public:
- std::array<u8, 32> hi_mask;
- std::array<u8, 32> lo_mask;
- std::array<u8, 32> bucket_select_mask_hi;
- std::array<u8, 32> bucket_select_mask_lo;
- u32 neg_mask;
- s32 offset;
- const RoseInstruction *target;
-
- RoseInstrCheckShufti32x16(std::array<u8, 32> hi_mask_in,
- std::array<u8, 32> lo_mask_in,
- std::array<u8, 32> bucket_select_mask_hi_in,
- std::array<u8, 32> bucket_select_mask_lo_in,
- u32 neg_mask_in, s32 offset_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
- bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
- neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckShufti32x16 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask_hi == ri.bucket_select_mask_hi &&
- bucket_select_mask_lo == ri.bucket_select_mask_lo &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
- bucket_select_mask_lo, neg_mask, offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask_hi == ri.bucket_select_mask_hi &&
- bucket_select_mask_lo == ri.bucket_select_mask_lo &&
- neg_mask == ri.neg_mask && offset == ri.offset &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
+class RoseInstrCheckByte
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BYTE,
+ ROSE_STRUCT_CHECK_BYTE,
+ RoseInstrCheckByte> {
+public:
+ u8 and_mask;
+ u8 cmp_mask;
+ u8 negation;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in,
+ s32 offset_in, const RoseInstruction *target_in)
+ : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in),
+ offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckByte &ri) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ negation == ri.negation && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, and_mask, cmp_mask, negation, offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
+ negation == ri.negation && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckShufti16x8
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x8,
+ ROSE_STRUCT_CHECK_SHUFTI_16x8,
+ RoseInstrCheckShufti16x8> {
+public:
+ std::array<u8, 32> nib_mask;
+ std::array<u8, 16> bucket_select_mask;
+ u32 neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckShufti16x8(std::array<u8, 32> nib_mask_in,
+ std::array<u8, 16> bucket_select_mask_in,
+ u32 neg_mask_in, s32 offset_in,
+ const RoseInstruction *target_in)
+ : nib_mask(std::move(nib_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckShufti16x8 &ri) const {
+ return nib_mask == ri.nib_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, nib_mask, bucket_select_mask, neg_mask, offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return nib_mask == ri.nib_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckShufti32x8
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x8,
+ ROSE_STRUCT_CHECK_SHUFTI_32x8,
+ RoseInstrCheckShufti32x8> {
+public:
+ std::array<u8, 16> hi_mask;
+ std::array<u8, 16> lo_mask;
+ std::array<u8, 32> bucket_select_mask;
+ u32 neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckShufti32x8(std::array<u8, 16> hi_mask_in,
+ std::array<u8, 16> lo_mask_in,
+ std::array<u8, 32> bucket_select_mask_in,
+ u32 neg_mask_in, s32 offset_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckShufti32x8 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
+ offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckShufti16x16
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x16,
+ ROSE_STRUCT_CHECK_SHUFTI_16x16,
+ RoseInstrCheckShufti16x16> {
+public:
+ std::array<u8, 32> hi_mask;
+ std::array<u8, 32> lo_mask;
+ std::array<u8, 32> bucket_select_mask;
+ u32 neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckShufti16x16(std::array<u8, 32> hi_mask_in,
+ std::array<u8, 32> lo_mask_in,
+ std::array<u8, 32> bucket_select_mask_in,
+ u32 neg_mask_in, s32 offset_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckShufti16x16 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
+ offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckShufti32x16
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x16,
+ ROSE_STRUCT_CHECK_SHUFTI_32x16,
+ RoseInstrCheckShufti32x16> {
+public:
+ std::array<u8, 32> hi_mask;
+ std::array<u8, 32> lo_mask;
+ std::array<u8, 32> bucket_select_mask_hi;
+ std::array<u8, 32> bucket_select_mask_lo;
+ u32 neg_mask;
+ s32 offset;
+ const RoseInstruction *target;
+
+ RoseInstrCheckShufti32x16(std::array<u8, 32> hi_mask_in,
+ std::array<u8, 32> lo_mask_in,
+ std::array<u8, 32> bucket_select_mask_hi_in,
+ std::array<u8, 32> bucket_select_mask_lo_in,
+ u32 neg_mask_in, s32 offset_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
+ bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
+ neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckShufti32x16 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask_hi == ri.bucket_select_mask_hi &&
+ bucket_select_mask_lo == ri.bucket_select_mask_lo &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
+ bucket_select_mask_lo, neg_mask, offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask_hi == ri.bucket_select_mask_hi &&
+ bucket_select_mask_lo == ri.bucket_select_mask_lo &&
+ neg_mask == ri.neg_mask && offset == ri.offset &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
class RoseInstrCheckShufti64x8
: public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_64x8,
ROSE_STRUCT_CHECK_SHUFTI_64x8,
@@ -878,1412 +878,1412 @@ public:
}
};
-class RoseInstrCheckInfix
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_INFIX,
- ROSE_STRUCT_CHECK_INFIX,
- RoseInstrCheckInfix> {
-public:
- u32 queue;
- u32 lag;
- ReportID report;
- const RoseInstruction *target;
-
- RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in,
- const RoseInstruction *target_in)
- : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckInfix &ri) const {
- return queue == ri.queue && lag == ri.lag && report == ri.report &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, queue, lag, report);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return queue == ri.queue && lag == ri.lag && report == ri.report &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckPrefix
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_PREFIX,
- ROSE_STRUCT_CHECK_PREFIX,
- RoseInstrCheckPrefix> {
-public:
- u32 queue;
- u32 lag;
- ReportID report;
- const RoseInstruction *target;
-
- RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in,
- const RoseInstruction *target_in)
- : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckPrefix &ri) const {
- return queue == ri.queue && lag == ri.lag && report == ri.report &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, queue, lag, report);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return queue == ri.queue && lag == ri.lag && report == ri.report &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrPushDelayed
- : public RoseInstrBaseNoTargets<ROSE_INSTR_PUSH_DELAYED,
- ROSE_STRUCT_PUSH_DELAYED,
- RoseInstrPushDelayed> {
-public:
- u8 delay;
- u32 index;
-
- RoseInstrPushDelayed(u8 delay_in, u32 index_in)
- : delay(delay_in), index(index_in) {}
-
- bool operator==(const RoseInstrPushDelayed &ri) const {
- return delay == ri.delay && index == ri.index;
- }
-
- size_t hash() const override {
- return hash_all(opcode, delay, index);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &,
- const OffsetMap &) const {
- return delay == ri.delay && index == ri.index;
- }
-};
-
-class RoseInstrCatchUp
- : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP, ROSE_STRUCT_CATCH_UP,
- RoseInstrCatchUp> {
-public:
- ~RoseInstrCatchUp() override;
-};
-
-class RoseInstrCatchUpMpv
- : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP_MPV,
- ROSE_STRUCT_CATCH_UP_MPV,
- RoseInstrCatchUpMpv> {
-public:
- ~RoseInstrCatchUpMpv() override;
-};
-
-class RoseInstrSomAdjust
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_ADJUST,
- ROSE_STRUCT_SOM_ADJUST,
- RoseInstrSomAdjust> {
-public:
- u32 distance;
-
- explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {}
-
- bool operator==(const RoseInstrSomAdjust &ri) const {
- return distance == ri.distance;
- }
-
- size_t hash() const override {
- return hash_all(opcode, distance);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &,
- const OffsetMap &) const {
- return distance == ri.distance;
- }
-};
-
-class RoseInstrSomLeftfix
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_LEFTFIX,
- ROSE_STRUCT_SOM_LEFTFIX,
- RoseInstrSomLeftfix> {
-public:
- u32 queue;
- u32 lag;
-
- RoseInstrSomLeftfix(u32 queue_in, u32 lag_in)
- : queue(queue_in), lag(lag_in) {}
-
- bool operator==(const RoseInstrSomLeftfix &ri) const {
- return queue == ri.queue && lag == ri.lag;
- }
-
- size_t hash() const override {
- return hash_all(opcode, queue, lag);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &,
- const OffsetMap &) const {
- return queue == ri.queue && lag == ri.lag;
- }
-};
-
-class RoseInstrSomFromReport
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_FROM_REPORT,
- ROSE_STRUCT_SOM_FROM_REPORT,
- RoseInstrSomFromReport> {
-public:
- som_operation som;
-
- RoseInstrSomFromReport() {
- std::memset(&som, 0, sizeof(som));
- }
-
- bool operator==(const RoseInstrSomFromReport &ri) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-
- size_t hash() const override {
- return hash_all(opcode, som.type, som.onmatch);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &,
- const OffsetMap &) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-};
-
-class RoseInstrSomZero
- : public RoseInstrBaseTrivial<ROSE_INSTR_SOM_ZERO, ROSE_STRUCT_SOM_ZERO,
- RoseInstrSomZero> {
-public:
- ~RoseInstrSomZero() override;
-};
-
-class RoseInstrTriggerInfix
- : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_INFIX,
- ROSE_STRUCT_TRIGGER_INFIX,
- RoseInstrTriggerInfix> {
-public:
- u8 cancel;
- u32 queue;
- u32 event;
-
- RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in)
- : cancel(cancel_in), queue(queue_in), event(event_in) {}
-
- bool operator==(const RoseInstrTriggerInfix &ri) const {
- return cancel == ri.cancel && queue == ri.queue && event == ri.event;
- }
-
- size_t hash() const override {
- return hash_all(opcode, cancel, queue, event);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &,
- const OffsetMap &) const {
- return cancel == ri.cancel && queue == ri.queue && event == ri.event;
- }
-};
-
-class RoseInstrTriggerSuffix
- : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_SUFFIX,
- ROSE_STRUCT_TRIGGER_SUFFIX,
- RoseInstrTriggerSuffix> {
-public:
- u32 queue;
- u32 event;
-
- RoseInstrTriggerSuffix(u32 queue_in, u32 event_in)
- : queue(queue_in), event(event_in) {}
-
- bool operator==(const RoseInstrTriggerSuffix &ri) const {
- return queue == ri.queue && event == ri.event;
- }
-
- size_t hash() const override {
- return hash_all(opcode, queue, event);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &,
- const OffsetMap &) const {
- return queue == ri.queue && event == ri.event;
- }
-};
-
-class RoseInstrDedupe
- : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE, ROSE_STRUCT_DEDUPE,
- RoseInstrDedupe> {
-public:
- u8 quash_som;
- u32 dkey;
- s32 offset_adjust;
- const RoseInstruction *target;
-
- RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
- const RoseInstruction *target_in)
- : quash_som(quash_som_in), dkey(dkey_in),
- offset_adjust(offset_adjust_in), target(target_in) {}
-
- bool operator==(const RoseInstrDedupe &ri) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- offset_adjust == ri.offset_adjust && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, quash_som, dkey, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- offset_adjust == ri.offset_adjust &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrDedupeSom
- : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_SOM,
- ROSE_STRUCT_DEDUPE_SOM,
- RoseInstrDedupeSom> {
-public:
- u8 quash_som;
- u32 dkey;
- s32 offset_adjust;
- const RoseInstruction *target;
-
- RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
- const RoseInstruction *target_in)
- : quash_som(quash_som_in), dkey(dkey_in),
- offset_adjust(offset_adjust_in), target(target_in) {}
-
- bool operator==(const RoseInstrDedupeSom &ri) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- offset_adjust == ri.offset_adjust && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, quash_som, dkey, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- offset_adjust == ri.offset_adjust &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrReportChain
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_CHAIN,
- ROSE_STRUCT_REPORT_CHAIN,
- RoseInstrReportChain> {
-public:
- u32 event;
- u64a top_squash_distance;
-
- RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in)
- : event(event_in), top_squash_distance(top_squash_distance_in) {}
-
- bool operator==(const RoseInstrReportChain &ri) const {
- return event == ri.event &&
- top_squash_distance == ri.top_squash_distance;
- }
-
- size_t hash() const override {
- return hash_all(opcode, event, top_squash_distance);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &,
- const OffsetMap &) const {
- return event == ri.event &&
- top_squash_distance == ri.top_squash_distance;
- }
-};
-
-class RoseInstrReportSomInt
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_INT,
- ROSE_STRUCT_REPORT_SOM_INT,
- RoseInstrReportSomInt> {
-public:
- som_operation som;
-
- RoseInstrReportSomInt() {
- std::memset(&som, 0, sizeof(som));
- }
-
- bool operator==(const RoseInstrReportSomInt &ri) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-
- size_t hash() const override {
- return hash_all(opcode, som.type, som.onmatch);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &,
- const OffsetMap &) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-};
-
-class RoseInstrReportSomAware
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_AWARE,
- ROSE_STRUCT_REPORT_SOM_AWARE,
- RoseInstrReportSomAware> {
-public:
- som_operation som;
-
- RoseInstrReportSomAware() {
- std::memset(&som, 0, sizeof(som));
- }
-
- bool operator==(const RoseInstrReportSomAware &ri) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-
- size_t hash() const override {
- return hash_all(opcode, som.type, som.onmatch);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &,
- const OffsetMap &) const {
- return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
- }
-};
-
-class RoseInstrReport
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT, ROSE_STRUCT_REPORT,
- RoseInstrReport> {
-public:
- ReportID onmatch;
- s32 offset_adjust;
-
- RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in)
- : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
-
- bool operator==(const RoseInstrReport &ri) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-
- size_t hash() const override {
- return hash_all(opcode, onmatch, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReport &ri, const OffsetMap &,
- const OffsetMap &) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-};
-
-class RoseInstrReportExhaust
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_EXHAUST,
- ROSE_STRUCT_REPORT_EXHAUST,
- RoseInstrReportExhaust> {
-public:
- ReportID onmatch;
- s32 offset_adjust;
- u32 ekey;
-
- RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in,
- u32 ekey_in)
- : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
-
- bool operator==(const RoseInstrReportExhaust &ri) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- ekey == ri.ekey;
- }
-
- size_t hash() const override {
- return hash_all(opcode, onmatch, offset_adjust, ekey);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &,
- const OffsetMap &) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- ekey == ri.ekey;
- }
-};
-
-class RoseInstrReportSom
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM,
- ROSE_STRUCT_REPORT_SOM,
- RoseInstrReportSom> {
-public:
- ReportID onmatch;
- s32 offset_adjust;
-
- RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in)
- : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
-
- bool operator==(const RoseInstrReportSom &ri) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-
- size_t hash() const override {
- return hash_all(opcode, onmatch, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &,
- const OffsetMap &) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-};
-
-class RoseInstrReportSomExhaust
- : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_EXHAUST,
- ROSE_STRUCT_REPORT_SOM_EXHAUST,
- RoseInstrReportSomExhaust> {
-public:
- ReportID onmatch;
- s32 offset_adjust;
- u32 ekey;
-
- RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in,
- u32 ekey_in)
- : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
-
- bool operator==(const RoseInstrReportSomExhaust &ri) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- ekey == ri.ekey;
- }
-
- size_t hash() const override {
- return hash_all(opcode, onmatch, offset_adjust, ekey);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &,
- const OffsetMap &) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- ekey == ri.ekey;
- }
-};
-
-class RoseInstrDedupeAndReport
- : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_AND_REPORT,
- ROSE_STRUCT_DEDUPE_AND_REPORT,
- RoseInstrDedupeAndReport> {
-public:
- u8 quash_som;
- u32 dkey;
- ReportID onmatch;
- s32 offset_adjust;
- const RoseInstruction *target;
-
- RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in,
- s32 offset_adjust_in,
- const RoseInstruction *target_in)
- : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in),
- offset_adjust(offset_adjust_in), target(target_in) {}
-
- bool operator==(const RoseInstrDedupeAndReport &ri) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, quash_som, dkey, onmatch, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return quash_som == ri.quash_som && dkey == ri.dkey &&
- onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrFinalReport
- : public RoseInstrBaseNoTargets<ROSE_INSTR_FINAL_REPORT,
- ROSE_STRUCT_FINAL_REPORT,
- RoseInstrFinalReport> {
-public:
- ReportID onmatch;
- s32 offset_adjust;
-
- RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in)
- : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
-
- bool operator==(const RoseInstrFinalReport &ri) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-
- size_t hash() const override {
- return hash_all(opcode, onmatch, offset_adjust);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &,
- const OffsetMap &) const {
- return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
- }
-};
-
-class RoseInstrCheckExhausted
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_EXHAUSTED,
- ROSE_STRUCT_CHECK_EXHAUSTED,
- RoseInstrCheckExhausted> {
-public:
- u32 ekey;
- const RoseInstruction *target;
-
- RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in)
- : ekey(ekey_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckExhausted &ri) const {
- return ekey == ri.ekey && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, ekey);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return ekey == ri.ekey &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMinLength
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MIN_LENGTH,
- ROSE_STRUCT_CHECK_MIN_LENGTH,
- RoseInstrCheckMinLength> {
-public:
- s32 end_adj;
- u64a min_length;
- const RoseInstruction *target;
-
- RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in,
- const RoseInstruction *target_in)
- : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMinLength &ri) const {
- return end_adj == ri.end_adj && min_length == ri.min_length &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, end_adj, min_length);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return end_adj == ri.end_adj && min_length == ri.min_length &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrSetState
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_STATE, ROSE_STRUCT_SET_STATE,
- RoseInstrSetState> {
-public:
- u32 index;
-
- explicit RoseInstrSetState(u32 index_in) : index(index_in) {}
-
- bool operator==(const RoseInstrSetState &ri) const {
- return index == ri.index;
- }
-
- size_t hash() const override {
- return hash_all(opcode, index);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &,
- const OffsetMap &) const {
- return index == ri.index;
- }
-};
-
-class RoseInstrSetGroups
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_GROUPS,
- ROSE_STRUCT_SET_GROUPS,
- RoseInstrSetGroups> {
-public:
- rose_group groups;
-
- explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {}
-
- bool operator==(const RoseInstrSetGroups &ri) const {
- return groups == ri.groups;
- }
-
- size_t hash() const override {
- return hash_all(opcode, groups);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &,
- const OffsetMap &) const {
- return groups == ri.groups;
- }
-};
-
-class RoseInstrSquashGroups
- : public RoseInstrBaseNoTargets<ROSE_INSTR_SQUASH_GROUPS,
- ROSE_STRUCT_SQUASH_GROUPS,
- RoseInstrSquashGroups> {
-public:
- rose_group groups;
-
- explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {}
-
- bool operator==(const RoseInstrSquashGroups &ri) const {
- return groups == ri.groups;
- }
-
- size_t hash() const override {
- return hash_all(opcode, groups);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &,
- const OffsetMap &) const {
- return groups == ri.groups;
- }
-};
-
-class RoseInstrCheckState
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_STATE,
- ROSE_STRUCT_CHECK_STATE,
- RoseInstrCheckState> {
-public:
- u32 index;
- const RoseInstruction *target;
-
- RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in)
- : index(index_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckState &ri) const {
- return index == ri.index && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, index);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return index == ri.index &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrSparseIterBegin
- : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_BEGIN,
- ROSE_STRUCT_SPARSE_ITER_BEGIN,
- RoseInstrSparseIterBegin> {
-public:
- u32 num_keys; // total number of multibit keys
- std::vector<std::pair<u32, const RoseInstruction *>> jump_table;
- const RoseInstruction *target;
-
- RoseInstrSparseIterBegin(u32 num_keys_in,
- const RoseInstruction *target_in)
- : num_keys(num_keys_in), target(target_in) {}
-
- bool operator==(const RoseInstrSparseIterBegin &ri) const {
- return num_keys == ri.num_keys && jump_table == ri.jump_table &&
- target == ri.target;
- }
-
- size_t hash() const override {
- size_t v = hash_all(opcode, num_keys);
- for (const u32 &key : jump_table | boost::adaptors::map_keys) {
- hash_combine(v, key);
- }
- return v;
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- void update_target(const RoseInstruction *old_target,
- const RoseInstruction *new_target) override {
- if (target == old_target) {
- target = new_target;
- }
- for (auto &jump : jump_table) {
- if (jump.second == old_target) {
- jump.second = new_target;
- }
- }
- }
-
- bool equiv_to(const RoseInstrSparseIterBegin &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- if (iter_offset != ri.iter_offset ||
- offsets.at(target) != other_offsets.at(ri.target)) {
- return false;
- }
- if (jump_table.size() != ri.jump_table.size()) {
- return false;
- }
- auto it1 = jump_table.begin(), it2 = ri.jump_table.begin();
- for (; it1 != jump_table.end(); ++it1, ++it2) {
- if (it1->first != it2->first) {
- return false;
- }
- if (offsets.at(it1->second) != other_offsets.at(it2->second)) {
- return false;
- }
- }
- return true;
- }
-
-private:
- friend class RoseInstrSparseIterNext;
-
- // These variables allow us to use the same multibit iterator and jump
- // table in subsequent SPARSE_ITER_NEXT write() operations.
- mutable bool is_written = false;
- mutable u32 iter_offset = 0;
- mutable u32 jump_table_offset = 0;
-};
-
-class RoseInstrSparseIterNext
- : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_NEXT,
- ROSE_STRUCT_SPARSE_ITER_NEXT,
- RoseInstrSparseIterNext> {
-public:
- u32 state;
- const RoseInstrSparseIterBegin *begin;
- const RoseInstruction *target;
-
- RoseInstrSparseIterNext(u32 state_in,
- const RoseInstrSparseIterBegin *begin_in,
- const RoseInstruction *target_in)
- : state(state_in), begin(begin_in), target(target_in) {}
-
- bool operator==(const RoseInstrSparseIterNext &ri) const {
- return state == ri.state && begin == ri.begin && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, state);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- void update_target(const RoseInstruction *old_target,
- const RoseInstruction *new_target) override {
- if (target == old_target) {
- target = new_target;
- }
- if (begin == old_target) {
- assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN);
- begin = static_cast<const RoseInstrSparseIterBegin *>(new_target);
- }
- }
-
- bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return state == ri.state &&
- offsets.at(begin) == other_offsets.at(ri.begin) &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrSparseIterAny
- : public RoseInstrBaseOneTarget<ROSE_INSTR_SPARSE_ITER_ANY,
- ROSE_STRUCT_SPARSE_ITER_ANY,
- RoseInstrSparseIterAny> {
-public:
- u32 num_keys; // total number of multibit keys
- std::vector<u32> keys;
- const RoseInstruction *target;
-
- RoseInstrSparseIterAny(u32 num_keys_in, std::vector<u32> keys_in,
- const RoseInstruction *target_in)
- : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {}
-
- bool operator==(const RoseInstrSparseIterAny &ri) const {
- return num_keys == ri.num_keys && keys == ri.keys &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, num_keys, keys);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return num_keys == ri.num_keys && keys == ri.keys &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrEnginesEod
- : public RoseInstrBaseNoTargets<ROSE_INSTR_ENGINES_EOD,
- ROSE_STRUCT_ENGINES_EOD,
- RoseInstrEnginesEod> {
-public:
- u32 iter_offset;
-
- explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {}
-
- bool operator==(const RoseInstrEnginesEod &ri) const {
- return iter_offset == ri.iter_offset;
- }
-
- size_t hash() const override {
- return hash_all(opcode, iter_offset);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &,
- const OffsetMap &) const {
- return iter_offset == ri.iter_offset;
- }
-};
-
-class RoseInstrSuffixesEod
- : public RoseInstrBaseTrivial<ROSE_INSTR_SUFFIXES_EOD,
- ROSE_STRUCT_SUFFIXES_EOD,
- RoseInstrSuffixesEod> {
-public:
- ~RoseInstrSuffixesEod() override;
-};
-
-class RoseInstrMatcherEod : public RoseInstrBaseTrivial<ROSE_INSTR_MATCHER_EOD,
- ROSE_STRUCT_MATCHER_EOD,
- RoseInstrMatcherEod> {
-public:
- ~RoseInstrMatcherEod() override;
-};
-
-class RoseInstrCheckLongLit
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
- ROSE_STRUCT_CHECK_LONG_LIT,
- RoseInstrCheckLongLit> {
-public:
- std::string literal;
- const RoseInstruction *target;
-
- RoseInstrCheckLongLit(std::string literal_in,
- const RoseInstruction *target_in)
- : literal(std::move(literal_in)), target(target_in) {}
-
- bool operator==(const RoseInstrCheckLongLit &ri) const {
- return literal == ri.literal && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, literal);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return literal == ri.literal &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckLongLitNocase
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
- ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
- RoseInstrCheckLongLitNocase> {
-public:
- std::string literal;
- const RoseInstruction *target;
-
- RoseInstrCheckLongLitNocase(std::string literal_in,
- const RoseInstruction *target_in)
- : literal(std::move(literal_in)), target(target_in) {
- upperString(literal);
- }
-
- bool operator==(const RoseInstrCheckLongLitNocase &ri) const {
- return literal == ri.literal && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, literal);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckLongLitNocase &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return literal == ri.literal &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMedLit
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT,
- ROSE_STRUCT_CHECK_MED_LIT,
- RoseInstrCheckMedLit> {
-public:
- std::string literal;
- const RoseInstruction *target;
-
- explicit RoseInstrCheckMedLit(std::string literal_in,
- const RoseInstruction *target_in)
- : literal(std::move(literal_in)), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMedLit &ri) const {
- return literal == ri.literal && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, literal);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return literal == ri.literal &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMedLitNocase
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
- ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
- RoseInstrCheckMedLitNocase> {
-public:
- std::string literal;
- const RoseInstruction *target;
-
- explicit RoseInstrCheckMedLitNocase(std::string literal_in,
- const RoseInstruction *target_in)
- : literal(std::move(literal_in)), target(target_in) {
- upperString(literal);
- }
-
- bool operator==(const RoseInstrCheckMedLitNocase &ri) const {
- return literal == ri.literal && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, literal);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMedLitNocase &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return literal == ri.literal &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrClearWorkDone
- : public RoseInstrBaseTrivial<ROSE_INSTR_CLEAR_WORK_DONE,
- ROSE_STRUCT_CLEAR_WORK_DONE,
- RoseInstrClearWorkDone> {
-public:
- ~RoseInstrClearWorkDone() override;
-};
-
-class RoseInstrMultipathLookaround
- : public RoseInstrBaseOneTarget<ROSE_INSTR_MULTIPATH_LOOKAROUND,
- ROSE_STRUCT_MULTIPATH_LOOKAROUND,
- RoseInstrMultipathLookaround> {
-public:
- std::vector<std::vector<LookEntry>> multi_look;
- s32 last_start;
- std::array<u8, 16> start_mask;
- const RoseInstruction *target;
-
- RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,
- s32 last_start_in,
- std::array<u8, 16> start_mask_in,
- const RoseInstruction *target_in)
- : multi_look(std::move(ml)), last_start(last_start_in),
- start_mask(std::move(start_mask_in)), target(target_in) {}
-
- bool operator==(const RoseInstrMultipathLookaround &ri) const {
- return multi_look == ri.multi_look && last_start == ri.last_start
- && start_mask == ri.start_mask && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, multi_look, last_start, start_mask);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrMultipathLookaround &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return multi_look == ri.multi_look && last_start == ri.last_start
- && start_mask == ri.start_mask
- && offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMultipathShufti16x8
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
- ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8,
- RoseInstrCheckMultipathShufti16x8> {
-public:
- std::array<u8, 32> nib_mask;
- std::array<u8, 64> bucket_select_mask;
- std::array<u8, 64> data_select_mask;
- u16 hi_bits_mask;
- u16 lo_bits_mask;
- u16 neg_mask;
- s32 base_offset;
- s32 last_start;
- const RoseInstruction *target;
-
- RoseInstrCheckMultipathShufti16x8(std::array<u8, 32> nib_mask_in,
- std::array<u8, 64> bucket_select_mask_in,
- std::array<u8, 64> data_select_mask_in,
- u16 hi_bits_mask_in, u16 lo_bits_mask_in,
- u16 neg_mask_in, s32 base_offset_in,
- s32 last_start_in,
- const RoseInstruction *target_in)
- : nib_mask(std::move(nib_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- data_select_mask(std::move(data_select_mask_in)),
- hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
- neg_mask(neg_mask_in), base_offset(base_offset_in),
- last_start(last_start_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const {
- return nib_mask == ri.nib_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask &&
- neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
- last_start == ri.last_start && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, nib_mask, bucket_select_mask, data_select_mask,
- hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
- last_start);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return nib_mask == ri.nib_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
- base_offset == ri.base_offset && last_start == ri.last_start &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMultipathShufti32x8
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
- ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8,
- RoseInstrCheckMultipathShufti32x8> {
-public:
- std::array<u8, 32> hi_mask;
- std::array<u8, 32> lo_mask;
- std::array<u8, 64> bucket_select_mask;
- std::array<u8, 64> data_select_mask;
- u32 hi_bits_mask;
- u32 lo_bits_mask;
- u32 neg_mask;
- s32 base_offset;
- s32 last_start;
- const RoseInstruction *target;
-
- RoseInstrCheckMultipathShufti32x8(std::array<u8, 32> hi_mask_in,
- std::array<u8, 32> lo_mask_in,
- std::array<u8, 64> bucket_select_mask_in,
- std::array<u8, 64> data_select_mask_in,
- u32 hi_bits_mask_in, u32 lo_bits_mask_in,
- u32 neg_mask_in, s32 base_offset_in,
- s32 last_start_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- data_select_mask(std::move(data_select_mask_in)),
- hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
- neg_mask(neg_mask_in), base_offset(base_offset_in),
- last_start(last_start_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask &&
- neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
- last_start == ri.last_start && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
- data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
- base_offset, last_start);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
- base_offset == ri.base_offset && last_start == ri.last_start &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMultipathShufti32x16
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
- ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16,
- RoseInstrCheckMultipathShufti32x16> {
-public:
- std::array<u8, 32> hi_mask;
- std::array<u8, 32> lo_mask;
- std::array<u8, 64> bucket_select_mask_hi;
- std::array<u8, 64> bucket_select_mask_lo;
- std::array<u8, 64> data_select_mask;
- u32 hi_bits_mask;
- u32 lo_bits_mask;
- u32 neg_mask;
- s32 base_offset;
- s32 last_start;
- const RoseInstruction *target;
-
- RoseInstrCheckMultipathShufti32x16(std::array<u8, 32> hi_mask_in,
- std::array<u8, 32> lo_mask_in,
- std::array<u8, 64> bucket_select_mask_hi_in,
- std::array<u8, 64> bucket_select_mask_lo_in,
- std::array<u8, 64> data_select_mask_in,
- u32 hi_bits_mask_in, u32 lo_bits_mask_in,
- u32 neg_mask_in, s32 base_offset_in,
- s32 last_start_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
- bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
- data_select_mask(std::move(data_select_mask_in)),
- hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
- neg_mask(neg_mask_in), base_offset(base_offset_in),
- last_start(last_start_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask_hi == ri.bucket_select_mask_hi &&
- bucket_select_mask_lo == ri.bucket_select_mask_lo &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask &&
- neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
- last_start == ri.last_start && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
- bucket_select_mask_lo, data_select_mask, hi_bits_mask,
- lo_bits_mask, neg_mask, base_offset, last_start);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask_hi == ri.bucket_select_mask_hi &&
- bucket_select_mask_lo == ri.bucket_select_mask_lo &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
- base_offset == ri.base_offset && last_start == ri.last_start &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckMultipathShufti64
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
- ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64,
- RoseInstrCheckMultipathShufti64> {
-public:
- std::array<u8, 32> hi_mask;
- std::array<u8, 32> lo_mask;
- std::array<u8, 64> bucket_select_mask;
- std::array<u8, 64> data_select_mask;
- u64a hi_bits_mask;
- u64a lo_bits_mask;
- u64a neg_mask;
- s32 base_offset;
- s32 last_start;
- const RoseInstruction *target;
-
- RoseInstrCheckMultipathShufti64(std::array<u8, 32> hi_mask_in,
- std::array<u8, 32> lo_mask_in,
- std::array<u8, 64> bucket_select_mask_in,
- std::array<u8, 64> data_select_mask_in,
- u64a hi_bits_mask_in, u64a lo_bits_mask_in,
- u64a neg_mask_in, s32 base_offset_in,
- s32 last_start_in,
- const RoseInstruction *target_in)
- : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
- bucket_select_mask(std::move(bucket_select_mask_in)),
- data_select_mask(std::move(data_select_mask_in)),
- hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
- neg_mask(neg_mask_in), base_offset(base_offset_in),
- last_start(last_start_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask &&
- neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
- last_start == ri.last_start && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
- data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
- base_offset, last_start);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrCheckMultipathShufti64 &ri,
- const OffsetMap &offsets,
- const OffsetMap &other_offsets) const {
- return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
- bucket_select_mask == ri.bucket_select_mask &&
- data_select_mask == ri.data_select_mask &&
- hi_bits_mask == ri.hi_bits_mask &&
- lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
- base_offset == ri.base_offset && last_start == ri.last_start &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrIncludedJump
- : public RoseInstrBaseNoTargets<ROSE_INSTR_INCLUDED_JUMP,
- ROSE_STRUCT_INCLUDED_JUMP,
- RoseInstrIncludedJump> {
-public:
- u32 child_offset;
- u8 squash;
-
- RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in)
- : child_offset(child_offset_in), squash(squash_in) {}
-
- bool operator==(const RoseInstrIncludedJump &ri) const {
- return child_offset == ri.child_offset && squash == ri.squash;
- }
-
- size_t hash() const override {
- return hash_all(static_cast<int>(opcode), child_offset, squash);
- }
-
- void write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const override;
-
- bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &,
- const OffsetMap &) const {
- return child_offset == ri.child_offset && squash == ri.squash;
- }
-};
-
+class RoseInstrCheckInfix
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_INFIX,
+ ROSE_STRUCT_CHECK_INFIX,
+ RoseInstrCheckInfix> {
+public:
+ u32 queue;
+ u32 lag;
+ ReportID report;
+ const RoseInstruction *target;
+
+ RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in,
+ const RoseInstruction *target_in)
+ : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckInfix &ri) const {
+ return queue == ri.queue && lag == ri.lag && report == ri.report &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, queue, lag, report);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return queue == ri.queue && lag == ri.lag && report == ri.report &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckPrefix
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_PREFIX,
+ ROSE_STRUCT_CHECK_PREFIX,
+ RoseInstrCheckPrefix> {
+public:
+ u32 queue;
+ u32 lag;
+ ReportID report;
+ const RoseInstruction *target;
+
+ RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in,
+ const RoseInstruction *target_in)
+ : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckPrefix &ri) const {
+ return queue == ri.queue && lag == ri.lag && report == ri.report &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, queue, lag, report);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return queue == ri.queue && lag == ri.lag && report == ri.report &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrPushDelayed
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_PUSH_DELAYED,
+ ROSE_STRUCT_PUSH_DELAYED,
+ RoseInstrPushDelayed> {
+public:
+ u8 delay;
+ u32 index;
+
+ RoseInstrPushDelayed(u8 delay_in, u32 index_in)
+ : delay(delay_in), index(index_in) {}
+
+ bool operator==(const RoseInstrPushDelayed &ri) const {
+ return delay == ri.delay && index == ri.index;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, delay, index);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return delay == ri.delay && index == ri.index;
+ }
+};
+
+class RoseInstrCatchUp
+ : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP, ROSE_STRUCT_CATCH_UP,
+ RoseInstrCatchUp> {
+public:
+ ~RoseInstrCatchUp() override;
+};
+
+class RoseInstrCatchUpMpv
+ : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP_MPV,
+ ROSE_STRUCT_CATCH_UP_MPV,
+ RoseInstrCatchUpMpv> {
+public:
+ ~RoseInstrCatchUpMpv() override;
+};
+
+class RoseInstrSomAdjust
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_ADJUST,
+ ROSE_STRUCT_SOM_ADJUST,
+ RoseInstrSomAdjust> {
+public:
+ u32 distance;
+
+ explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {}
+
+ bool operator==(const RoseInstrSomAdjust &ri) const {
+ return distance == ri.distance;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, distance);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return distance == ri.distance;
+ }
+};
+
+class RoseInstrSomLeftfix
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_LEFTFIX,
+ ROSE_STRUCT_SOM_LEFTFIX,
+ RoseInstrSomLeftfix> {
+public:
+ u32 queue;
+ u32 lag;
+
+ RoseInstrSomLeftfix(u32 queue_in, u32 lag_in)
+ : queue(queue_in), lag(lag_in) {}
+
+ bool operator==(const RoseInstrSomLeftfix &ri) const {
+ return queue == ri.queue && lag == ri.lag;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, queue, lag);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return queue == ri.queue && lag == ri.lag;
+ }
+};
+
+class RoseInstrSomFromReport
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_FROM_REPORT,
+ ROSE_STRUCT_SOM_FROM_REPORT,
+ RoseInstrSomFromReport> {
+public:
+ som_operation som;
+
+ RoseInstrSomFromReport() {
+ std::memset(&som, 0, sizeof(som));
+ }
+
+ bool operator==(const RoseInstrSomFromReport &ri) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, som.type, som.onmatch);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+};
+
+class RoseInstrSomZero
+ : public RoseInstrBaseTrivial<ROSE_INSTR_SOM_ZERO, ROSE_STRUCT_SOM_ZERO,
+ RoseInstrSomZero> {
+public:
+ ~RoseInstrSomZero() override;
+};
+
+class RoseInstrTriggerInfix
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_INFIX,
+ ROSE_STRUCT_TRIGGER_INFIX,
+ RoseInstrTriggerInfix> {
+public:
+ u8 cancel;
+ u32 queue;
+ u32 event;
+
+ RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in)
+ : cancel(cancel_in), queue(queue_in), event(event_in) {}
+
+ bool operator==(const RoseInstrTriggerInfix &ri) const {
+ return cancel == ri.cancel && queue == ri.queue && event == ri.event;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, cancel, queue, event);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return cancel == ri.cancel && queue == ri.queue && event == ri.event;
+ }
+};
+
+class RoseInstrTriggerSuffix
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_SUFFIX,
+ ROSE_STRUCT_TRIGGER_SUFFIX,
+ RoseInstrTriggerSuffix> {
+public:
+ u32 queue;
+ u32 event;
+
+ RoseInstrTriggerSuffix(u32 queue_in, u32 event_in)
+ : queue(queue_in), event(event_in) {}
+
+ bool operator==(const RoseInstrTriggerSuffix &ri) const {
+ return queue == ri.queue && event == ri.event;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, queue, event);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return queue == ri.queue && event == ri.event;
+ }
+};
+
+class RoseInstrDedupe
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE, ROSE_STRUCT_DEDUPE,
+ RoseInstrDedupe> {
+public:
+ u8 quash_som;
+ u32 dkey;
+ s32 offset_adjust;
+ const RoseInstruction *target;
+
+ RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
+ const RoseInstruction *target_in)
+ : quash_som(quash_som_in), dkey(dkey_in),
+ offset_adjust(offset_adjust_in), target(target_in) {}
+
+ bool operator==(const RoseInstrDedupe &ri) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ offset_adjust == ri.offset_adjust && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, quash_som, dkey, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ offset_adjust == ri.offset_adjust &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrDedupeSom
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_SOM,
+ ROSE_STRUCT_DEDUPE_SOM,
+ RoseInstrDedupeSom> {
+public:
+ u8 quash_som;
+ u32 dkey;
+ s32 offset_adjust;
+ const RoseInstruction *target;
+
+ RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
+ const RoseInstruction *target_in)
+ : quash_som(quash_som_in), dkey(dkey_in),
+ offset_adjust(offset_adjust_in), target(target_in) {}
+
+ bool operator==(const RoseInstrDedupeSom &ri) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ offset_adjust == ri.offset_adjust && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, quash_som, dkey, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ offset_adjust == ri.offset_adjust &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrReportChain
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_CHAIN,
+ ROSE_STRUCT_REPORT_CHAIN,
+ RoseInstrReportChain> {
+public:
+ u32 event;
+ u64a top_squash_distance;
+
+ RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in)
+ : event(event_in), top_squash_distance(top_squash_distance_in) {}
+
+ bool operator==(const RoseInstrReportChain &ri) const {
+ return event == ri.event &&
+ top_squash_distance == ri.top_squash_distance;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, event, top_squash_distance);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return event == ri.event &&
+ top_squash_distance == ri.top_squash_distance;
+ }
+};
+
+class RoseInstrReportSomInt
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_INT,
+ ROSE_STRUCT_REPORT_SOM_INT,
+ RoseInstrReportSomInt> {
+public:
+ som_operation som;
+
+ RoseInstrReportSomInt() {
+ std::memset(&som, 0, sizeof(som));
+ }
+
+ bool operator==(const RoseInstrReportSomInt &ri) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, som.type, som.onmatch);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+};
+
+class RoseInstrReportSomAware
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_AWARE,
+ ROSE_STRUCT_REPORT_SOM_AWARE,
+ RoseInstrReportSomAware> {
+public:
+ som_operation som;
+
+ RoseInstrReportSomAware() {
+ std::memset(&som, 0, sizeof(som));
+ }
+
+ bool operator==(const RoseInstrReportSomAware &ri) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, som.type, som.onmatch);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
+ }
+};
+
+class RoseInstrReport
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT, ROSE_STRUCT_REPORT,
+ RoseInstrReport> {
+public:
+ ReportID onmatch;
+ s32 offset_adjust;
+
+ RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in)
+ : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
+
+ bool operator==(const RoseInstrReport &ri) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, onmatch, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReport &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+};
+
+class RoseInstrReportExhaust
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_EXHAUST,
+ ROSE_STRUCT_REPORT_EXHAUST,
+ RoseInstrReportExhaust> {
+public:
+ ReportID onmatch;
+ s32 offset_adjust;
+ u32 ekey;
+
+ RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in,
+ u32 ekey_in)
+ : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
+
+ bool operator==(const RoseInstrReportExhaust &ri) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ ekey == ri.ekey;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, onmatch, offset_adjust, ekey);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ ekey == ri.ekey;
+ }
+};
+
+class RoseInstrReportSom
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM,
+ ROSE_STRUCT_REPORT_SOM,
+ RoseInstrReportSom> {
+public:
+ ReportID onmatch;
+ s32 offset_adjust;
+
+ RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in)
+ : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
+
+ bool operator==(const RoseInstrReportSom &ri) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, onmatch, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+};
+
+class RoseInstrReportSomExhaust
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_EXHAUST,
+ ROSE_STRUCT_REPORT_SOM_EXHAUST,
+ RoseInstrReportSomExhaust> {
+public:
+ ReportID onmatch;
+ s32 offset_adjust;
+ u32 ekey;
+
+ RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in,
+ u32 ekey_in)
+ : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
+
+ bool operator==(const RoseInstrReportSomExhaust &ri) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ ekey == ri.ekey;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, onmatch, offset_adjust, ekey);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ ekey == ri.ekey;
+ }
+};
+
+class RoseInstrDedupeAndReport
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_AND_REPORT,
+ ROSE_STRUCT_DEDUPE_AND_REPORT,
+ RoseInstrDedupeAndReport> {
+public:
+ u8 quash_som;
+ u32 dkey;
+ ReportID onmatch;
+ s32 offset_adjust;
+ const RoseInstruction *target;
+
+ RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in,
+ s32 offset_adjust_in,
+ const RoseInstruction *target_in)
+ : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in),
+ offset_adjust(offset_adjust_in), target(target_in) {}
+
+ bool operator==(const RoseInstrDedupeAndReport &ri) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, quash_som, dkey, onmatch, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return quash_som == ri.quash_som && dkey == ri.dkey &&
+ onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrFinalReport
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_FINAL_REPORT,
+ ROSE_STRUCT_FINAL_REPORT,
+ RoseInstrFinalReport> {
+public:
+ ReportID onmatch;
+ s32 offset_adjust;
+
+ RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in)
+ : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
+
+ bool operator==(const RoseInstrFinalReport &ri) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, onmatch, offset_adjust);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
+ }
+};
+
+class RoseInstrCheckExhausted
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_EXHAUSTED,
+ ROSE_STRUCT_CHECK_EXHAUSTED,
+ RoseInstrCheckExhausted> {
+public:
+ u32 ekey;
+ const RoseInstruction *target;
+
+ RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in)
+ : ekey(ekey_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckExhausted &ri) const {
+ return ekey == ri.ekey && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, ekey);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return ekey == ri.ekey &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMinLength
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MIN_LENGTH,
+ ROSE_STRUCT_CHECK_MIN_LENGTH,
+ RoseInstrCheckMinLength> {
+public:
+ s32 end_adj;
+ u64a min_length;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in,
+ const RoseInstruction *target_in)
+ : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMinLength &ri) const {
+ return end_adj == ri.end_adj && min_length == ri.min_length &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, end_adj, min_length);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return end_adj == ri.end_adj && min_length == ri.min_length &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrSetState
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_STATE, ROSE_STRUCT_SET_STATE,
+ RoseInstrSetState> {
+public:
+ u32 index;
+
+ explicit RoseInstrSetState(u32 index_in) : index(index_in) {}
+
+ bool operator==(const RoseInstrSetState &ri) const {
+ return index == ri.index;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, index);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return index == ri.index;
+ }
+};
+
+class RoseInstrSetGroups
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_GROUPS,
+ ROSE_STRUCT_SET_GROUPS,
+ RoseInstrSetGroups> {
+public:
+ rose_group groups;
+
+ explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {}
+
+ bool operator==(const RoseInstrSetGroups &ri) const {
+ return groups == ri.groups;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, groups);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return groups == ri.groups;
+ }
+};
+
+class RoseInstrSquashGroups
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_SQUASH_GROUPS,
+ ROSE_STRUCT_SQUASH_GROUPS,
+ RoseInstrSquashGroups> {
+public:
+ rose_group groups;
+
+ explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {}
+
+ bool operator==(const RoseInstrSquashGroups &ri) const {
+ return groups == ri.groups;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, groups);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return groups == ri.groups;
+ }
+};
+
+class RoseInstrCheckState
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_STATE,
+ ROSE_STRUCT_CHECK_STATE,
+ RoseInstrCheckState> {
+public:
+ u32 index;
+ const RoseInstruction *target;
+
+ RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in)
+ : index(index_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckState &ri) const {
+ return index == ri.index && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, index);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return index == ri.index &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrSparseIterBegin
+ : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_BEGIN,
+ ROSE_STRUCT_SPARSE_ITER_BEGIN,
+ RoseInstrSparseIterBegin> {
+public:
+ u32 num_keys; // total number of multibit keys
+ std::vector<std::pair<u32, const RoseInstruction *>> jump_table;
+ const RoseInstruction *target;
+
+ RoseInstrSparseIterBegin(u32 num_keys_in,
+ const RoseInstruction *target_in)
+ : num_keys(num_keys_in), target(target_in) {}
+
+ bool operator==(const RoseInstrSparseIterBegin &ri) const {
+ return num_keys == ri.num_keys && jump_table == ri.jump_table &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ size_t v = hash_all(opcode, num_keys);
+ for (const u32 &key : jump_table | boost::adaptors::map_keys) {
+ hash_combine(v, key);
+ }
+ return v;
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ void update_target(const RoseInstruction *old_target,
+ const RoseInstruction *new_target) override {
+ if (target == old_target) {
+ target = new_target;
+ }
+ for (auto &jump : jump_table) {
+ if (jump.second == old_target) {
+ jump.second = new_target;
+ }
+ }
+ }
+
+ bool equiv_to(const RoseInstrSparseIterBegin &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ if (iter_offset != ri.iter_offset ||
+ offsets.at(target) != other_offsets.at(ri.target)) {
+ return false;
+ }
+ if (jump_table.size() != ri.jump_table.size()) {
+ return false;
+ }
+ auto it1 = jump_table.begin(), it2 = ri.jump_table.begin();
+ for (; it1 != jump_table.end(); ++it1, ++it2) {
+ if (it1->first != it2->first) {
+ return false;
+ }
+ if (offsets.at(it1->second) != other_offsets.at(it2->second)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ friend class RoseInstrSparseIterNext;
+
+ // These variables allow us to use the same multibit iterator and jump
+ // table in subsequent SPARSE_ITER_NEXT write() operations.
+ mutable bool is_written = false;
+ mutable u32 iter_offset = 0;
+ mutable u32 jump_table_offset = 0;
+};
+
+class RoseInstrSparseIterNext
+ : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_NEXT,
+ ROSE_STRUCT_SPARSE_ITER_NEXT,
+ RoseInstrSparseIterNext> {
+public:
+ u32 state;
+ const RoseInstrSparseIterBegin *begin;
+ const RoseInstruction *target;
+
+ RoseInstrSparseIterNext(u32 state_in,
+ const RoseInstrSparseIterBegin *begin_in,
+ const RoseInstruction *target_in)
+ : state(state_in), begin(begin_in), target(target_in) {}
+
+ bool operator==(const RoseInstrSparseIterNext &ri) const {
+ return state == ri.state && begin == ri.begin && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, state);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ void update_target(const RoseInstruction *old_target,
+ const RoseInstruction *new_target) override {
+ if (target == old_target) {
+ target = new_target;
+ }
+ if (begin == old_target) {
+ assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN);
+ begin = static_cast<const RoseInstrSparseIterBegin *>(new_target);
+ }
+ }
+
+ bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return state == ri.state &&
+ offsets.at(begin) == other_offsets.at(ri.begin) &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrSparseIterAny
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_SPARSE_ITER_ANY,
+ ROSE_STRUCT_SPARSE_ITER_ANY,
+ RoseInstrSparseIterAny> {
+public:
+ u32 num_keys; // total number of multibit keys
+ std::vector<u32> keys;
+ const RoseInstruction *target;
+
+ RoseInstrSparseIterAny(u32 num_keys_in, std::vector<u32> keys_in,
+ const RoseInstruction *target_in)
+ : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrSparseIterAny &ri) const {
+ return num_keys == ri.num_keys && keys == ri.keys &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, num_keys, keys);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return num_keys == ri.num_keys && keys == ri.keys &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrEnginesEod
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_ENGINES_EOD,
+ ROSE_STRUCT_ENGINES_EOD,
+ RoseInstrEnginesEod> {
+public:
+ u32 iter_offset;
+
+ explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {}
+
+ bool operator==(const RoseInstrEnginesEod &ri) const {
+ return iter_offset == ri.iter_offset;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, iter_offset);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return iter_offset == ri.iter_offset;
+ }
+};
+
+class RoseInstrSuffixesEod
+ : public RoseInstrBaseTrivial<ROSE_INSTR_SUFFIXES_EOD,
+ ROSE_STRUCT_SUFFIXES_EOD,
+ RoseInstrSuffixesEod> {
+public:
+ ~RoseInstrSuffixesEod() override;
+};
+
+class RoseInstrMatcherEod : public RoseInstrBaseTrivial<ROSE_INSTR_MATCHER_EOD,
+ ROSE_STRUCT_MATCHER_EOD,
+ RoseInstrMatcherEod> {
+public:
+ ~RoseInstrMatcherEod() override;
+};
+
+class RoseInstrCheckLongLit
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
+ ROSE_STRUCT_CHECK_LONG_LIT,
+ RoseInstrCheckLongLit> {
+public:
+ std::string literal;
+ const RoseInstruction *target;
+
+ RoseInstrCheckLongLit(std::string literal_in,
+ const RoseInstruction *target_in)
+ : literal(std::move(literal_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckLongLit &ri) const {
+ return literal == ri.literal && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, literal);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return literal == ri.literal &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckLongLitNocase
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
+ ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
+ RoseInstrCheckLongLitNocase> {
+public:
+ std::string literal;
+ const RoseInstruction *target;
+
+ RoseInstrCheckLongLitNocase(std::string literal_in,
+ const RoseInstruction *target_in)
+ : literal(std::move(literal_in)), target(target_in) {
+ upperString(literal);
+ }
+
+ bool operator==(const RoseInstrCheckLongLitNocase &ri) const {
+ return literal == ri.literal && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, literal);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckLongLitNocase &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return literal == ri.literal &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMedLit
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT,
+ ROSE_STRUCT_CHECK_MED_LIT,
+ RoseInstrCheckMedLit> {
+public:
+ std::string literal;
+ const RoseInstruction *target;
+
+ explicit RoseInstrCheckMedLit(std::string literal_in,
+ const RoseInstruction *target_in)
+ : literal(std::move(literal_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMedLit &ri) const {
+ return literal == ri.literal && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, literal);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return literal == ri.literal &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMedLitNocase
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
+ ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
+ RoseInstrCheckMedLitNocase> {
+public:
+ std::string literal;
+ const RoseInstruction *target;
+
+ explicit RoseInstrCheckMedLitNocase(std::string literal_in,
+ const RoseInstruction *target_in)
+ : literal(std::move(literal_in)), target(target_in) {
+ upperString(literal);
+ }
+
+ bool operator==(const RoseInstrCheckMedLitNocase &ri) const {
+ return literal == ri.literal && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, literal);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMedLitNocase &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return literal == ri.literal &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrClearWorkDone
+ : public RoseInstrBaseTrivial<ROSE_INSTR_CLEAR_WORK_DONE,
+ ROSE_STRUCT_CLEAR_WORK_DONE,
+ RoseInstrClearWorkDone> {
+public:
+ ~RoseInstrClearWorkDone() override;
+};
+
+class RoseInstrMultipathLookaround
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_MULTIPATH_LOOKAROUND,
+ ROSE_STRUCT_MULTIPATH_LOOKAROUND,
+ RoseInstrMultipathLookaround> {
+public:
+ std::vector<std::vector<LookEntry>> multi_look;
+ s32 last_start;
+ std::array<u8, 16> start_mask;
+ const RoseInstruction *target;
+
+ RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,
+ s32 last_start_in,
+ std::array<u8, 16> start_mask_in,
+ const RoseInstruction *target_in)
+ : multi_look(std::move(ml)), last_start(last_start_in),
+ start_mask(std::move(start_mask_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrMultipathLookaround &ri) const {
+ return multi_look == ri.multi_look && last_start == ri.last_start
+ && start_mask == ri.start_mask && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, multi_look, last_start, start_mask);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrMultipathLookaround &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return multi_look == ri.multi_look && last_start == ri.last_start
+ && start_mask == ri.start_mask
+ && offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMultipathShufti16x8
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
+ ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8,
+ RoseInstrCheckMultipathShufti16x8> {
+public:
+ std::array<u8, 32> nib_mask;
+ std::array<u8, 64> bucket_select_mask;
+ std::array<u8, 64> data_select_mask;
+ u16 hi_bits_mask;
+ u16 lo_bits_mask;
+ u16 neg_mask;
+ s32 base_offset;
+ s32 last_start;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMultipathShufti16x8(std::array<u8, 32> nib_mask_in,
+ std::array<u8, 64> bucket_select_mask_in,
+ std::array<u8, 64> data_select_mask_in,
+ u16 hi_bits_mask_in, u16 lo_bits_mask_in,
+ u16 neg_mask_in, s32 base_offset_in,
+ s32 last_start_in,
+ const RoseInstruction *target_in)
+ : nib_mask(std::move(nib_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ data_select_mask(std::move(data_select_mask_in)),
+ hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
+ neg_mask(neg_mask_in), base_offset(base_offset_in),
+ last_start(last_start_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const {
+ return nib_mask == ri.nib_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask &&
+ neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
+ last_start == ri.last_start && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, nib_mask, bucket_select_mask, data_select_mask,
+ hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
+ last_start);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return nib_mask == ri.nib_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
+ base_offset == ri.base_offset && last_start == ri.last_start &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMultipathShufti32x8
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
+ ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8,
+ RoseInstrCheckMultipathShufti32x8> {
+public:
+ std::array<u8, 32> hi_mask;
+ std::array<u8, 32> lo_mask;
+ std::array<u8, 64> bucket_select_mask;
+ std::array<u8, 64> data_select_mask;
+ u32 hi_bits_mask;
+ u32 lo_bits_mask;
+ u32 neg_mask;
+ s32 base_offset;
+ s32 last_start;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMultipathShufti32x8(std::array<u8, 32> hi_mask_in,
+ std::array<u8, 32> lo_mask_in,
+ std::array<u8, 64> bucket_select_mask_in,
+ std::array<u8, 64> data_select_mask_in,
+ u32 hi_bits_mask_in, u32 lo_bits_mask_in,
+ u32 neg_mask_in, s32 base_offset_in,
+ s32 last_start_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ data_select_mask(std::move(data_select_mask_in)),
+ hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
+ neg_mask(neg_mask_in), base_offset(base_offset_in),
+ last_start(last_start_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask &&
+ neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
+ last_start == ri.last_start && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
+ data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
+ base_offset, last_start);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
+ base_offset == ri.base_offset && last_start == ri.last_start &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMultipathShufti32x16
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
+ ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16,
+ RoseInstrCheckMultipathShufti32x16> {
+public:
+ std::array<u8, 32> hi_mask;
+ std::array<u8, 32> lo_mask;
+ std::array<u8, 64> bucket_select_mask_hi;
+ std::array<u8, 64> bucket_select_mask_lo;
+ std::array<u8, 64> data_select_mask;
+ u32 hi_bits_mask;
+ u32 lo_bits_mask;
+ u32 neg_mask;
+ s32 base_offset;
+ s32 last_start;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMultipathShufti32x16(std::array<u8, 32> hi_mask_in,
+ std::array<u8, 32> lo_mask_in,
+ std::array<u8, 64> bucket_select_mask_hi_in,
+ std::array<u8, 64> bucket_select_mask_lo_in,
+ std::array<u8, 64> data_select_mask_in,
+ u32 hi_bits_mask_in, u32 lo_bits_mask_in,
+ u32 neg_mask_in, s32 base_offset_in,
+ s32 last_start_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
+ bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
+ data_select_mask(std::move(data_select_mask_in)),
+ hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
+ neg_mask(neg_mask_in), base_offset(base_offset_in),
+ last_start(last_start_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask_hi == ri.bucket_select_mask_hi &&
+ bucket_select_mask_lo == ri.bucket_select_mask_lo &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask &&
+ neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
+ last_start == ri.last_start && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
+ bucket_select_mask_lo, data_select_mask, hi_bits_mask,
+ lo_bits_mask, neg_mask, base_offset, last_start);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask_hi == ri.bucket_select_mask_hi &&
+ bucket_select_mask_lo == ri.bucket_select_mask_lo &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
+ base_offset == ri.base_offset && last_start == ri.last_start &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckMultipathShufti64
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
+ ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64,
+ RoseInstrCheckMultipathShufti64> {
+public:
+ std::array<u8, 32> hi_mask;
+ std::array<u8, 32> lo_mask;
+ std::array<u8, 64> bucket_select_mask;
+ std::array<u8, 64> data_select_mask;
+ u64a hi_bits_mask;
+ u64a lo_bits_mask;
+ u64a neg_mask;
+ s32 base_offset;
+ s32 last_start;
+ const RoseInstruction *target;
+
+ RoseInstrCheckMultipathShufti64(std::array<u8, 32> hi_mask_in,
+ std::array<u8, 32> lo_mask_in,
+ std::array<u8, 64> bucket_select_mask_in,
+ std::array<u8, 64> data_select_mask_in,
+ u64a hi_bits_mask_in, u64a lo_bits_mask_in,
+ u64a neg_mask_in, s32 base_offset_in,
+ s32 last_start_in,
+ const RoseInstruction *target_in)
+ : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
+ bucket_select_mask(std::move(bucket_select_mask_in)),
+ data_select_mask(std::move(data_select_mask_in)),
+ hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
+ neg_mask(neg_mask_in), base_offset(base_offset_in),
+ last_start(last_start_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask &&
+ neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
+ last_start == ri.last_start && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
+ data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
+ base_offset, last_start);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrCheckMultipathShufti64 &ri,
+ const OffsetMap &offsets,
+ const OffsetMap &other_offsets) const {
+ return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
+ bucket_select_mask == ri.bucket_select_mask &&
+ data_select_mask == ri.data_select_mask &&
+ hi_bits_mask == ri.hi_bits_mask &&
+ lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
+ base_offset == ri.base_offset && last_start == ri.last_start &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrIncludedJump
+ : public RoseInstrBaseNoTargets<ROSE_INSTR_INCLUDED_JUMP,
+ ROSE_STRUCT_INCLUDED_JUMP,
+ RoseInstrIncludedJump> {
+public:
+ u32 child_offset;
+ u8 squash;
+
+ RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in)
+ : child_offset(child_offset_in), squash(squash_in) {}
+
+ bool operator==(const RoseInstrIncludedJump &ri) const {
+ return child_offset == ri.child_offset && squash == ri.squash;
+ }
+
+ size_t hash() const override {
+ return hash_all(static_cast<int>(opcode), child_offset, squash);
+ }
+
+ void write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const override;
+
+ bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &,
+ const OffsetMap &) const {
+ return child_offset == ri.child_offset && squash == ri.squash;
+ }
+};
+
class RoseInstrSetLogical
: public RoseInstrBaseNoTargets<ROSE_INSTR_SET_LOGICAL,
ROSE_STRUCT_SET_LOGICAL,
@@ -2380,12 +2380,12 @@ public:
}
};
-class RoseInstrEnd
- : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
- RoseInstrEnd> {
-public:
- ~RoseInstrEnd() override;
-};
-
-}
-#endif
+class RoseInstrEnd
+ : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
+ RoseInstrEnd> {
+public:
+ ~RoseInstrEnd() override;
+};
+
+}
+#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.cpp b/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.cpp
index 5d7af283138..b389f493d11 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.cpp
@@ -1,467 +1,467 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_lit_accel.h"
-
-#include "grey.h"
-#include "ue2common.h"
-#include "hwlm/hwlm_build.h"
-#include "hwlm/hwlm_internal.h"
-#include "hwlm/hwlm_literal.h"
-#include "nfa/accel.h"
-#include "nfa/shufticompile.h"
-#include "nfa/trufflecompile.h"
-#include "util/compare.h"
-#include "util/dump_charclass.h"
-#include "util/ue2string.h"
-#include "util/verify_types.h"
-
-using namespace std;
-
-namespace ue2 {
-
-static const unsigned int MAX_ACCEL_OFFSET = 16;
-static const unsigned int MAX_SHUFTI_WIDTH = 240;
-
-static
-size_t mask_overhang(const AccelString &lit) {
- size_t msk_true_size = lit.msk.size();
- assert(msk_true_size <= HWLM_MASKLEN);
- assert(HWLM_MASKLEN <= MAX_ACCEL_OFFSET);
- for (u8 c : lit.msk) {
- if (!c) {
- msk_true_size--;
- } else {
- break;
- }
- }
-
- if (lit.s.length() >= msk_true_size) {
- return 0;
- }
-
- /* only short literals should be able to have a mask which overhangs */
- assert(lit.s.length() < MAX_ACCEL_OFFSET);
- return msk_true_size - lit.s.length();
-}
-
-static
-bool findDVerm(const vector<const AccelString *> &lits, AccelAux *aux) {
- const AccelString &first = *lits.front();
-
- struct candidate {
- candidate(void)
- : c1(0), c2(0), max_offset(0), b5insens(false), valid(false) {}
- candidate(const AccelString &base, u32 offset)
- : c1(base.s[offset]), c2(base.s[offset + 1]), max_offset(0),
- b5insens(false), valid(true) {}
- char c1;
- char c2;
- u32 max_offset;
- bool b5insens;
- bool valid;
-
- bool operator>(const candidate &other) const {
- if (!valid) {
- return false;
- }
-
- if (!other.valid) {
- return true;
- }
-
- if (other.cdiffers() && !cdiffers()) {
- return false;
- }
-
- if (!other.cdiffers() && cdiffers()) {
- return true;
- }
-
- if (!other.b5insens && b5insens) {
- return false;
- }
-
- if (other.b5insens && !b5insens) {
- return true;
- }
-
- if (max_offset > other.max_offset) {
- return false;
- }
-
- return true;
- }
-
- bool cdiffers(void) const {
- if (!b5insens) {
- return c1 != c2;
- }
- return (c1 & CASE_CLEAR) != (c2 & CASE_CLEAR);
- }
- };
-
- candidate best;
-
- for (u32 i = 0; i < MIN(MAX_ACCEL_OFFSET, first.s.length()) - 1; i++) {
- candidate curr(first, i);
-
- /* check to see if this pair appears in each string */
- for (const auto &lit_ptr : lits) {
- const AccelString &lit = *lit_ptr;
- if (lit.nocase && (ourisalpha(curr.c1) || ourisalpha(curr.c2))) {
- curr.b5insens = true; /* no choice but to be case insensitive */
- }
-
- bool found = false;
- bool found_nc = false;
- for (u32 j = 0;
- !found && j < MIN(MAX_ACCEL_OFFSET, lit.s.length()) - 1; j++) {
- found |= curr.c1 == lit.s[j] && curr.c2 == lit.s[j + 1];
- found_nc |= (curr.c1 & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR)
- && (curr.c2 & CASE_CLEAR) == (lit.s[j + 1] & CASE_CLEAR);
-
- if (curr.b5insens) {
- found = found_nc;
- }
- }
-
- if (!curr.b5insens && !found && found_nc) {
- curr.b5insens = true;
- found = true;
- }
-
- if (!found) {
- goto next_candidate;
- }
- }
-
- /* check to find the max offset where this appears */
- for (const auto &lit_ptr : lits) {
- const AccelString &lit = *lit_ptr;
- for (u32 j = 0; j < MIN(MAX_ACCEL_OFFSET, lit.s.length()) - 1;
- j++) {
- bool found = false;
- if (curr.b5insens) {
- found = (curr.c1 & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR)
- && (curr.c2 & CASE_CLEAR) == (lit.s[j + 1] & CASE_CLEAR);
- } else {
- found = curr.c1 == lit.s[j] && curr.c2 == lit.s[j + 1];
- }
-
- if (found) {
- assert(j + mask_overhang(lit) <= MAX_ACCEL_OFFSET);
- ENSURE_AT_LEAST(&curr.max_offset, j + mask_overhang(lit));
- break;
- }
- }
- }
-
- if (curr > best) {
- best = curr;
- }
-
- next_candidate:;
- }
-
- if (!best.valid) {
- return false;
- }
-
- aux->dverm.offset = verify_u8(best.max_offset);
-
- if (!best.b5insens) {
- aux->dverm.accel_type = ACCEL_DVERM;
- aux->dverm.c1 = best.c1;
- aux->dverm.c2 = best.c2;
- DEBUG_PRINTF("built dverm for %02hhx%02hhx\n",
- aux->dverm.c1, aux->dverm.c2);
- } else {
- aux->dverm.accel_type = ACCEL_DVERM_NOCASE;
- aux->dverm.c1 = best.c1 & CASE_CLEAR;
- aux->dverm.c2 = best.c2 & CASE_CLEAR;
- DEBUG_PRINTF("built dverm nc for %02hhx%02hhx\n",
- aux->dverm.c1, aux->dverm.c2);
- }
- return true;
-}
-
-static
-bool findSVerm(const vector<const AccelString *> &lits, AccelAux *aux) {
- const AccelString &first = *lits.front();
-
- struct candidate {
- candidate(void)
- : c(0), max_offset(0), b5insens(false), valid(false) {}
- candidate(const AccelString &base, u32 offset)
- : c(base.s[offset]), max_offset(0),
- b5insens(false), valid(true) {}
- char c;
- u32 max_offset;
- bool b5insens;
- bool valid;
-
- bool operator>(const candidate &other) const {
- if (!valid) {
- return false;
- }
-
- if (!other.valid) {
- return true;
- }
-
- if (!other.b5insens && b5insens) {
- return false;
- }
-
- if (other.b5insens && !b5insens) {
- return true;
- }
-
- if (max_offset > other.max_offset) {
- return false;
- }
-
- return true;
- }
- };
-
- candidate best;
-
- for (u32 i = 0; i < MIN(MAX_ACCEL_OFFSET, first.s.length()); i++) {
- candidate curr(first, i);
-
- /* check to see if this pair appears in each string */
- for (const auto &lit_ptr : lits) {
- const AccelString &lit = *lit_ptr;
- if (lit.nocase && ourisalpha(curr.c)) {
- curr.b5insens = true; /* no choice but to be case insensitive */
- }
-
- bool found = false;
- bool found_nc = false;
- for (u32 j = 0;
- !found && j < MIN(MAX_ACCEL_OFFSET, lit.s.length()); j++) {
- found |= curr.c == lit.s[j];
- found_nc |= (curr.c & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR);
-
- if (curr.b5insens) {
- found = found_nc;
- }
- }
-
- if (!curr.b5insens && !found && found_nc) {
- curr.b5insens = true;
- found = true;
- }
-
- if (!found) {
- goto next_candidate;
- }
- }
-
- /* check to find the max offset where this appears */
- for (const auto &lit_ptr : lits) {
- const AccelString &lit = *lit_ptr;
- for (u32 j = 0; j < MIN(MAX_ACCEL_OFFSET, lit.s.length()); j++) {
- bool found = false;
- if (curr.b5insens) {
- found = (curr.c & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR);
- } else {
- found = curr.c == lit.s[j];
- }
-
- if (found) {
- assert(j + mask_overhang(lit) <= MAX_ACCEL_OFFSET);
- ENSURE_AT_LEAST(&curr.max_offset, j + mask_overhang(lit));
- }
- }
- }
-
- if (curr > best) {
- best = curr;
- }
-
- next_candidate:;
- }
-
- if (!best.valid) {
- return false;
- }
-
- if (!best.b5insens) {
- aux->verm.accel_type = ACCEL_VERM;
- aux->verm.c = best.c;
- DEBUG_PRINTF("built verm for %02hhx\n", aux->verm.c);
- } else {
- aux->verm.accel_type = ACCEL_VERM_NOCASE;
- aux->verm.c = best.c & CASE_CLEAR;
- DEBUG_PRINTF("built verm nc for %02hhx\n", aux->verm.c);
- }
- aux->verm.offset = verify_u8(best.max_offset);
-
- return true;
-}
-
-static
-void filterLits(const vector<AccelString> &lits, hwlm_group_t expected_groups,
- vector<const AccelString *> *filtered_lits, u32 *min_len) {
- *min_len = MAX_ACCEL_OFFSET;
-
- for (const auto &lit : lits) {
- if (!(lit.groups & expected_groups)) {
- continue;
- }
-
- const size_t lit_len = lit.s.length();
- if (lit_len < *min_len) {
- *min_len = verify_u32(lit_len);
- }
-
- DEBUG_PRINTF("lit: '%s', nocase=%d, groups=0x%llx\n",
- escapeString(lit.s).c_str(), lit.nocase ? 1 : 0,
- lit.groups);
- filtered_lits->push_back(&lit);
- }
-}
-
-static
-bool litGuardedByCharReach(const CharReach &cr, const AccelString &lit,
- u32 max_offset) {
- for (u32 i = 0; i <= max_offset && i < lit.s.length(); i++) {
- unsigned char c = lit.s[i];
- if (lit.nocase) {
- if (cr.test(mytoupper(c)) && cr.test(mytolower(c))) {
- return true;
- }
- } else {
- if (cr.test(c)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static
-void findForwardAccelScheme(const vector<AccelString> &lits,
- hwlm_group_t expected_groups, AccelAux *aux) {
- DEBUG_PRINTF("building accel expected=%016llx\n", expected_groups);
- u32 min_len = MAX_ACCEL_OFFSET;
- vector<const AccelString *> filtered_lits;
-
- filterLits(lits, expected_groups, &filtered_lits, &min_len);
- if (filtered_lits.empty()) {
- return;
- }
-
- if (findDVerm(filtered_lits, aux)
- || findSVerm(filtered_lits, aux)) {
- return;
- }
-
- /* look for shufti/truffle */
-
- vector<CharReach> reach(MAX_ACCEL_OFFSET, CharReach());
- for (const auto &lit : lits) {
- if (!(lit.groups & expected_groups)) {
- continue;
- }
-
- u32 overhang = mask_overhang(lit);
- for (u32 i = 0; i < overhang; i++) {
- /* this offset overhangs the start of the real literal; look at the
- * msk/cmp */
- for (u32 j = 0; j < N_CHARS; j++) {
- if ((j & lit.msk[i]) == lit.cmp[i]) {
- reach[i].set(j);
- }
- }
- }
- for (u32 i = overhang; i < MAX_ACCEL_OFFSET; i++) {
- CharReach &reach_i = reach[i];
- u32 i_effective = i - overhang;
-
- if (litGuardedByCharReach(reach_i, lit, i_effective)) {
- continue;
- }
- unsigned char c = i_effective < lit.s.length() ? lit.s[i_effective]
- : lit.s.back();
- if (lit.nocase) {
- reach_i.set(mytoupper(c));
- reach_i.set(mytolower(c));
- } else {
- reach_i.set(c);
- }
- }
- }
-
- u32 min_count = ~0U;
- u32 min_offset = ~0U;
- for (u32 i = 0; i < MAX_ACCEL_OFFSET; i++) {
- size_t count = reach[i].count();
- DEBUG_PRINTF("offset %u is %s (reach %zu)\n", i,
- describeClass(reach[i]).c_str(), count);
- if (count < min_count) {
- min_count = (u32)count;
- min_offset = i;
- }
- }
-
- if (min_count > MAX_SHUFTI_WIDTH) {
- DEBUG_PRINTF("FAIL: min shufti with %u chars is too wide\n", min_count);
- return;
- }
-
- const CharReach &cr = reach[min_offset];
- if (-1 !=
- shuftiBuildMasks(cr, (u8 *)&aux->shufti.lo, (u8 *)&aux->shufti.hi)) {
- DEBUG_PRINTF("built shufti for %s (%zu chars, offset %u)\n",
- describeClass(cr).c_str(), cr.count(), min_offset);
- aux->shufti.accel_type = ACCEL_SHUFTI;
- aux->shufti.offset = verify_u8(min_offset);
- return;
- }
-
- truffleBuildMasks(cr, (u8 *)&aux->truffle.mask1, (u8 *)&aux->truffle.mask2);
- DEBUG_PRINTF("built truffle for %s (%zu chars, offset %u)\n",
- describeClass(cr).c_str(), cr.count(), min_offset);
- aux->truffle.accel_type = ACCEL_TRUFFLE;
- aux->truffle.offset = verify_u8(min_offset);
-}
-
-void buildForwardAccel(HWLM *h, const vector<AccelString> &lits,
- hwlm_group_t expected_groups) {
- findForwardAccelScheme(lits, expected_groups, &h->accel1);
- findForwardAccelScheme(lits, HWLM_ALL_GROUPS, &h->accel0);
-
- h->accel1_groups = expected_groups;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_lit_accel.h"
+
+#include "grey.h"
+#include "ue2common.h"
+#include "hwlm/hwlm_build.h"
+#include "hwlm/hwlm_internal.h"
+#include "hwlm/hwlm_literal.h"
+#include "nfa/accel.h"
+#include "nfa/shufticompile.h"
+#include "nfa/trufflecompile.h"
+#include "util/compare.h"
+#include "util/dump_charclass.h"
+#include "util/ue2string.h"
+#include "util/verify_types.h"
+
+using namespace std;
+
+namespace ue2 {
+
+static const unsigned int MAX_ACCEL_OFFSET = 16;
+static const unsigned int MAX_SHUFTI_WIDTH = 240;
+
+static
+size_t mask_overhang(const AccelString &lit) {
+ size_t msk_true_size = lit.msk.size();
+ assert(msk_true_size <= HWLM_MASKLEN);
+ assert(HWLM_MASKLEN <= MAX_ACCEL_OFFSET);
+ for (u8 c : lit.msk) {
+ if (!c) {
+ msk_true_size--;
+ } else {
+ break;
+ }
+ }
+
+ if (lit.s.length() >= msk_true_size) {
+ return 0;
+ }
+
+ /* only short literals should be able to have a mask which overhangs */
+ assert(lit.s.length() < MAX_ACCEL_OFFSET);
+ return msk_true_size - lit.s.length();
+}
+
+static
+bool findDVerm(const vector<const AccelString *> &lits, AccelAux *aux) {
+ const AccelString &first = *lits.front();
+
+ struct candidate {
+ candidate(void)
+ : c1(0), c2(0), max_offset(0), b5insens(false), valid(false) {}
+ candidate(const AccelString &base, u32 offset)
+ : c1(base.s[offset]), c2(base.s[offset + 1]), max_offset(0),
+ b5insens(false), valid(true) {}
+ char c1;
+ char c2;
+ u32 max_offset;
+ bool b5insens;
+ bool valid;
+
+ bool operator>(const candidate &other) const {
+ if (!valid) {
+ return false;
+ }
+
+ if (!other.valid) {
+ return true;
+ }
+
+ if (other.cdiffers() && !cdiffers()) {
+ return false;
+ }
+
+ if (!other.cdiffers() && cdiffers()) {
+ return true;
+ }
+
+ if (!other.b5insens && b5insens) {
+ return false;
+ }
+
+ if (other.b5insens && !b5insens) {
+ return true;
+ }
+
+ if (max_offset > other.max_offset) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool cdiffers(void) const {
+ if (!b5insens) {
+ return c1 != c2;
+ }
+ return (c1 & CASE_CLEAR) != (c2 & CASE_CLEAR);
+ }
+ };
+
+ candidate best;
+
+ for (u32 i = 0; i < MIN(MAX_ACCEL_OFFSET, first.s.length()) - 1; i++) {
+ candidate curr(first, i);
+
+ /* check to see if this pair appears in each string */
+ for (const auto &lit_ptr : lits) {
+ const AccelString &lit = *lit_ptr;
+ if (lit.nocase && (ourisalpha(curr.c1) || ourisalpha(curr.c2))) {
+ curr.b5insens = true; /* no choice but to be case insensitive */
+ }
+
+ bool found = false;
+ bool found_nc = false;
+ for (u32 j = 0;
+ !found && j < MIN(MAX_ACCEL_OFFSET, lit.s.length()) - 1; j++) {
+ found |= curr.c1 == lit.s[j] && curr.c2 == lit.s[j + 1];
+ found_nc |= (curr.c1 & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR)
+ && (curr.c2 & CASE_CLEAR) == (lit.s[j + 1] & CASE_CLEAR);
+
+ if (curr.b5insens) {
+ found = found_nc;
+ }
+ }
+
+ if (!curr.b5insens && !found && found_nc) {
+ curr.b5insens = true;
+ found = true;
+ }
+
+ if (!found) {
+ goto next_candidate;
+ }
+ }
+
+ /* check to find the max offset where this appears */
+ for (const auto &lit_ptr : lits) {
+ const AccelString &lit = *lit_ptr;
+ for (u32 j = 0; j < MIN(MAX_ACCEL_OFFSET, lit.s.length()) - 1;
+ j++) {
+ bool found = false;
+ if (curr.b5insens) {
+ found = (curr.c1 & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR)
+ && (curr.c2 & CASE_CLEAR) == (lit.s[j + 1] & CASE_CLEAR);
+ } else {
+ found = curr.c1 == lit.s[j] && curr.c2 == lit.s[j + 1];
+ }
+
+ if (found) {
+ assert(j + mask_overhang(lit) <= MAX_ACCEL_OFFSET);
+ ENSURE_AT_LEAST(&curr.max_offset, j + mask_overhang(lit));
+ break;
+ }
+ }
+ }
+
+ if (curr > best) {
+ best = curr;
+ }
+
+ next_candidate:;
+ }
+
+ if (!best.valid) {
+ return false;
+ }
+
+ aux->dverm.offset = verify_u8(best.max_offset);
+
+ if (!best.b5insens) {
+ aux->dverm.accel_type = ACCEL_DVERM;
+ aux->dverm.c1 = best.c1;
+ aux->dverm.c2 = best.c2;
+ DEBUG_PRINTF("built dverm for %02hhx%02hhx\n",
+ aux->dverm.c1, aux->dverm.c2);
+ } else {
+ aux->dverm.accel_type = ACCEL_DVERM_NOCASE;
+ aux->dverm.c1 = best.c1 & CASE_CLEAR;
+ aux->dverm.c2 = best.c2 & CASE_CLEAR;
+ DEBUG_PRINTF("built dverm nc for %02hhx%02hhx\n",
+ aux->dverm.c1, aux->dverm.c2);
+ }
+ return true;
+}
+
+static
+bool findSVerm(const vector<const AccelString *> &lits, AccelAux *aux) {
+ const AccelString &first = *lits.front();
+
+ struct candidate {
+ candidate(void)
+ : c(0), max_offset(0), b5insens(false), valid(false) {}
+ candidate(const AccelString &base, u32 offset)
+ : c(base.s[offset]), max_offset(0),
+ b5insens(false), valid(true) {}
+ char c;
+ u32 max_offset;
+ bool b5insens;
+ bool valid;
+
+ bool operator>(const candidate &other) const {
+ if (!valid) {
+ return false;
+ }
+
+ if (!other.valid) {
+ return true;
+ }
+
+ if (!other.b5insens && b5insens) {
+ return false;
+ }
+
+ if (other.b5insens && !b5insens) {
+ return true;
+ }
+
+ if (max_offset > other.max_offset) {
+ return false;
+ }
+
+ return true;
+ }
+ };
+
+ candidate best;
+
+ for (u32 i = 0; i < MIN(MAX_ACCEL_OFFSET, first.s.length()); i++) {
+ candidate curr(first, i);
+
+ /* check to see if this pair appears in each string */
+ for (const auto &lit_ptr : lits) {
+ const AccelString &lit = *lit_ptr;
+ if (lit.nocase && ourisalpha(curr.c)) {
+ curr.b5insens = true; /* no choice but to be case insensitive */
+ }
+
+ bool found = false;
+ bool found_nc = false;
+ for (u32 j = 0;
+ !found && j < MIN(MAX_ACCEL_OFFSET, lit.s.length()); j++) {
+ found |= curr.c == lit.s[j];
+ found_nc |= (curr.c & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR);
+
+ if (curr.b5insens) {
+ found = found_nc;
+ }
+ }
+
+ if (!curr.b5insens && !found && found_nc) {
+ curr.b5insens = true;
+ found = true;
+ }
+
+ if (!found) {
+ goto next_candidate;
+ }
+ }
+
+ /* check to find the max offset where this appears */
+ for (const auto &lit_ptr : lits) {
+ const AccelString &lit = *lit_ptr;
+ for (u32 j = 0; j < MIN(MAX_ACCEL_OFFSET, lit.s.length()); j++) {
+ bool found = false;
+ if (curr.b5insens) {
+ found = (curr.c & CASE_CLEAR) == (lit.s[j] & CASE_CLEAR);
+ } else {
+ found = curr.c == lit.s[j];
+ }
+
+ if (found) {
+ assert(j + mask_overhang(lit) <= MAX_ACCEL_OFFSET);
+ ENSURE_AT_LEAST(&curr.max_offset, j + mask_overhang(lit));
+ }
+ }
+ }
+
+ if (curr > best) {
+ best = curr;
+ }
+
+ next_candidate:;
+ }
+
+ if (!best.valid) {
+ return false;
+ }
+
+ if (!best.b5insens) {
+ aux->verm.accel_type = ACCEL_VERM;
+ aux->verm.c = best.c;
+ DEBUG_PRINTF("built verm for %02hhx\n", aux->verm.c);
+ } else {
+ aux->verm.accel_type = ACCEL_VERM_NOCASE;
+ aux->verm.c = best.c & CASE_CLEAR;
+ DEBUG_PRINTF("built verm nc for %02hhx\n", aux->verm.c);
+ }
+ aux->verm.offset = verify_u8(best.max_offset);
+
+ return true;
+}
+
+static
+void filterLits(const vector<AccelString> &lits, hwlm_group_t expected_groups,
+ vector<const AccelString *> *filtered_lits, u32 *min_len) {
+ *min_len = MAX_ACCEL_OFFSET;
+
+ for (const auto &lit : lits) {
+ if (!(lit.groups & expected_groups)) {
+ continue;
+ }
+
+ const size_t lit_len = lit.s.length();
+ if (lit_len < *min_len) {
+ *min_len = verify_u32(lit_len);
+ }
+
+ DEBUG_PRINTF("lit: '%s', nocase=%d, groups=0x%llx\n",
+ escapeString(lit.s).c_str(), lit.nocase ? 1 : 0,
+ lit.groups);
+ filtered_lits->push_back(&lit);
+ }
+}
+
+static
+bool litGuardedByCharReach(const CharReach &cr, const AccelString &lit,
+ u32 max_offset) {
+ for (u32 i = 0; i <= max_offset && i < lit.s.length(); i++) {
+ unsigned char c = lit.s[i];
+ if (lit.nocase) {
+ if (cr.test(mytoupper(c)) && cr.test(mytolower(c))) {
+ return true;
+ }
+ } else {
+ if (cr.test(c)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static
+void findForwardAccelScheme(const vector<AccelString> &lits,
+ hwlm_group_t expected_groups, AccelAux *aux) {
+ DEBUG_PRINTF("building accel expected=%016llx\n", expected_groups);
+ u32 min_len = MAX_ACCEL_OFFSET;
+ vector<const AccelString *> filtered_lits;
+
+ filterLits(lits, expected_groups, &filtered_lits, &min_len);
+ if (filtered_lits.empty()) {
+ return;
+ }
+
+ if (findDVerm(filtered_lits, aux)
+ || findSVerm(filtered_lits, aux)) {
+ return;
+ }
+
+ /* look for shufti/truffle */
+
+ vector<CharReach> reach(MAX_ACCEL_OFFSET, CharReach());
+ for (const auto &lit : lits) {
+ if (!(lit.groups & expected_groups)) {
+ continue;
+ }
+
+ u32 overhang = mask_overhang(lit);
+ for (u32 i = 0; i < overhang; i++) {
+ /* this offset overhangs the start of the real literal; look at the
+ * msk/cmp */
+ for (u32 j = 0; j < N_CHARS; j++) {
+ if ((j & lit.msk[i]) == lit.cmp[i]) {
+ reach[i].set(j);
+ }
+ }
+ }
+ for (u32 i = overhang; i < MAX_ACCEL_OFFSET; i++) {
+ CharReach &reach_i = reach[i];
+ u32 i_effective = i - overhang;
+
+ if (litGuardedByCharReach(reach_i, lit, i_effective)) {
+ continue;
+ }
+ unsigned char c = i_effective < lit.s.length() ? lit.s[i_effective]
+ : lit.s.back();
+ if (lit.nocase) {
+ reach_i.set(mytoupper(c));
+ reach_i.set(mytolower(c));
+ } else {
+ reach_i.set(c);
+ }
+ }
+ }
+
+ u32 min_count = ~0U;
+ u32 min_offset = ~0U;
+ for (u32 i = 0; i < MAX_ACCEL_OFFSET; i++) {
+ size_t count = reach[i].count();
+ DEBUG_PRINTF("offset %u is %s (reach %zu)\n", i,
+ describeClass(reach[i]).c_str(), count);
+ if (count < min_count) {
+ min_count = (u32)count;
+ min_offset = i;
+ }
+ }
+
+ if (min_count > MAX_SHUFTI_WIDTH) {
+ DEBUG_PRINTF("FAIL: min shufti with %u chars is too wide\n", min_count);
+ return;
+ }
+
+ const CharReach &cr = reach[min_offset];
+ if (-1 !=
+ shuftiBuildMasks(cr, (u8 *)&aux->shufti.lo, (u8 *)&aux->shufti.hi)) {
+ DEBUG_PRINTF("built shufti for %s (%zu chars, offset %u)\n",
+ describeClass(cr).c_str(), cr.count(), min_offset);
+ aux->shufti.accel_type = ACCEL_SHUFTI;
+ aux->shufti.offset = verify_u8(min_offset);
+ return;
+ }
+
+ truffleBuildMasks(cr, (u8 *)&aux->truffle.mask1, (u8 *)&aux->truffle.mask2);
+ DEBUG_PRINTF("built truffle for %s (%zu chars, offset %u)\n",
+ describeClass(cr).c_str(), cr.count(), min_offset);
+ aux->truffle.accel_type = ACCEL_TRUFFLE;
+ aux->truffle.offset = verify_u8(min_offset);
+}
+
+void buildForwardAccel(HWLM *h, const vector<AccelString> &lits,
+ hwlm_group_t expected_groups) {
+ findForwardAccelScheme(lits, expected_groups, &h->accel1);
+ findForwardAccelScheme(lits, HWLM_ALL_GROUPS, &h->accel0);
+
+ h->accel1_groups = expected_groups;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.h b/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.h
index 5a959d7de28..f0c0143485c 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_lit_accel.h
@@ -1,71 +1,71 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_LIT_ACCEL_H
-#define ROSE_BUILD_LIT_ACCEL_H
-
-#include "hwlm/hwlm.h"
-
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-struct HWLM;
-
-namespace ue2 {
-
-struct AccelString {
- AccelString(std::string s_in, bool nocase_in, std::vector<u8> msk_in,
- std::vector<u8> cmp_in, hwlm_group_t groups_in)
- : s(std::move(s_in)), nocase(nocase_in), msk(std::move(msk_in)),
- cmp(std::move(cmp_in)), groups(groups_in) {}
-
- std::string s;
- bool nocase;
- std::vector<u8> msk;
- std::vector<u8> cmp;
- hwlm_group_t groups;
-
- bool operator==(const AccelString &a) const {
- return s == a.s && nocase == a.nocase && msk == a.msk && cmp == a.cmp &&
- groups == a.groups;
- }
-
- bool operator<(const AccelString &a) const {
- return std::tie(s, nocase, msk, cmp, groups) <
- std::tie(a.s, a.nocase, a.msk, a.cmp, a.groups);
- }
-};
-
-void buildForwardAccel(HWLM *h, const std::vector<AccelString> &lits,
- hwlm_group_t expected_groups);
-
-} // namespace ue2
-
-#endif // ROSE_BUILD_LIT_ACCEL_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_LIT_ACCEL_H
+#define ROSE_BUILD_LIT_ACCEL_H
+
+#include "hwlm/hwlm.h"
+
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+struct HWLM;
+
+namespace ue2 {
+
+struct AccelString {
+ AccelString(std::string s_in, bool nocase_in, std::vector<u8> msk_in,
+ std::vector<u8> cmp_in, hwlm_group_t groups_in)
+ : s(std::move(s_in)), nocase(nocase_in), msk(std::move(msk_in)),
+ cmp(std::move(cmp_in)), groups(groups_in) {}
+
+ std::string s;
+ bool nocase;
+ std::vector<u8> msk;
+ std::vector<u8> cmp;
+ hwlm_group_t groups;
+
+ bool operator==(const AccelString &a) const {
+ return s == a.s && nocase == a.nocase && msk == a.msk && cmp == a.cmp &&
+ groups == a.groups;
+ }
+
+ bool operator<(const AccelString &a) const {
+ return std::tie(s, nocase, msk, cmp, groups) <
+ std::tie(a.s, a.nocase, a.msk, a.cmp, a.groups);
+ }
+};
+
+void buildForwardAccel(HWLM *h, const std::vector<AccelString> &lits,
+ hwlm_group_t expected_groups);
+
+} // namespace ue2
+
+#endif // ROSE_BUILD_LIT_ACCEL_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_long_lit.cpp b/contrib/libs/hyperscan/src/rose/rose_build_long_lit.cpp
index f9c3b0f8409..45a2eb270d5 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_long_lit.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_long_lit.cpp
@@ -1,452 +1,452 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_long_lit.h"
-
-#include "rose_build_engine_blob.h"
-#include "rose_build_impl.h"
-#include "stream_long_lit_hash.h"
-#include "util/bytecode_ptr.h"
-#include "util/bitutils.h"
-#include "util/verify_types.h"
-#include "util/compile_context.h"
-
-#include <algorithm>
-#include <numeric>
-
-using namespace std;
-
-namespace ue2 {
-
-/** \brief Minimum size for a non-empty hash table. Must be a power of two. */
-static constexpr size_t MIN_HASH_TABLE_SIZE = 128;
-
-/** \brief Maximum load factor (between zero and one) for a hash table. */
-static constexpr double MAX_HASH_TABLE_LOAD = 0.7;
-
-/** \brief Minimum size (in bits) for a bloom filter. Must be a power of two. */
-static constexpr u32 MIN_BLOOM_FILTER_SIZE = 256;
-
-/** \brief Maximum load factor (between zero and one) for a bloom filter. */
-static constexpr double MAX_BLOOM_FILTER_LOAD = 0.25;
-
-struct LongLitModeInfo {
- u32 num_literals = 0; //!< Number of strings for this mode.
- u32 hashed_positions = 0; //!< Number of hashable string positions.
-};
-
-struct LongLitInfo {
- LongLitModeInfo caseful;
- LongLitModeInfo nocase;
-};
-
-static
-u32 roundUpToPowerOfTwo(u32 x) {
- assert(x != 0);
- u32 bits = lg2(x - 1) + 1;
- assert(bits < 32);
- return 1U << bits;
-}
-
-static
-LongLitInfo analyzeLongLits(const vector<ue2_case_string> &lits,
- size_t max_len) {
- LongLitInfo info;
-
- for (const auto &lit : lits) {
- auto &lit_info = lit.nocase ? info.nocase : info.caseful;
- assert(lit.s.size() > max_len);
- lit_info.num_literals++;
- lit_info.hashed_positions += lit.s.size() - max_len;
- }
-
- DEBUG_PRINTF("case: hashed %u positions\n", info.caseful.hashed_positions);
- DEBUG_PRINTF("nocase: hashed %u positions\n", info.nocase.hashed_positions);
-
- return info;
-}
-
-static
-void addToBloomFilter(vector<u8> &bloom, const u8 *substr, bool nocase) {
- const u32 num_keys = verify_u32(bloom.size() * 8);
- const u32 key_mask = (1U << lg2(num_keys)) -1;
-
- const auto hash_functions = { bloomHash_1, bloomHash_2, bloomHash_3 };
- for (const auto &hash_func : hash_functions) {
- u32 hash = hash_func(substr, nocase);
- u32 key = hash & key_mask;
- DEBUG_PRINTF("set key %u (of %zu)\n", key, bloom.size() * 8);
- bloom[key / 8] |= 1U << (key % 8);
- }
-}
-
-static
-size_t bloomOccupancy(const vector<u8> &bloom) {
- return accumulate(begin(bloom), end(bloom), 0,
- [](const size_t &sum, const u8 &elem) {
- return sum + popcount32(elem);
- });
-}
-
-static
-double bloomLoad(const vector<u8> &bloom) {
- return (double)bloomOccupancy(bloom) / (double)(bloom.size() * 8);
-}
-
-static
-vector<u8> buildBloomFilter(const vector<ue2_case_string> &lits, size_t max_len,
- size_t num_entries, bool nocase) {
- assert(num_entries % 8 == 0);
- assert((num_entries & (num_entries - 1)) == 0); // Must be power of two.
-
- vector<u8> bloom(num_entries / 8, 0);
-
- if (!num_entries) {
- return bloom;
- }
-
- for (const auto &lit : lits) {
- if (nocase != lit.nocase) {
- continue;
- }
- for (u32 offset = 1; offset < lit.s.size() - max_len + 1; offset++) {
- const u8 *substr = (const u8 *)lit.s.c_str() + offset;
- addToBloomFilter(bloom, substr, nocase);
- }
- }
-
- DEBUG_PRINTF("%s bloom filter occupancy %zu of %zu entries\n",
- nocase ? "nocase" : "caseful", bloomOccupancy(bloom),
- num_entries);
-
- return bloom;
-}
-
-
-static
-vector<u8> makeBloomFilter(const vector<ue2_case_string> &lits,
- size_t max_len, bool nocase) {
- vector<u8> bloom;
-
- size_t num_entries = MIN_BLOOM_FILTER_SIZE;
- for (;;) {
- bloom = buildBloomFilter(lits, max_len, num_entries, nocase);
- DEBUG_PRINTF("built %s bloom for %zu entries: load %f\n",
- nocase ? "nocase" : "caseful", num_entries,
- bloomLoad(bloom));
- if (bloomLoad(bloom) < MAX_BLOOM_FILTER_LOAD) {
- break;
- }
- num_entries *= 2;
- }
- return bloom;
-}
-
-static UNUSED
-size_t hashTableOccupancy(const vector<RoseLongLitHashEntry> &tab) {
- return count_if(begin(tab), end(tab), [](const RoseLongLitHashEntry &ent) {
- return ent.str_offset != 0;
- });
-}
-
-static UNUSED
-double hashTableLoad(const vector<RoseLongLitHashEntry> &tab) {
- return (double)hashTableOccupancy(tab) / (double)(tab.size());
-}
-
-using LitOffsetVector = small_vector<pair<u32, u32>, 1>;
-
-static
-vector<RoseLongLitHashEntry> buildHashTable(
- size_t max_len, const vector<u32> &litToOffsetVal,
- const map<u32, LitOffsetVector> &hashToLitOffPairs,
- size_t numEntries) {
- vector<RoseLongLitHashEntry> tab(numEntries, {0,0});
-
- if (!numEntries) {
- return tab;
- }
-
- for (const auto &m : hashToLitOffPairs) {
- u32 hash = m.first;
- const LitOffsetVector &d = m.second;
-
- u32 bucket = hash % numEntries;
-
- // Placement via linear probing.
- for (const auto &lit_offset : d) {
- while (tab[bucket].str_offset != 0) {
- bucket++;
- if (bucket == numEntries) {
- bucket = 0;
- }
- }
-
- u32 lit_id = lit_offset.first;
- u32 offset = lit_offset.second;
-
- DEBUG_PRINTF("hash 0x%08x lit_id %u offset %u bucket %u\n", hash,
- lit_id, offset, bucket);
-
- auto &entry = tab[bucket];
- entry.str_offset = verify_u32(litToOffsetVal.at(lit_id));
- assert(entry.str_offset != 0);
- entry.str_len = offset + max_len;
- }
- }
-
- DEBUG_PRINTF("hash table occupancy %zu of %zu entries\n",
- hashTableOccupancy(tab), numEntries);
-
- return tab;
-}
-
-static
-map<u32, LitOffsetVector> computeLitHashes(const vector<ue2_case_string> &lits,
- size_t max_len, bool nocase) {
- map<u32, LitOffsetVector> hashToLitOffPairs;
-
- for (u32 lit_id = 0; lit_id < lits.size(); lit_id++) {
- const ue2_case_string &lit = lits[lit_id];
- if (nocase != lit.nocase) {
- continue;
- }
- for (u32 offset = 1; offset < lit.s.size() - max_len + 1; offset++) {
- const u8 *substr = (const u8 *)lit.s.c_str() + offset;
- u32 hash = hashLongLiteral(substr, max_len, lit.nocase);
- hashToLitOffPairs[hash].emplace_back(lit_id, offset);
- }
- }
-
- for (auto &m : hashToLitOffPairs) {
- LitOffsetVector &d = m.second;
- if (d.size() == 1) {
- continue;
- }
-
- // Sort by (offset, string) so that we'll be able to remove identical
- // string prefixes.
- stable_sort(begin(d), end(d),
- [&](const pair<u32, u32> &a, const pair<u32, u32> &b) {
- const auto &str_a = lits[a.first].s;
- const auto &str_b = lits[b.first].s;
- return tie(a.second, str_a) < tie(b.second, str_b);
- });
-
- // Remove entries that point to the same literal prefix.
- d.erase(unique(begin(d), end(d),
- [&](const pair<u32, u32> &a, const pair<u32, u32> &b) {
- if (a.second != b.second) {
- return false;
- }
- const auto &str_a = lits[a.first].s;
- const auto &str_b = lits[b.first].s;
- const size_t len = max_len + a.second;
- return equal(begin(str_a), begin(str_a) + len,
- begin(str_b));
- }),
- end(d));
-
- // Sort d by distance of the residual string (len minus our depth into
- // the string). We need to put the 'furthest back' string first.
- stable_sort(begin(d), end(d),
- [](const pair<u32, u32> &a, const pair<u32, u32> &b) {
- if (a.second != b.second) {
- return a.second > b.second; /* longest is first */
- }
- return a.first < b.first;
- });
- }
-
- return hashToLitOffPairs;
-}
-
-static
-vector<RoseLongLitHashEntry> makeHashTable(const vector<ue2_case_string> &lits,
- size_t max_len,
- const vector<u32> &litToOffsetVal,
- u32 numPositions, bool nocase) {
- // Compute lit substring hashes.
- const auto hashToLitOffPairs = computeLitHashes(lits, max_len, nocase);
-
- // Compute the size of the hash table: we need enough entries to satisfy
- // our max load constraint, and it must be a power of two.
- size_t num_entries = (double)numPositions / MAX_HASH_TABLE_LOAD + 1;
- num_entries = roundUpToPowerOfTwo(max(MIN_HASH_TABLE_SIZE, num_entries));
-
- auto tab = buildHashTable(max_len, litToOffsetVal, hashToLitOffPairs,
- num_entries);
- DEBUG_PRINTF("built %s hash table for %zu entries: load %f\n",
- nocase ? "nocase" : "caseful", num_entries,
- hashTableLoad(tab));
- assert(hashTableLoad(tab) < MAX_HASH_TABLE_LOAD);
-
- return tab;
-}
-
-static
-vector<u8> buildLits(const vector<ue2_case_string> &lits, u32 baseOffset,
- vector<u32> &litToOffsetVal) {
- vector<u8> blob;
- litToOffsetVal.resize(lits.size(), 0);
-
- u32 lit_id = 0;
- for (const auto &lit : lits) {
- u32 offset = baseOffset + verify_u32(blob.size());
- blob.insert(blob.end(), begin(lit.s), end(lit.s));
- litToOffsetVal[lit_id] = offset;
- lit_id++;
- }
-
- DEBUG_PRINTF("built %zu bytes of strings\n", blob.size());
- return blob;
-}
-
-u32 buildLongLiteralTable(const RoseBuildImpl &build, RoseEngineBlob &blob,
- vector<ue2_case_string> &lits,
- size_t longLitLengthThreshold,
- size_t *historyRequired,
- size_t *longLitStreamStateRequired) {
- // Work in terms of history requirement (i.e. literal len - 1).
- const size_t max_len = longLitLengthThreshold - 1;
-
- // We should only be building the long literal hash table in streaming mode.
- if (!build.cc.streaming) {
- return 0;
- }
-
- if (lits.empty()) {
- DEBUG_PRINTF("no long literals\n");
- return 0;
- }
-
- // The last char of each literal is trimmed as we're not interested in full
- // matches, only partial matches.
- for (auto &lit : lits) {
- assert(!lit.s.empty());
- lit.s.pop_back();
- }
-
- // Sort by caseful/caseless and in lexicographical order.
- stable_sort(begin(lits), end(lits), [](const ue2_case_string &a,
- const ue2_case_string &b) {
- if (a.nocase != b.nocase) {
- return a.nocase < b.nocase;
- }
- return a.s < b.s;
- });
-
- // Find literals that are prefixes of other literals (including
- // duplicates). Note that we iterate in reverse, since we want to retain
- // only the longest string from a set of prefixes.
- auto it = unique(lits.rbegin(), lits.rend(), [](const ue2_case_string &a,
- const ue2_case_string &b) {
- return a.nocase == b.nocase && a.s.size() >= b.s.size() &&
- equal(b.s.begin(), b.s.end(), a.s.begin());
- });
-
- // Erase dupes found by unique().
- lits.erase(lits.begin(), it.base());
-
- LongLitInfo info = analyzeLongLits(lits, max_len);
-
- vector<u32> litToOffsetVal;
- const size_t headerSize = ROUNDUP_16(sizeof(RoseLongLitTable));
- vector<u8> lit_blob = buildLits(lits, headerSize, litToOffsetVal);
-
- // Build caseful bloom filter and hash table.
- vector<u8> bloom_case;
- vector<RoseLongLitHashEntry> tab_case;
- if (info.caseful.num_literals) {
- bloom_case = makeBloomFilter(lits, max_len, false);
- tab_case = makeHashTable(lits, max_len, litToOffsetVal,
- info.caseful.hashed_positions, false);
- }
-
- // Build nocase bloom filter and hash table.
- vector<u8> bloom_nocase;
- vector<RoseLongLitHashEntry> tab_nocase;
- if (info.nocase.num_literals) {
- bloom_nocase = makeBloomFilter(lits, max_len, true);
- tab_nocase = makeHashTable(lits, max_len, litToOffsetVal,
- info.nocase.hashed_positions, true);
- }
-
- size_t wholeLitTabSize = ROUNDUP_16(byte_length(lit_blob));
- size_t htOffsetCase = headerSize + wholeLitTabSize;
- size_t htOffsetNocase = htOffsetCase + byte_length(tab_case);
- size_t bloomOffsetCase = htOffsetNocase + byte_length(tab_nocase);
- size_t bloomOffsetNocase = bloomOffsetCase + byte_length(bloom_case);
-
- size_t tabSize = ROUNDUP_16(bloomOffsetNocase + byte_length(bloom_nocase));
-
- // need to add +2 to both of these to allow space for the actual largest
- // value as well as handling the fact that we add one to the space when
- // storing out a position to allow zero to mean "no stream state value"
- u8 streamBitsCase = lg2(roundUpToPowerOfTwo(tab_case.size() + 2));
- u8 streamBitsNocase = lg2(roundUpToPowerOfTwo(tab_nocase.size() + 2));
- u32 tot_state_bytes = ROUNDUP_N(streamBitsCase + streamBitsNocase, 8) / 8;
-
- auto table = make_zeroed_bytecode_ptr<char>(tabSize, 16);
- assert(table); // otherwise would have thrown std::bad_alloc
-
- // Fill in the RoseLongLitTable header structure.
- RoseLongLitTable *header = (RoseLongLitTable *)(table.get());
- header->size = verify_u32(tabSize);
- header->maxLen = verify_u8(max_len); // u8 so doesn't matter; won't go > 255
- header->caseful.hashOffset = verify_u32(htOffsetCase);
- header->caseful.hashBits = lg2(tab_case.size());
- header->caseful.streamStateBits = streamBitsCase;
- header->caseful.bloomOffset = verify_u32(bloomOffsetCase);
- header->caseful.bloomBits = lg2(bloom_case.size() * 8);
- header->nocase.hashOffset = verify_u32(htOffsetNocase);
- header->nocase.hashBits = lg2(tab_nocase.size());
- header->nocase.streamStateBits = streamBitsNocase;
- header->nocase.bloomOffset = verify_u32(bloomOffsetNocase);
- header->nocase.bloomBits = lg2(bloom_nocase.size() * 8);
- assert(tot_state_bytes < sizeof(u64a));
- header->streamStateBytes = verify_u8(tot_state_bytes); // u8
-
- // Copy in the literal strings, hash tables and bloom filters,
- copy_bytes(table.get() + headerSize, lit_blob);
- copy_bytes(table.get() + htOffsetCase, tab_case);
- copy_bytes(table.get() + bloomOffsetCase, bloom_case);
- copy_bytes(table.get() + htOffsetNocase, tab_nocase);
- copy_bytes(table.get() + bloomOffsetNocase, bloom_nocase);
-
- DEBUG_PRINTF("built streaming table, size=%zu\n", tabSize);
- DEBUG_PRINTF("requires %zu bytes of history\n", max_len);
- DEBUG_PRINTF("requires %u bytes of stream state\n", tot_state_bytes);
-
- *historyRequired = max(*historyRequired, max_len);
- *longLitStreamStateRequired = tot_state_bytes;
-
- return blob.add(table);
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_long_lit.h"
+
+#include "rose_build_engine_blob.h"
+#include "rose_build_impl.h"
+#include "stream_long_lit_hash.h"
+#include "util/bytecode_ptr.h"
+#include "util/bitutils.h"
+#include "util/verify_types.h"
+#include "util/compile_context.h"
+
+#include <algorithm>
+#include <numeric>
+
+using namespace std;
+
+namespace ue2 {
+
+/** \brief Minimum size for a non-empty hash table. Must be a power of two. */
+static constexpr size_t MIN_HASH_TABLE_SIZE = 128;
+
+/** \brief Maximum load factor (between zero and one) for a hash table. */
+static constexpr double MAX_HASH_TABLE_LOAD = 0.7;
+
+/** \brief Minimum size (in bits) for a bloom filter. Must be a power of two. */
+static constexpr u32 MIN_BLOOM_FILTER_SIZE = 256;
+
+/** \brief Maximum load factor (between zero and one) for a bloom filter. */
+static constexpr double MAX_BLOOM_FILTER_LOAD = 0.25;
+
+struct LongLitModeInfo {
+ u32 num_literals = 0; //!< Number of strings for this mode.
+ u32 hashed_positions = 0; //!< Number of hashable string positions.
+};
+
+struct LongLitInfo {
+ LongLitModeInfo caseful;
+ LongLitModeInfo nocase;
+};
+
+static
+u32 roundUpToPowerOfTwo(u32 x) {
+ assert(x != 0);
+ u32 bits = lg2(x - 1) + 1;
+ assert(bits < 32);
+ return 1U << bits;
+}
+
+static
+LongLitInfo analyzeLongLits(const vector<ue2_case_string> &lits,
+ size_t max_len) {
+ LongLitInfo info;
+
+ for (const auto &lit : lits) {
+ auto &lit_info = lit.nocase ? info.nocase : info.caseful;
+ assert(lit.s.size() > max_len);
+ lit_info.num_literals++;
+ lit_info.hashed_positions += lit.s.size() - max_len;
+ }
+
+ DEBUG_PRINTF("case: hashed %u positions\n", info.caseful.hashed_positions);
+ DEBUG_PRINTF("nocase: hashed %u positions\n", info.nocase.hashed_positions);
+
+ return info;
+}
+
+static
+void addToBloomFilter(vector<u8> &bloom, const u8 *substr, bool nocase) {
+ const u32 num_keys = verify_u32(bloom.size() * 8);
+ const u32 key_mask = (1U << lg2(num_keys)) -1;
+
+ const auto hash_functions = { bloomHash_1, bloomHash_2, bloomHash_3 };
+ for (const auto &hash_func : hash_functions) {
+ u32 hash = hash_func(substr, nocase);
+ u32 key = hash & key_mask;
+ DEBUG_PRINTF("set key %u (of %zu)\n", key, bloom.size() * 8);
+ bloom[key / 8] |= 1U << (key % 8);
+ }
+}
+
+static
+size_t bloomOccupancy(const vector<u8> &bloom) {
+ return accumulate(begin(bloom), end(bloom), 0,
+ [](const size_t &sum, const u8 &elem) {
+ return sum + popcount32(elem);
+ });
+}
+
+static
+double bloomLoad(const vector<u8> &bloom) {
+ return (double)bloomOccupancy(bloom) / (double)(bloom.size() * 8);
+}
+
+static
+vector<u8> buildBloomFilter(const vector<ue2_case_string> &lits, size_t max_len,
+ size_t num_entries, bool nocase) {
+ assert(num_entries % 8 == 0);
+ assert((num_entries & (num_entries - 1)) == 0); // Must be power of two.
+
+ vector<u8> bloom(num_entries / 8, 0);
+
+ if (!num_entries) {
+ return bloom;
+ }
+
+ for (const auto &lit : lits) {
+ if (nocase != lit.nocase) {
+ continue;
+ }
+ for (u32 offset = 1; offset < lit.s.size() - max_len + 1; offset++) {
+ const u8 *substr = (const u8 *)lit.s.c_str() + offset;
+ addToBloomFilter(bloom, substr, nocase);
+ }
+ }
+
+ DEBUG_PRINTF("%s bloom filter occupancy %zu of %zu entries\n",
+ nocase ? "nocase" : "caseful", bloomOccupancy(bloom),
+ num_entries);
+
+ return bloom;
+}
+
+
+static
+vector<u8> makeBloomFilter(const vector<ue2_case_string> &lits,
+ size_t max_len, bool nocase) {
+ vector<u8> bloom;
+
+ size_t num_entries = MIN_BLOOM_FILTER_SIZE;
+ for (;;) {
+ bloom = buildBloomFilter(lits, max_len, num_entries, nocase);
+ DEBUG_PRINTF("built %s bloom for %zu entries: load %f\n",
+ nocase ? "nocase" : "caseful", num_entries,
+ bloomLoad(bloom));
+ if (bloomLoad(bloom) < MAX_BLOOM_FILTER_LOAD) {
+ break;
+ }
+ num_entries *= 2;
+ }
+ return bloom;
+}
+
+static UNUSED
+size_t hashTableOccupancy(const vector<RoseLongLitHashEntry> &tab) {
+ return count_if(begin(tab), end(tab), [](const RoseLongLitHashEntry &ent) {
+ return ent.str_offset != 0;
+ });
+}
+
+static UNUSED
+double hashTableLoad(const vector<RoseLongLitHashEntry> &tab) {
+ return (double)hashTableOccupancy(tab) / (double)(tab.size());
+}
+
+using LitOffsetVector = small_vector<pair<u32, u32>, 1>;
+
+static
+vector<RoseLongLitHashEntry> buildHashTable(
+ size_t max_len, const vector<u32> &litToOffsetVal,
+ const map<u32, LitOffsetVector> &hashToLitOffPairs,
+ size_t numEntries) {
+ vector<RoseLongLitHashEntry> tab(numEntries, {0,0});
+
+ if (!numEntries) {
+ return tab;
+ }
+
+ for (const auto &m : hashToLitOffPairs) {
+ u32 hash = m.first;
+ const LitOffsetVector &d = m.second;
+
+ u32 bucket = hash % numEntries;
+
+ // Placement via linear probing.
+ for (const auto &lit_offset : d) {
+ while (tab[bucket].str_offset != 0) {
+ bucket++;
+ if (bucket == numEntries) {
+ bucket = 0;
+ }
+ }
+
+ u32 lit_id = lit_offset.first;
+ u32 offset = lit_offset.second;
+
+ DEBUG_PRINTF("hash 0x%08x lit_id %u offset %u bucket %u\n", hash,
+ lit_id, offset, bucket);
+
+ auto &entry = tab[bucket];
+ entry.str_offset = verify_u32(litToOffsetVal.at(lit_id));
+ assert(entry.str_offset != 0);
+ entry.str_len = offset + max_len;
+ }
+ }
+
+ DEBUG_PRINTF("hash table occupancy %zu of %zu entries\n",
+ hashTableOccupancy(tab), numEntries);
+
+ return tab;
+}
+
+static
+map<u32, LitOffsetVector> computeLitHashes(const vector<ue2_case_string> &lits,
+ size_t max_len, bool nocase) {
+ map<u32, LitOffsetVector> hashToLitOffPairs;
+
+ for (u32 lit_id = 0; lit_id < lits.size(); lit_id++) {
+ const ue2_case_string &lit = lits[lit_id];
+ if (nocase != lit.nocase) {
+ continue;
+ }
+ for (u32 offset = 1; offset < lit.s.size() - max_len + 1; offset++) {
+ const u8 *substr = (const u8 *)lit.s.c_str() + offset;
+ u32 hash = hashLongLiteral(substr, max_len, lit.nocase);
+ hashToLitOffPairs[hash].emplace_back(lit_id, offset);
+ }
+ }
+
+ for (auto &m : hashToLitOffPairs) {
+ LitOffsetVector &d = m.second;
+ if (d.size() == 1) {
+ continue;
+ }
+
+ // Sort by (offset, string) so that we'll be able to remove identical
+ // string prefixes.
+ stable_sort(begin(d), end(d),
+ [&](const pair<u32, u32> &a, const pair<u32, u32> &b) {
+ const auto &str_a = lits[a.first].s;
+ const auto &str_b = lits[b.first].s;
+ return tie(a.second, str_a) < tie(b.second, str_b);
+ });
+
+ // Remove entries that point to the same literal prefix.
+ d.erase(unique(begin(d), end(d),
+ [&](const pair<u32, u32> &a, const pair<u32, u32> &b) {
+ if (a.second != b.second) {
+ return false;
+ }
+ const auto &str_a = lits[a.first].s;
+ const auto &str_b = lits[b.first].s;
+ const size_t len = max_len + a.second;
+ return equal(begin(str_a), begin(str_a) + len,
+ begin(str_b));
+ }),
+ end(d));
+
+ // Sort d by distance of the residual string (len minus our depth into
+ // the string). We need to put the 'furthest back' string first.
+ stable_sort(begin(d), end(d),
+ [](const pair<u32, u32> &a, const pair<u32, u32> &b) {
+ if (a.second != b.second) {
+ return a.second > b.second; /* longest is first */
+ }
+ return a.first < b.first;
+ });
+ }
+
+ return hashToLitOffPairs;
+}
+
+static
+vector<RoseLongLitHashEntry> makeHashTable(const vector<ue2_case_string> &lits,
+ size_t max_len,
+ const vector<u32> &litToOffsetVal,
+ u32 numPositions, bool nocase) {
+ // Compute lit substring hashes.
+ const auto hashToLitOffPairs = computeLitHashes(lits, max_len, nocase);
+
+ // Compute the size of the hash table: we need enough entries to satisfy
+ // our max load constraint, and it must be a power of two.
+ size_t num_entries = (double)numPositions / MAX_HASH_TABLE_LOAD + 1;
+ num_entries = roundUpToPowerOfTwo(max(MIN_HASH_TABLE_SIZE, num_entries));
+
+ auto tab = buildHashTable(max_len, litToOffsetVal, hashToLitOffPairs,
+ num_entries);
+ DEBUG_PRINTF("built %s hash table for %zu entries: load %f\n",
+ nocase ? "nocase" : "caseful", num_entries,
+ hashTableLoad(tab));
+ assert(hashTableLoad(tab) < MAX_HASH_TABLE_LOAD);
+
+ return tab;
+}
+
+static
+vector<u8> buildLits(const vector<ue2_case_string> &lits, u32 baseOffset,
+ vector<u32> &litToOffsetVal) {
+ vector<u8> blob;
+ litToOffsetVal.resize(lits.size(), 0);
+
+ u32 lit_id = 0;
+ for (const auto &lit : lits) {
+ u32 offset = baseOffset + verify_u32(blob.size());
+ blob.insert(blob.end(), begin(lit.s), end(lit.s));
+ litToOffsetVal[lit_id] = offset;
+ lit_id++;
+ }
+
+ DEBUG_PRINTF("built %zu bytes of strings\n", blob.size());
+ return blob;
+}
+
+u32 buildLongLiteralTable(const RoseBuildImpl &build, RoseEngineBlob &blob,
+ vector<ue2_case_string> &lits,
+ size_t longLitLengthThreshold,
+ size_t *historyRequired,
+ size_t *longLitStreamStateRequired) {
+ // Work in terms of history requirement (i.e. literal len - 1).
+ const size_t max_len = longLitLengthThreshold - 1;
+
+ // We should only be building the long literal hash table in streaming mode.
+ if (!build.cc.streaming) {
+ return 0;
+ }
+
+ if (lits.empty()) {
+ DEBUG_PRINTF("no long literals\n");
+ return 0;
+ }
+
+ // The last char of each literal is trimmed as we're not interested in full
+ // matches, only partial matches.
+ for (auto &lit : lits) {
+ assert(!lit.s.empty());
+ lit.s.pop_back();
+ }
+
+ // Sort by caseful/caseless and in lexicographical order.
+ stable_sort(begin(lits), end(lits), [](const ue2_case_string &a,
+ const ue2_case_string &b) {
+ if (a.nocase != b.nocase) {
+ return a.nocase < b.nocase;
+ }
+ return a.s < b.s;
+ });
+
+ // Find literals that are prefixes of other literals (including
+ // duplicates). Note that we iterate in reverse, since we want to retain
+ // only the longest string from a set of prefixes.
+ auto it = unique(lits.rbegin(), lits.rend(), [](const ue2_case_string &a,
+ const ue2_case_string &b) {
+ return a.nocase == b.nocase && a.s.size() >= b.s.size() &&
+ equal(b.s.begin(), b.s.end(), a.s.begin());
+ });
+
+ // Erase dupes found by unique().
+ lits.erase(lits.begin(), it.base());
+
+ LongLitInfo info = analyzeLongLits(lits, max_len);
+
+ vector<u32> litToOffsetVal;
+ const size_t headerSize = ROUNDUP_16(sizeof(RoseLongLitTable));
+ vector<u8> lit_blob = buildLits(lits, headerSize, litToOffsetVal);
+
+ // Build caseful bloom filter and hash table.
+ vector<u8> bloom_case;
+ vector<RoseLongLitHashEntry> tab_case;
+ if (info.caseful.num_literals) {
+ bloom_case = makeBloomFilter(lits, max_len, false);
+ tab_case = makeHashTable(lits, max_len, litToOffsetVal,
+ info.caseful.hashed_positions, false);
+ }
+
+ // Build nocase bloom filter and hash table.
+ vector<u8> bloom_nocase;
+ vector<RoseLongLitHashEntry> tab_nocase;
+ if (info.nocase.num_literals) {
+ bloom_nocase = makeBloomFilter(lits, max_len, true);
+ tab_nocase = makeHashTable(lits, max_len, litToOffsetVal,
+ info.nocase.hashed_positions, true);
+ }
+
+ size_t wholeLitTabSize = ROUNDUP_16(byte_length(lit_blob));
+ size_t htOffsetCase = headerSize + wholeLitTabSize;
+ size_t htOffsetNocase = htOffsetCase + byte_length(tab_case);
+ size_t bloomOffsetCase = htOffsetNocase + byte_length(tab_nocase);
+ size_t bloomOffsetNocase = bloomOffsetCase + byte_length(bloom_case);
+
+ size_t tabSize = ROUNDUP_16(bloomOffsetNocase + byte_length(bloom_nocase));
+
+ // need to add +2 to both of these to allow space for the actual largest
+ // value as well as handling the fact that we add one to the space when
+ // storing out a position to allow zero to mean "no stream state value"
+ u8 streamBitsCase = lg2(roundUpToPowerOfTwo(tab_case.size() + 2));
+ u8 streamBitsNocase = lg2(roundUpToPowerOfTwo(tab_nocase.size() + 2));
+ u32 tot_state_bytes = ROUNDUP_N(streamBitsCase + streamBitsNocase, 8) / 8;
+
+ auto table = make_zeroed_bytecode_ptr<char>(tabSize, 16);
+ assert(table); // otherwise would have thrown std::bad_alloc
+
+ // Fill in the RoseLongLitTable header structure.
+ RoseLongLitTable *header = (RoseLongLitTable *)(table.get());
+ header->size = verify_u32(tabSize);
+ header->maxLen = verify_u8(max_len); // u8 so doesn't matter; won't go > 255
+ header->caseful.hashOffset = verify_u32(htOffsetCase);
+ header->caseful.hashBits = lg2(tab_case.size());
+ header->caseful.streamStateBits = streamBitsCase;
+ header->caseful.bloomOffset = verify_u32(bloomOffsetCase);
+ header->caseful.bloomBits = lg2(bloom_case.size() * 8);
+ header->nocase.hashOffset = verify_u32(htOffsetNocase);
+ header->nocase.hashBits = lg2(tab_nocase.size());
+ header->nocase.streamStateBits = streamBitsNocase;
+ header->nocase.bloomOffset = verify_u32(bloomOffsetNocase);
+ header->nocase.bloomBits = lg2(bloom_nocase.size() * 8);
+ assert(tot_state_bytes < sizeof(u64a));
+ header->streamStateBytes = verify_u8(tot_state_bytes); // u8
+
+ // Copy in the literal strings, hash tables and bloom filters,
+ copy_bytes(table.get() + headerSize, lit_blob);
+ copy_bytes(table.get() + htOffsetCase, tab_case);
+ copy_bytes(table.get() + bloomOffsetCase, bloom_case);
+ copy_bytes(table.get() + htOffsetNocase, tab_nocase);
+ copy_bytes(table.get() + bloomOffsetNocase, bloom_nocase);
+
+ DEBUG_PRINTF("built streaming table, size=%zu\n", tabSize);
+ DEBUG_PRINTF("requires %zu bytes of history\n", max_len);
+ DEBUG_PRINTF("requires %u bytes of stream state\n", tot_state_bytes);
+
+ *historyRequired = max(*historyRequired, max_len);
+ *longLitStreamStateRequired = tot_state_bytes;
+
+ return blob.add(table);
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_long_lit.h b/contrib/libs/hyperscan/src/rose/rose_build_long_lit.h
index 24b61a2f81d..a77b1b69216 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_long_lit.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_long_lit.h
@@ -1,51 +1,51 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_LONG_LIT_H
-#define ROSE_BUILD_LONG_LIT_H
-
-#include "ue2common.h"
-
-#include <vector>
-
-namespace ue2 {
-
-class RoseBuildImpl;
-class RoseEngineBlob;
-struct ue2_case_string;
-
-u32 buildLongLiteralTable(const RoseBuildImpl &build, RoseEngineBlob &blob,
- std::vector<ue2_case_string> &lits,
- size_t longLitLengthThreshold,
- size_t *historyRequired,
- size_t *longLitStreamStateRequired);
-
-} // namespace ue2
-
-
-#endif // ROSE_BUILD_LONG_LIT_H
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_LONG_LIT_H
+#define ROSE_BUILD_LONG_LIT_H
+
+#include "ue2common.h"
+
+#include <vector>
+
+namespace ue2 {
+
+class RoseBuildImpl;
+class RoseEngineBlob;
+struct ue2_case_string;
+
+u32 buildLongLiteralTable(const RoseBuildImpl &build, RoseEngineBlob &blob,
+ std::vector<ue2_case_string> &lits,
+ size_t longLitLengthThreshold,
+ size_t *historyRequired,
+ size_t *longLitStreamStateRequired);
+
+} // namespace ue2
+
+
+#endif // ROSE_BUILD_LONG_LIT_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_lookaround.cpp b/contrib/libs/hyperscan/src/rose/rose_build_lookaround.cpp
index 11f9fa2aa28..d0540d79b07 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_lookaround.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_lookaround.cpp
@@ -40,12 +40,12 @@
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/verify_types.h"
#include <cstdlib>
#include <queue>
-#include <sstream>
+#include <sstream>
using namespace std;
@@ -63,23 +63,23 @@ static const u32 MAX_LOOKAROUND_ENTRIES = 32;
/** \brief We would rather have lookarounds with smaller reach than this. */
static const u32 LOOKAROUND_WIDE_REACH = 200;
-#if defined(DEBUG) || defined(DUMP_SUPPORT)
-static UNUSED
-string dump(const map<s32, CharReach> &look) {
- ostringstream oss;
- for (auto it = look.begin(), ite = look.end(); it != ite; ++it) {
- if (it != look.begin()) {
- oss << ", ";
- }
- oss << "{" << it->first << ": " << describeClass(it->second) << "}";
- }
- return oss.str();
-}
-#endif
-
+#if defined(DEBUG) || defined(DUMP_SUPPORT)
+static UNUSED
+string dump(const map<s32, CharReach> &look) {
+ ostringstream oss;
+ for (auto it = look.begin(), ite = look.end(); it != ite; ++it) {
+ if (it != look.begin()) {
+ oss << ", ";
+ }
+ oss << "{" << it->first << ": " << describeClass(it->second) << "}";
+ }
+ return oss.str();
+}
+#endif
+
static
void getForwardReach(const NGHolder &g, u32 top, map<s32, CharReach> &look) {
- flat_set<NFAVertex> curr, next;
+ flat_set<NFAVertex> curr, next;
// Consider only successors of start with the required top.
for (const auto &e : out_edges_range(g.start, g)) {
@@ -87,7 +87,7 @@ void getForwardReach(const NGHolder &g, u32 top, map<s32, CharReach> &look) {
if (v == g.startDs) {
continue;
}
- if (contains(g[e].tops, top)) {
+ if (contains(g[e].tops, top)) {
curr.insert(v);
}
}
@@ -116,7 +116,7 @@ void getForwardReach(const NGHolder &g, u32 top, map<s32, CharReach> &look) {
static
void getBackwardReach(const NGHolder &g, ReportID report, u32 lag,
map<s32, CharReach> &look) {
- flat_set<NFAVertex> curr, next;
+ flat_set<NFAVertex> curr, next;
for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
if (contains(g[v].reports, report)) {
@@ -187,7 +187,7 @@ void getForwardReach(const raw_dfa &rdfa, map<s32, CharReach> &look) {
return;
}
- flat_set<dstate_id_t> curr, next;
+ flat_set<dstate_id_t> curr, next;
curr.insert(rdfa.start_anchored);
for (u32 i = 0; i < MAX_FWD_LEN && !curr.empty(); i++) {
@@ -276,7 +276,7 @@ void findForwardReach(const RoseGraph &g, const RoseVertex v,
for (const auto &e : out_edges_range(v, g)) {
RoseVertex t = target(e, g);
if (!g[t].left) {
- DEBUG_PRINTF("successor %zu has no leftfix\n", g[t].index);
+ DEBUG_PRINTF("successor %zu has no leftfix\n", g[t].index);
return;
}
rose_look.push_back(map<s32, CharReach>());
@@ -447,7 +447,7 @@ static
void findFloodReach(const RoseBuildImpl &tbi, const RoseVertex v,
set<CharReach> &flood_reach) {
for (u32 lit_id : tbi.g[v].literals) {
- const ue2_literal &s = tbi.literals.at(lit_id).s;
+ const ue2_literal &s = tbi.literals.at(lit_id).s;
if (s.empty()) {
continue;
}
@@ -460,69 +460,69 @@ void findFloodReach(const RoseBuildImpl &tbi, const RoseVertex v,
}
}
-
-namespace {
-struct LookProto {
- LookProto(s32 offset_in, CharReach reach_in)
- : offset(offset_in), reach(move(reach_in)) {}
- s32 offset;
- CharReach reach;
-};
-}
-
+
+namespace {
+struct LookProto {
+ LookProto(s32 offset_in, CharReach reach_in)
+ : offset(offset_in), reach(move(reach_in)) {}
+ s32 offset;
+ CharReach reach;
+};
+}
+
+static
+vector<LookProto> findLiteralReach(const rose_literal_id &lit) {
+ vector<LookProto> look;
+ look.reserve(lit.s.length());
+
+ s32 i = 0 - lit.s.length() - lit.delay;
+ for (const auto &c : lit.s) {
+ look.emplace_back(i, c);
+ i++;
+ }
+
+ return look;
+}
+
static
-vector<LookProto> findLiteralReach(const rose_literal_id &lit) {
- vector<LookProto> look;
- look.reserve(lit.s.length());
-
- s32 i = 0 - lit.s.length() - lit.delay;
- for (const auto &c : lit.s) {
- look.emplace_back(i, c);
- i++;
- }
-
- return look;
-}
-
-static
-vector<LookProto> findLiteralReach(const RoseBuildImpl &build,
- const RoseVertex v) {
- bool first = true;
- vector<LookProto> look;
-
+vector<LookProto> findLiteralReach(const RoseBuildImpl &build,
+ const RoseVertex v) {
+ bool first = true;
+ vector<LookProto> look;
+
for (u32 lit_id : build.g[v].literals) {
- const rose_literal_id &lit = build.literals.at(lit_id);
- auto lit_look = findLiteralReach(lit);
-
- if (first) {
- look = std::move(lit_look);
- first = false;
- continue;
- }
-
- // Erase elements from look with keys not in lit_look. Where a key is
- // in both maps, union its reach with the lookaround.
- auto jt = begin(lit_look);
- for (auto it = begin(look); it != end(look);) {
- if (jt == end(lit_look)) {
- // No further lit_look entries, erase remaining elements from
- // look.
- look.erase(it, end(look));
- break;
- }
- if (it->offset < jt->offset) {
- // Offset is present in look but not in lit_look, erase.
- it = look.erase(it);
- } else if (it->offset > jt->offset) {
- // Offset is preset in lit_look but not in look, ignore.
- ++jt;
- } else {
- // Offset is present in both, union its reach with look.
- it->reach |= jt->reach;
- ++it;
- ++jt;
- }
- }
+ const rose_literal_id &lit = build.literals.at(lit_id);
+ auto lit_look = findLiteralReach(lit);
+
+ if (first) {
+ look = std::move(lit_look);
+ first = false;
+ continue;
+ }
+
+ // Erase elements from look with keys not in lit_look. Where a key is
+ // in both maps, union its reach with the lookaround.
+ auto jt = begin(lit_look);
+ for (auto it = begin(look); it != end(look);) {
+ if (jt == end(lit_look)) {
+ // No further lit_look entries, erase remaining elements from
+ // look.
+ look.erase(it, end(look));
+ break;
+ }
+ if (it->offset < jt->offset) {
+ // Offset is present in look but not in lit_look, erase.
+ it = look.erase(it);
+ } else if (it->offset > jt->offset) {
+ // Offset is preset in lit_look but not in look, ignore.
+ ++jt;
+ } else {
+ // Offset is present in both, union its reach with look.
+ it->reach |= jt->reach;
+ ++it;
+ ++jt;
+ }
+ }
}
return look;
@@ -538,11 +538,11 @@ void trimLiterals(const RoseBuildImpl &build, const RoseVertex v,
DEBUG_PRINTF("pre-trim lookaround: %s\n", dump(look).c_str());
for (const auto &m : findLiteralReach(build, v)) {
- auto it = look.find(m.offset);
+ auto it = look.find(m.offset);
if (it == end(look)) {
continue;
}
- if (m.reach.isSubsetOf(it->second)) {
+ if (m.reach.isSubsetOf(it->second)) {
DEBUG_PRINTF("can trim entry at %d\n", it->first);
look.erase(it);
}
@@ -551,76 +551,76 @@ void trimLiterals(const RoseBuildImpl &build, const RoseVertex v,
DEBUG_PRINTF("post-trim lookaround: %s\n", dump(look).c_str());
}
-static
-void normaliseLeftfix(map<s32, CharReach> &look) {
- // We can erase entries where the reach is "all characters", except for the
- // very first one -- this might be required to establish a minimum bound on
- // the literal's match offset.
-
- // TODO: It would be cleaner to use a literal program instruction to check
- // the minimum bound explicitly.
-
- if (look.empty()) {
- return;
- }
-
- const auto earliest = begin(look)->first;
-
- vector<s32> dead;
- for (const auto &m : look) {
- if (m.second.all() && m.first != earliest) {
- dead.push_back(m.first);
- }
- }
- erase_all(&look, dead);
-}
-
-static
-bool trimMultipathLeftfix(const RoseBuildImpl &build, const RoseVertex v,
- vector<map<s32, CharReach>> &looks) {
- size_t path_count = 0;
- for (auto &look : looks) {
- ++path_count;
- DEBUG_PRINTF("Path #%ld\n", path_count);
-
- assert(!look.empty());
- trimLiterals(build, v, look);
-
- if (look.empty()) {
- return false;
- }
-
- // Could be optimized here, just keep the empty byte of the longest path
- normaliseLeftfix(look);
-
- if (look.size() > MAX_LOOKAROUND_ENTRIES) {
- DEBUG_PRINTF("lookaround too big (%zu entries)\n", look.size());
- return false;
- }
- }
- return true;
-}
-
-static
-void transToLookaround(const vector<map<s32, CharReach>> &looks,
- vector<vector<LookEntry>> &lookarounds) {
- for (const auto &look : looks) {
- vector<LookEntry> lookaround;
- DEBUG_PRINTF("lookaround: %s\n", dump(look).c_str());
- lookaround.reserve(look.size());
- for (const auto &m : look) {
- if (m.first < -128 || m.first > 127) {
- DEBUG_PRINTF("range too big\n");
- lookarounds.clear();
- return;
- }
- s8 offset = verify_s8(m.first);
- lookaround.emplace_back(offset, m.second);
- }
- lookarounds.push_back(lookaround);
- }
-}
-
+static
+void normaliseLeftfix(map<s32, CharReach> &look) {
+ // We can erase entries where the reach is "all characters", except for the
+ // very first one -- this might be required to establish a minimum bound on
+ // the literal's match offset.
+
+ // TODO: It would be cleaner to use a literal program instruction to check
+ // the minimum bound explicitly.
+
+ if (look.empty()) {
+ return;
+ }
+
+ const auto earliest = begin(look)->first;
+
+ vector<s32> dead;
+ for (const auto &m : look) {
+ if (m.second.all() && m.first != earliest) {
+ dead.push_back(m.first);
+ }
+ }
+ erase_all(&look, dead);
+}
+
+static
+bool trimMultipathLeftfix(const RoseBuildImpl &build, const RoseVertex v,
+ vector<map<s32, CharReach>> &looks) {
+ size_t path_count = 0;
+ for (auto &look : looks) {
+ ++path_count;
+ DEBUG_PRINTF("Path #%ld\n", path_count);
+
+ assert(!look.empty());
+ trimLiterals(build, v, look);
+
+ if (look.empty()) {
+ return false;
+ }
+
+ // Could be optimized here, just keep the empty byte of the longest path
+ normaliseLeftfix(look);
+
+ if (look.size() > MAX_LOOKAROUND_ENTRIES) {
+ DEBUG_PRINTF("lookaround too big (%zu entries)\n", look.size());
+ return false;
+ }
+ }
+ return true;
+}
+
+static
+void transToLookaround(const vector<map<s32, CharReach>> &looks,
+ vector<vector<LookEntry>> &lookarounds) {
+ for (const auto &look : looks) {
+ vector<LookEntry> lookaround;
+ DEBUG_PRINTF("lookaround: %s\n", dump(look).c_str());
+ lookaround.reserve(look.size());
+ for (const auto &m : look) {
+ if (m.first < -128 || m.first > 127) {
+ DEBUG_PRINTF("range too big\n");
+ lookarounds.clear();
+ return;
+ }
+ s8 offset = verify_s8(m.first);
+ lookaround.emplace_back(offset, m.second);
+ }
+ lookarounds.push_back(lookaround);
+ }
+}
+
void findLookaroundMasks(const RoseBuildImpl &tbi, const RoseVertex v,
vector<LookEntry> &lookaround) {
lookaround.clear();
@@ -659,155 +659,155 @@ void findLookaroundMasks(const RoseBuildImpl &tbi, const RoseVertex v,
}
static
-bool checkShuftiBuckets(const vector<map<s32, CharReach>> &looks,
- u32 bucket_size) {
- set<u32> bucket;
- for (const auto &look : looks) {
- for (const auto &l : look) {
- CharReach cr = l.second;
- if (cr.count() > 128) {
- cr.flip();
- }
- map <u16, u16> lo2hi;
-
- for (size_t i = cr.find_first(); i != CharReach::npos;) {
- u8 it_hi = i >> 4;
- u16 low_encode = 0;
- while (i != CharReach::npos && (i >> 4) == it_hi) {
- low_encode |= 1 << (i &0xf);
- i = cr.find_next(i);
- }
- lo2hi[low_encode] |= 1 << it_hi;
- }
-
- for (const auto &it : lo2hi) {
- u32 hi_lo = (it.second << 16) | it.first;
- bucket.insert(hi_lo);
- }
- }
- }
- DEBUG_PRINTF("shufti has %lu bucket(s)\n", bucket.size());
- return bucket.size() <= bucket_size;
-}
-
-static
-bool getTransientPrefixReach(const NGHolder &g, ReportID report, u32 lag,
- vector<map<s32, CharReach>> &looks) {
- if (!isAcyclic(g)) {
- DEBUG_PRINTF("contains back-edge\n");
+bool checkShuftiBuckets(const vector<map<s32, CharReach>> &looks,
+ u32 bucket_size) {
+ set<u32> bucket;
+ for (const auto &look : looks) {
+ for (const auto &l : look) {
+ CharReach cr = l.second;
+ if (cr.count() > 128) {
+ cr.flip();
+ }
+ map <u16, u16> lo2hi;
+
+ for (size_t i = cr.find_first(); i != CharReach::npos;) {
+ u8 it_hi = i >> 4;
+ u16 low_encode = 0;
+ while (i != CharReach::npos && (i >> 4) == it_hi) {
+ low_encode |= 1 << (i &0xf);
+ i = cr.find_next(i);
+ }
+ lo2hi[low_encode] |= 1 << it_hi;
+ }
+
+ for (const auto &it : lo2hi) {
+ u32 hi_lo = (it.second << 16) | it.first;
+ bucket.insert(hi_lo);
+ }
+ }
+ }
+ DEBUG_PRINTF("shufti has %lu bucket(s)\n", bucket.size());
+ return bucket.size() <= bucket_size;
+}
+
+static
+bool getTransientPrefixReach(const NGHolder &g, ReportID report, u32 lag,
+ vector<map<s32, CharReach>> &looks) {
+ if (!isAcyclic(g)) {
+ DEBUG_PRINTF("contains back-edge\n");
return false;
}
- // Must be floating chains wired to startDs.
- if (!isFloating(g)) {
- DEBUG_PRINTF("not a floating start\n");
+ // Must be floating chains wired to startDs.
+ if (!isFloating(g)) {
+ DEBUG_PRINTF("not a floating start\n");
return false;
}
- vector<NFAVertex> curr;
- for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
- if (v == g.start || v == g.startDs) {
- DEBUG_PRINTF("empty graph\n");
- return true;
- }
- if (contains(g[v].reports, report)) {
- curr.push_back(v);
- }
- }
-
- assert(!curr.empty());
-
- u32 total_len = curr.size();
-
- for (const auto &v : curr) {
- looks.emplace_back(map<s32, CharReach>());
- looks.back()[0 - (lag + 1)] = g[v].char_reach;
- }
-
- bool curr_active = false;
-
- /* For each offset -i, we backwardly trace the path by vertices in curr.
- * Once there are more than 8 paths and more than 64 bits total_len,
- * which means that neither MULTIPATH_LOOKAROUND nor MULTIPATH_SHUFTI
- * could be successfully built, we will give up the path finding.
- * Otherwise, the loop will halt when all vertices in curr are startDs.
- */
- for (u32 i = lag + 2; i < (lag + 2) + MAX_BACK_LEN; i++) {
- curr_active = false;
- size_t curr_size = curr.size();
- if (curr.size() > 1 && i > lag + MULTIPATH_MAX_LEN) {
- DEBUG_PRINTF("range is larger than 16 in multi-path\n");
+ vector<NFAVertex> curr;
+ for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
+ if (v == g.start || v == g.startDs) {
+ DEBUG_PRINTF("empty graph\n");
+ return true;
+ }
+ if (contains(g[v].reports, report)) {
+ curr.push_back(v);
+ }
+ }
+
+ assert(!curr.empty());
+
+ u32 total_len = curr.size();
+
+ for (const auto &v : curr) {
+ looks.emplace_back(map<s32, CharReach>());
+ looks.back()[0 - (lag + 1)] = g[v].char_reach;
+ }
+
+ bool curr_active = false;
+
+ /* For each offset -i, we backwardly trace the path by vertices in curr.
+ * Once there are more than 8 paths and more than 64 bits total_len,
+ * which means that neither MULTIPATH_LOOKAROUND nor MULTIPATH_SHUFTI
+ * could be successfully built, we will give up the path finding.
+ * Otherwise, the loop will halt when all vertices in curr are startDs.
+ */
+ for (u32 i = lag + 2; i < (lag + 2) + MAX_BACK_LEN; i++) {
+ curr_active = false;
+ size_t curr_size = curr.size();
+ if (curr.size() > 1 && i > lag + MULTIPATH_MAX_LEN) {
+ DEBUG_PRINTF("range is larger than 16 in multi-path\n");
return false;
}
- for (size_t idx = 0; idx < curr_size; idx++) {
- NFAVertex v = curr[idx];
- if (v == g.startDs) {
- continue;
- }
- assert(!is_special(v, g));
-
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- if (u == g.start || u == g.startDs) {
- curr[idx] = g.startDs;
- break;
- }
- }
-
- if (is_special(curr[idx], g)) {
- continue;
- }
-
- for (auto u : inv_adjacent_vertices_range(v, g)) {
- curr_active = true;
- if (curr[idx] == v) {
- curr[idx] = u;
- looks[idx][0 - i] = g[u].char_reach;
- total_len++;
- } else {
- curr.push_back(u);
- looks.push_back(looks[idx]);
- (looks.back())[0 - i] = g[u].char_reach;
- total_len += looks.back().size();
- }
-
- if (curr.size() > MAX_LOOKAROUND_PATHS && total_len > 64) {
- DEBUG_PRINTF("too many branches\n");
- return false;
- }
- }
- }
- if (!curr_active) {
- break;
- }
- }
-
- if (curr_active) {
- DEBUG_PRINTF("single path too long\n");
- return false;
- }
-
- // More than 8 paths, check multi-path shufti.
- if (curr.size() > MAX_LOOKAROUND_PATHS) {
- u32 bucket_size = total_len > 32 ? 8 : 16;
- if (!checkShuftiBuckets(looks, bucket_size)) {
- DEBUG_PRINTF("shufti has too many buckets\n");
+ for (size_t idx = 0; idx < curr_size; idx++) {
+ NFAVertex v = curr[idx];
+ if (v == g.startDs) {
+ continue;
+ }
+ assert(!is_special(v, g));
+
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ if (u == g.start || u == g.startDs) {
+ curr[idx] = g.startDs;
+ break;
+ }
+ }
+
+ if (is_special(curr[idx], g)) {
+ continue;
+ }
+
+ for (auto u : inv_adjacent_vertices_range(v, g)) {
+ curr_active = true;
+ if (curr[idx] == v) {
+ curr[idx] = u;
+ looks[idx][0 - i] = g[u].char_reach;
+ total_len++;
+ } else {
+ curr.push_back(u);
+ looks.push_back(looks[idx]);
+ (looks.back())[0 - i] = g[u].char_reach;
+ total_len += looks.back().size();
+ }
+
+ if (curr.size() > MAX_LOOKAROUND_PATHS && total_len > 64) {
+ DEBUG_PRINTF("too many branches\n");
+ return false;
+ }
+ }
+ }
+ if (!curr_active) {
+ break;
+ }
+ }
+
+ if (curr_active) {
+ DEBUG_PRINTF("single path too long\n");
+ return false;
+ }
+
+ // More than 8 paths, check multi-path shufti.
+ if (curr.size() > MAX_LOOKAROUND_PATHS) {
+ u32 bucket_size = total_len > 32 ? 8 : 16;
+ if (!checkShuftiBuckets(looks, bucket_size)) {
+ DEBUG_PRINTF("shufti has too many buckets\n");
return false;
}
- }
+ }
- assert(!looks.empty());
- if (looks.size() == 1) {
- DEBUG_PRINTF("single lookaround\n");
- } else {
- DEBUG_PRINTF("multi-path lookaround\n");
+ assert(!looks.empty());
+ if (looks.size() == 1) {
+ DEBUG_PRINTF("single lookaround\n");
+ } else {
+ DEBUG_PRINTF("multi-path lookaround\n");
}
DEBUG_PRINTF("done\n");
return true;
}
bool makeLeftfixLookaround(const RoseBuildImpl &build, const RoseVertex v,
- vector<vector<LookEntry>> &lookaround) {
+ vector<vector<LookEntry>> &lookaround) {
lookaround.clear();
const RoseGraph &g = build.g;
@@ -823,19 +823,19 @@ bool makeLeftfixLookaround(const RoseBuildImpl &build, const RoseVertex v,
return false;
}
- vector<map<s32, CharReach>> looks;
- if (!getTransientPrefixReach(*leftfix.graph(), g[v].left.leftfix_report,
- g[v].left.lag, looks)) {
- DEBUG_PRINTF("graph has loop or too large\n");
+ vector<map<s32, CharReach>> looks;
+ if (!getTransientPrefixReach(*leftfix.graph(), g[v].left.leftfix_report,
+ g[v].left.lag, looks)) {
+ DEBUG_PRINTF("graph has loop or too large\n");
return false;
}
- if (!trimMultipathLeftfix(build, v, looks)) {
+ if (!trimMultipathLeftfix(build, v, looks)) {
return false;
}
- transToLookaround(looks, lookaround);
+ transToLookaround(looks, lookaround);
- return !lookaround.empty();
+ return !lookaround.empty();
}
void mergeLookaround(vector<LookEntry> &lookaround,
@@ -846,7 +846,7 @@ void mergeLookaround(vector<LookEntry> &lookaround,
}
// Don't merge lookarounds at offsets we already have entries for.
- flat_set<s8> offsets;
+ flat_set<s8> offsets;
for (const auto &e : lookaround) {
offsets.insert(e.offset);
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_lookaround.h b/contrib/libs/hyperscan/src/rose/rose_build_lookaround.h
index d1984f5b4af..70d4217ccc1 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_lookaround.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_lookaround.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,13 +33,13 @@
#define ROSE_ROSE_BUILD_LOOKAROUND_H
#include "rose_graph.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include <vector>
-/** \brief Max path number for multi-path lookaround. */
-#define MAX_LOOKAROUND_PATHS 8
-
+/** \brief Max path number for multi-path lookaround. */
+#define MAX_LOOKAROUND_PATHS 8
+
namespace ue2 {
class CharReach;
@@ -48,7 +48,7 @@ class RoseBuildImpl;
/** \brief Lookaround entry prototype, describing the reachability at a given
* distance from the end of a role match. */
struct LookEntry {
- LookEntry() : offset(0) {}
+ LookEntry() : offset(0) {}
LookEntry(s8 offset_in, const CharReach &reach_in)
: offset(offset_in), reach(reach_in) {}
s8 offset; //!< offset from role match location.
@@ -60,7 +60,7 @@ struct LookEntry {
};
void findLookaroundMasks(const RoseBuildImpl &tbi, const RoseVertex v,
- std::vector<LookEntry> &look_more);
+ std::vector<LookEntry> &look_more);
/**
* \brief If possible, render the prefix of the given vertex as a lookaround.
@@ -69,22 +69,22 @@ void findLookaroundMasks(const RoseBuildImpl &tbi, const RoseVertex v,
* it can be satisfied with a lookaround alone.
*/
bool makeLeftfixLookaround(const RoseBuildImpl &build, const RoseVertex v,
- std::vector<std::vector<LookEntry>> &lookaround);
+ std::vector<std::vector<LookEntry>> &lookaround);
void mergeLookaround(std::vector<LookEntry> &lookaround,
const std::vector<LookEntry> &more_lookaround);
} // namespace ue2
-namespace std {
-
-template<>
-struct hash<ue2::LookEntry> {
- size_t operator()(const ue2::LookEntry &l) const {
- return ue2::hash_all(l.offset, l.reach);
- }
-};
-
-} // namespace std
-
+namespace std {
+
+template<>
+struct hash<ue2::LookEntry> {
+ size_t operator()(const ue2::LookEntry &l) const {
+ return ue2::hash_all(l.offset, l.reach);
+ }
+};
+
+} // namespace std
+
#endif // ROSE_ROSE_BUILD_LOOKAROUND_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_matchers.cpp b/contrib/libs/hyperscan/src/rose/rose_build_matchers.cpp
index f172c095368..4fde4c44182 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_matchers.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_matchers.cpp
@@ -1,1053 +1,1053 @@
-/*
+/*
* Copyright (c) 2016-2019, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose build: code for constructing literal tables.
- */
-
-#include "rose_build_matchers.h"
-
-#include "rose_build_dump.h"
-#include "rose_build_impl.h"
-#include "rose_build_lit_accel.h"
-#include "rose_build_width.h"
-#include "hwlm/hwlm_build.h"
-#include "hwlm/hwlm_internal.h"
-#include "hwlm/hwlm_literal.h"
-#include "nfa/castlecompile.h"
-#include "nfa/nfa_api_queue.h"
-#include "util/charreach_util.h"
-#include "util/compile_context.h"
-#include "util/compile_error.h"
-#include "util/dump_charclass.h"
-#include "util/make_unique.h"
-#include "util/report.h"
-#include "util/report_manager.h"
-#include "util/verify_types.h"
-#include "ue2common.h"
-
-#include <iomanip>
-#include <sstream>
-
-#include <boost/range/adaptor/map.hpp>
-#include <boost/range/adaptor/reversed.hpp>
-
-using namespace std;
-using boost::adaptors::map_values;
-
-namespace ue2 {
-
-static const size_t MAX_ACCEL_STRING_LEN = 16;
-
-#if defined(DEBUG) || defined(DUMP_SUPPORT)
-static UNUSED
-string dumpMask(const vector<u8> &v) {
- ostringstream oss;
- for (u8 e : v) {
- oss << setfill('0') << setw(2) << hex << (unsigned int)e;
- }
- return oss.str();
-}
-#endif
-
-static
-bool maskFromLeftGraph(const LeftEngInfo &left, vector<u8> &msk,
- vector<u8> &cmp) {
- const u32 lag = left.lag;
- const ReportID report = left.leftfix_report;
-
- DEBUG_PRINTF("leftfix with lag %u, report %u\n", lag, report);
-
- assert(left.graph);
- const NGHolder &h = *left.graph;
- assert(in_degree(h.acceptEod, h) == 1); // no eod reports
-
- // Start with the set of reporter vertices for this leftfix.
- set<NFAVertex> curr;
- for (auto u : inv_adjacent_vertices_range(h.accept, h)) {
- if (contains(h[u].reports, report)) {
- curr.insert(u);
- }
- }
- assert(!curr.empty());
-
- size_t i = HWLM_MASKLEN - lag - 1;
- do {
- if (curr.empty() || contains(curr, h.start)
- || contains(curr, h.startDs)) {
- DEBUG_PRINTF("end of the road\n");
- break;
- }
-
- set<NFAVertex> next;
- CharReach cr;
- for (NFAVertex v : curr) {
- const auto &v_cr = h[v].char_reach;
- DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index,
- describeClass(v_cr).c_str());
- cr |= v_cr;
- insert(&next, inv_adjacent_vertices(v, h));
- }
- make_and_cmp_mask(cr, &msk.at(i), &cmp.at(i));
- DEBUG_PRINTF("%zu: reach=%s, msk=%u, cmp=%u\n", i,
- describeClass(cr).c_str(), msk[i], cmp[i]);
- curr.swap(next);
- } while (i-- > 0);
-
- return true;
-}
-
-static
-bool maskFromLeftCastle(const LeftEngInfo &left, vector<u8> &msk,
- vector<u8> &cmp) {
- const u32 lag = left.lag;
- const ReportID report = left.leftfix_report;
-
- DEBUG_PRINTF("leftfix with lag %u, report %u\n", lag, report);
-
- assert(left.castle);
- const CastleProto &c = *left.castle;
-
- depth min_width(depth::infinity());
- for (const PureRepeat &repeat : c.repeats | map_values) {
- if (contains(repeat.reports, report)) {
- min_width = min(min_width, repeat.bounds.min);
- }
- }
-
- DEBUG_PRINTF("castle min width for this report is %s\n",
- min_width.str().c_str());
-
- if (!min_width.is_finite() || min_width == depth(0)) {
- DEBUG_PRINTF("bad min width\n");
- return false;
- }
-
- u32 len = min_width;
- u32 end = HWLM_MASKLEN - lag;
- for (u32 i = end; i > end - min(end, len); i--) {
- make_and_cmp_mask(c.reach(), &msk.at(i - 1), &cmp.at(i - 1));
- }
-
- return true;
-}
-
-static
-bool maskFromLeft(const LeftEngInfo &left, vector<u8> &msk, vector<u8> &cmp) {
- if (left.lag >= HWLM_MASKLEN) {
- DEBUG_PRINTF("too much lag\n");
- return false;
- }
-
- if (left.graph) {
- return maskFromLeftGraph(left, msk, cmp);
- } else if (left.castle) {
- return maskFromLeftCastle(left, msk, cmp);
- }
-
- return false;
-}
-
-static
-bool maskFromPreds(const RoseBuildImpl &build, const rose_literal_id &id,
- const RoseVertex v, vector<u8> &msk, vector<u8> &cmp) {
- const RoseGraph &g = build.g;
-
- // For right now, wuss out and only handle cases with one pred.
- if (in_degree(v, g) != 1) {
- return false;
- }
-
- // Root successors have no literal before them.
- if (build.isRootSuccessor(v)) {
- return false;
- }
-
- // If we have a single predecessor with a short bound, we may be able to
- // fill out a mask with the trailing bytes of the previous literal. This
- // allows us to improve literals like the 'bar' in 'fo.bar'.
-
- RoseEdge e = *(in_edges(v, g).first);
- u32 bound = g[e].maxBound;
- if (bound != g[e].minBound || bound >= HWLM_MASKLEN) {
- return false;
- }
-
- bound += id.s.length();
- if (bound >= HWLM_MASKLEN) {
- return false;
- }
-
- DEBUG_PRINTF("bound %u\n", bound);
-
- RoseVertex u = source(e, g);
- if (g[u].literals.size() != 1) {
- DEBUG_PRINTF("u has %zu literals\n", g[u].literals.size());
- return false;
- }
-
- u32 u_lit_id = *(g[u].literals.begin());
- const rose_literal_id &u_id = build.literals.at(u_lit_id);
- DEBUG_PRINTF("u has lit: %s\n", escapeString(u_id.s).c_str());
-
- // Number of characters to take from the back of u's literal.
- size_t u_len = u_id.s.length();
- size_t u_sublen = min(u_len, (size_t)HWLM_MASKLEN - bound);
-
- size_t i = HWLM_MASKLEN - (bound + u_sublen);
-
- ue2_literal::const_iterator it, ite;
- for (it = u_id.s.begin() + (u_len - u_sublen), ite = u_id.s.end();
- it != ite; ++it) {
- make_and_cmp_mask(*it, &msk.at(i), &cmp.at(i));
- ++i;
- }
-
- return true;
-}
-
-static
-bool addSurroundingMask(const RoseBuildImpl &build, const rose_literal_id &id,
- const RoseVertex v, vector<u8> &msk, vector<u8> &cmp) {
- // Start with zero masks.
- msk.assign(HWLM_MASKLEN, 0);
- cmp.assign(HWLM_MASKLEN, 0);
-
- const LeftEngInfo &left = build.g[v].left;
- if (left && left.lag < HWLM_MASKLEN) {
- if (maskFromLeft(left, msk, cmp)) {
- DEBUG_PRINTF("mask from a leftfix!\n");
- return true;
- }
- }
-
- if (id.s.length() < HWLM_MASKLEN) {
- if (maskFromPreds(build, id, v, msk, cmp)) {
- DEBUG_PRINTF("mask from preds!\n");
- return true;
- }
- }
-
- return false;
-}
-
-static
-bool hamsterMaskCombine(vector<u8> &msk, vector<u8> &cmp,
- const vector<u8> &v_msk, const vector<u8> &v_cmp) {
- assert(msk.size() == HWLM_MASKLEN && cmp.size() == HWLM_MASKLEN);
- assert(v_msk.size() == HWLM_MASKLEN && v_cmp.size() == HWLM_MASKLEN);
-
- u8 all_masks = 0;
-
- for (size_t i = 0; i < HWLM_MASKLEN; i++) {
- u8 filter = ~(cmp[i] ^ v_cmp[i]);
- msk[i] &= v_msk[i];
- msk[i] &= filter;
- cmp[i] &= filter;
-
- all_masks |= msk[i];
- }
-
- // Return false if we have no bits on in any mask elements.
- return all_masks != 0;
-}
-
-static
-bool addSurroundingMask(const RoseBuildImpl &build, const rose_literal_id &id,
- const rose_literal_info &info, vector<u8> &msk,
- vector<u8> &cmp) {
- if (!build.cc.grey.roseHamsterMasks) {
- return false;
- }
-
- if (!info.delayed_ids.empty()) {
- // Not safe to add masks to delayed literals at this late stage.
- return false;
- }
-
- msk.assign(HWLM_MASKLEN, 0);
- cmp.assign(HWLM_MASKLEN, 0);
-
- size_t num = 0;
- vector<u8> v_msk, v_cmp;
-
- for (RoseVertex v : info.vertices) {
- if (!addSurroundingMask(build, id, v, v_msk, v_cmp)) {
- DEBUG_PRINTF("no mask\n");
- return false;
- }
-
- if (!num++) {
- // First (or only) vertex, this becomes the mask/cmp pair.
- msk = v_msk;
- cmp = v_cmp;
- } else {
- // Multiple vertices with potentially different masks. We combine
- // them into an 'advisory' mask.
- if (!hamsterMaskCombine(msk, cmp, v_msk, v_cmp)) {
- DEBUG_PRINTF("mask went to zero\n");
- return false;
- }
- }
- }
-
- normaliseLiteralMask(id.s, msk, cmp);
-
- if (msk.empty()) {
- DEBUG_PRINTF("no mask\n");
- return false;
- }
-
- DEBUG_PRINTF("msk=%s, cmp=%s\n", dumpMask(msk).c_str(),
- dumpMask(cmp).c_str());
- return true;
-}
-
-void findMoreLiteralMasks(RoseBuildImpl &build) {
- if (!build.cc.grey.roseHamsterMasks) {
- return;
- }
-
- vector<u32> candidates;
- for (u32 id = 0; id < build.literals.size(); id++) {
- const auto &lit = build.literals.at(id);
-
- if (lit.delay || build.isDelayed(id)) {
- continue;
- }
-
- // Literal masks are only allowed for literals that will end up in an
- // HWLM table.
- switch (lit.table) {
- case ROSE_FLOATING:
- case ROSE_EOD_ANCHORED:
- case ROSE_ANCHORED_SMALL_BLOCK:
- break;
- default:
- continue;
- }
-
- candidates.push_back(id);
- }
-
- for (const u32 &id : candidates) {
- const auto &lit = build.literals.at(id);
- auto &lit_info = build.literal_info.at(id);
-
- vector<u8> msk, cmp;
- if (!addSurroundingMask(build, lit, lit_info, msk, cmp)) {
- continue;
- }
- DEBUG_PRINTF("found surrounding mask for lit_id=%u (%s)\n", id,
- dumpString(lit.s).c_str());
- u32 new_id = build.getLiteralId(lit.s, msk, cmp, lit.delay, lit.table);
- if (new_id == id) {
- continue;
- }
- DEBUG_PRINTF("replacing with new lit_id=%u\n", new_id);
-
- // Note that our new literal may already exist and have vertices, etc.
- // We assume that this transform is happening prior to group assignment.
- assert(lit_info.group_mask == 0);
- auto &new_info = build.literal_info.at(new_id);
-
- // Move the vertices across.
- new_info.vertices.insert(begin(lit_info.vertices),
- end(lit_info.vertices));
- for (auto v : lit_info.vertices) {
- build.g[v].literals.erase(id);
- build.g[v].literals.insert(new_id);
- }
- lit_info.vertices.clear();
-
- // Preserve other properties.
- new_info.requires_benefits = lit_info.requires_benefits;
- }
-}
-
-// The mask already associated with the literal and any mask due to
-// mixed-case is mandatory.
-static
-void addLiteralMask(const rose_literal_id &id, vector<u8> &msk,
- vector<u8> &cmp) {
- const size_t suffix_len = min(id.s.length(), size_t{HWLM_MASKLEN});
- bool mixed_suffix = mixed_sensitivity_in(id.s.end() - suffix_len,
- id.s.end());
-
- if (id.msk.empty() && !mixed_suffix) {
- return;
- }
-
- while (msk.size() < HWLM_MASKLEN) {
- msk.insert(msk.begin(), 0);
- cmp.insert(cmp.begin(), 0);
- }
-
- if (!id.msk.empty()) {
- assert(id.msk.size() <= HWLM_MASKLEN);
- assert(id.msk.size() == id.cmp.size());
- for (size_t i = 0; i < id.msk.size(); i++) {
- size_t mand_offset = msk.size() - i - 1;
- size_t lit_offset = id.msk.size() - i - 1;
- msk[mand_offset] = id.msk[lit_offset];
- cmp[mand_offset] = id.cmp[lit_offset];
- }
- }
-
- if (mixed_suffix) {
- auto it = id.s.rbegin();
- for (size_t i = 0; i < suffix_len; ++i, ++it) {
- const auto &c = *it;
- if (!c.nocase) {
- size_t offset = HWLM_MASKLEN - i - 1;
- DEBUG_PRINTF("offset %zu must match 0x%02x exactly\n", offset,
- c.c);
- make_and_cmp_mask(c, &msk[offset], &cmp[offset]);
- }
- }
- }
-
- normaliseLiteralMask(id.s, msk, cmp);
-}
-
-static
-bool isDirectHighlander(const RoseBuildImpl &build, const u32 id,
- const rose_literal_info &info) {
- if (!build.isDirectReport(id)) {
- return false;
- }
-
- auto is_simple_exhaustible = [&build](ReportID rid) {
- const Report &report = build.rm.getReport(rid);
- return isSimpleExhaustible(report);
- };
-
- assert(!info.vertices.empty());
- for (const auto &v : info.vertices) {
- const auto &reports = build.g[v].reports;
- assert(!reports.empty());
- if (!all_of(begin(reports), end(reports),
- is_simple_exhaustible)) {
- return false;
- }
- }
- return true;
-}
-
-// Called by isNoRunsLiteral below.
-static
-bool isNoRunsVertex(const RoseBuildImpl &build, RoseVertex u) {
- const RoseGraph &g = build.g;
- if (!g[u].isBoring()) {
- DEBUG_PRINTF("u=%zu is not boring\n", g[u].index);
- return false;
- }
-
- if (!g[u].reports.empty()) {
- DEBUG_PRINTF("u=%zu has accept\n", g[u].index);
- return false;
- }
-
- /* TODO: handle non-root roles as well. It can't be that difficult... */
-
- if (in_degree(u, g) != 1) {
- DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index);
- return false;
- }
-
- RoseEdge e = edge(build.root, u, g);
-
- if (!e) {
- DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index);
- return false;
- }
-
- if (g[e].minBound != 0 || g[e].maxBound != ROSE_BOUND_INF) {
- DEBUG_PRINTF("u=%zu has bounds from root\n", g[u].index);
- return false;
- }
-
- for (const auto &oe : out_edges_range(u, g)) {
- RoseVertex v = target(oe, g);
- if (g[oe].maxBound != ROSE_BOUND_INF) {
- DEBUG_PRINTF("edge (%zu,%zu) has max bound\n", g[u].index,
- g[v].index);
- return false;
- }
- if (g[v].left) {
- DEBUG_PRINTF("v=%zu has rose prefix\n", g[v].index);
- return false;
- }
- }
- return true;
-}
-
-static
-bool isNoRunsLiteral(const RoseBuildImpl &build, const u32 id,
- const rose_literal_info &info, const size_t max_len) {
- DEBUG_PRINTF("lit id %u\n", id);
-
- if (info.requires_benefits) {
- DEBUG_PRINTF("requires benefits\n"); // which would need confirm
- return false;
- }
-
- size_t len = build.literals.at(id).s.length();
- if (len > max_len) {
- DEBUG_PRINTF("long literal, requires confirm\n");
- return false;
- }
-
- if (len > ROSE_SHORT_LITERAL_LEN_MAX) {
- DEBUG_PRINTF("medium-length literal, requires confirm\n");
- return false;
- }
-
- if (isDirectHighlander(build, id, info)) {
- DEBUG_PRINTF("highlander direct report\n");
- return true;
- }
-
- // Undelayed vertices.
- for (RoseVertex v : info.vertices) {
- if (!isNoRunsVertex(build, v)) {
- return false;
- }
- }
-
- // Delayed vertices.
- for (u32 d : info.delayed_ids) {
- assert(d < build.literal_info.size());
- const rose_literal_info &delayed_info = build.literal_info.at(d);
- assert(delayed_info.undelayed_id == id);
- for (RoseVertex v : delayed_info.vertices) {
- if (!isNoRunsVertex(build, v)) {
- return false;
- }
- }
- }
-
- DEBUG_PRINTF("is no-runs literal\n");
- return true;
-}
-
-static
-bool isNoRunsFragment(const RoseBuildImpl &build, const LitFragment &f,
- const size_t max_len) {
- // For the fragment to be marked "no runs", every literal it fires must
- // need no further confirmation work.
- return all_of_in(f.lit_ids, [&](u32 lit_id) {
- const auto &info = build.literal_info.at(lit_id);
- return isNoRunsLiteral(build, lit_id, info, max_len);
- });
-}
-
-static
-const raw_puff &getChainedPuff(const RoseBuildImpl &build,
- const Report &report) {
- DEBUG_PRINTF("chained report, event %u\n", report.onmatch);
-
- // MPV has already been moved to the outfixes vector.
- assert(!build.mpv_outfix);
-
- auto mpv_outfix_it = find_if(
- begin(build.outfixes), end(build.outfixes),
- [](const OutfixInfo &outfix) { return outfix.is_nonempty_mpv(); });
- assert(mpv_outfix_it != end(build.outfixes));
- const auto *mpv = mpv_outfix_it->mpv();
-
- u32 puff_index = report.onmatch - MQE_TOP_FIRST;
- assert(puff_index < mpv->triggered_puffettes.size());
- return mpv->triggered_puffettes.at(puff_index);
-}
-
-/**
- * \brief Returns a conservative estimate of the minimum offset at which the
- * given literal can lead to a report.
- *
- * TODO: This could be made more precise by calculating a "distance to accept"
- * for every vertex in the graph; right now we're only accurate for leaf nodes.
- */
-static
-u64a literalMinReportOffset(const RoseBuildImpl &build,
- const rose_literal_id &lit,
- const rose_literal_info &info) {
- const auto &g = build.g;
-
- const u32 lit_len = verify_u32(lit.elength());
-
- u64a lit_min_offset = UINT64_MAX;
-
- for (const auto &v : info.vertices) {
- DEBUG_PRINTF("vertex %zu min_offset=%u\n", g[v].index, g[v].min_offset);
-
- u64a vert_offset = g[v].min_offset;
-
- if (vert_offset >= lit_min_offset) {
- continue;
- }
-
- u64a min_offset = UINT64_MAX;
-
- for (const auto &id : g[v].reports) {
- const Report &report = build.rm.getReport(id);
- DEBUG_PRINTF("report id %u, min offset=%llu\n", id,
- report.minOffset);
- if (report.type == INTERNAL_ROSE_CHAIN) {
- // This vertex triggers an MPV, which will fire reports after
- // repeating for a while.
- assert(report.minOffset == 0); // Should not have bounds.
- const auto &puff = getChainedPuff(build, report);
- DEBUG_PRINTF("chained puff repeats=%u\n", puff.repeats);
- const Report &puff_report = build.rm.getReport(puff.report);
- DEBUG_PRINTF("puff report %u, min offset=%llu\n", puff.report,
- puff_report.minOffset);
- min_offset = min(min_offset, max(vert_offset + puff.repeats,
- puff_report.minOffset));
- } else {
- DEBUG_PRINTF("report min offset=%llu\n", report.minOffset);
- min_offset = min(min_offset, max(vert_offset,
- report.minOffset));
- }
- }
-
- if (g[v].suffix) {
- depth suffix_width = findMinWidth(g[v].suffix, g[v].suffix.top);
- assert(suffix_width.is_reachable());
- DEBUG_PRINTF("suffix with width %s\n", suffix_width.str().c_str());
- min_offset = min(min_offset, vert_offset + suffix_width);
- }
-
- if (!isLeafNode(v, g) || min_offset == UINT64_MAX) {
- min_offset = vert_offset;
- }
-
- lit_min_offset = min(lit_min_offset, min_offset);
- }
-
- // If this literal in the undelayed literal corresponding to some delayed
- // literals, we must take their minimum offsets into account.
- for (const u32 &delayed_id : info.delayed_ids) {
- const auto &delayed_lit = build.literals.at(delayed_id);
- const auto &delayed_info = build.literal_info.at(delayed_id);
- u64a delayed_min_offset = literalMinReportOffset(build, delayed_lit,
- delayed_info);
- DEBUG_PRINTF("delayed_id=%u, min_offset = %llu\n", delayed_id,
- delayed_min_offset);
- lit_min_offset = min(lit_min_offset, delayed_min_offset);
- }
-
- // If we share a vertex with a shorter literal, our min offset might dip
- // below the length of this one.
- lit_min_offset = max(lit_min_offset, u64a{lit_len});
-
- return lit_min_offset;
-}
-
-template<class Container>
-void trim_to_suffix(Container &c, size_t len) {
- if (c.size() <= len) {
- return;
- }
-
- size_t suffix_len = c.size() - len;
- c.erase(c.begin(), c.begin() + suffix_len);
-}
-
-namespace {
-
-/** \brief Prototype for literal matcher construction. */
-struct MatcherProto {
- /** \brief Literal fragments used to construct the literal matcher. */
- vector<hwlmLiteral> lits;
-
- /** \brief Longer literals used for acceleration analysis. */
- vector<AccelString> accel_lits;
-
- /** \brief The history required by the literal matcher. */
- size_t history_required = 0;
-
- /** \brief Insert the contents of another MatcherProto. */
- void insert(const MatcherProto &a);
-};
-}
-
-static
-void addFragmentLiteral(const RoseBuildImpl &build, MatcherProto &mp,
- const LitFragment &f, u32 id, size_t max_len) {
- const rose_literal_id &lit = build.literals.at(id);
-
- DEBUG_PRINTF("lit='%s' (len %zu)\n", dumpString(lit.s).c_str(),
- lit.s.length());
-
- vector<u8> msk = lit.msk; // copy
- vector<u8> cmp = lit.cmp; // copy
-
- bool noruns = isNoRunsFragment(build, f, max_len);
- DEBUG_PRINTF("fragment is %s\n", noruns ? "noruns" : "not noruns");
-
- auto lit_final = lit.s; // copy
-
- if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
- DEBUG_PRINTF("truncating to tail of length %zu\n",
- size_t{ROSE_SHORT_LITERAL_LEN_MAX});
- lit_final.erase(0, lit_final.length() - ROSE_SHORT_LITERAL_LEN_MAX);
- // We shouldn't have set a threshold below 8 chars.
- assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
- assert(!noruns);
- }
-
- addLiteralMask(lit, msk, cmp);
-
- const auto &s_final = lit_final.get_string();
- bool nocase = lit_final.any_nocase();
-
- DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, cmp=%s\n",
- f.fragment_id, escapeString(s_final).c_str(), (int)nocase,
- noruns, dumpMask(msk).c_str(), dumpMask(cmp).c_str());
-
- if (!maskIsConsistent(s_final, nocase, msk, cmp)) {
- DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
- return;
- }
-
- const auto &groups = f.groups;
-
- mp.lits.emplace_back(move(s_final), nocase, noruns, f.fragment_id,
- groups, msk, cmp);
-}
-
-static
-void addAccelLiteral(MatcherProto &mp, const rose_literal_id &lit,
- const rose_literal_info &info, size_t max_len) {
- const auto &s = lit.s; // copy
-
- DEBUG_PRINTF("lit='%s' (len %zu)\n", dumpString(s).c_str(), s.length());
-
- vector<u8> msk = lit.msk; // copy
- vector<u8> cmp = lit.cmp; // copy
- addLiteralMask(lit, msk, cmp);
-
- if (!maskIsConsistent(s.get_string(), s.any_nocase(), msk, cmp)) {
- DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
- return;
- }
-
- // Literals used for acceleration must be limited to max_len, as that's all
- // we can see in history.
- string s_final = lit.s.get_string();
- trim_to_suffix(s_final, max_len);
- trim_to_suffix(msk, max_len);
- trim_to_suffix(cmp, max_len);
-
- mp.accel_lits.emplace_back(s_final, lit.s.any_nocase(), msk, cmp,
- info.group_mask);
-}
-
-/**
- * \brief Build up a vector of literals (and associated other data) for the
- * given table.
- *
- * If max_offset is specified (and not ROSE_BOUND_INF), then literals that can
- * only lead to a pattern match after max_offset may be excluded.
- */
-static
-MatcherProto makeMatcherProto(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments,
- rose_literal_table table, bool delay_rebuild,
- size_t max_len, u32 max_offset = ROSE_BOUND_INF) {
- MatcherProto mp;
-
- if (delay_rebuild) {
- assert(table == ROSE_FLOATING);
- assert(build.cc.streaming);
- }
-
- vector<u32> used_lit_ids;
-
- for (const auto &f : fragments) {
- assert(!f.lit_ids.empty());
-
- // All literals that share a fragment are in the same table.
- if (build.literals.at(f.lit_ids.front()).table != table) {
- continue; // next fragment.
- }
-
- DEBUG_PRINTF("fragment %u, %zu lit_ids\n", f.fragment_id,
- f.lit_ids.size());
-
- used_lit_ids.clear();
- for (u32 id : f.lit_ids) {
- const rose_literal_id &lit = build.literals.at(id);
- assert(id < build.literal_info.size());
- const auto &info = build.literal_info.at(id);
- if (lit.delay) {
- continue; /* delay id's are virtual-ish */
- }
-
- // When building the delay rebuild table, we only want to include
- // literals that have delayed variants.
- if (delay_rebuild && info.delayed_ids.empty()) {
- DEBUG_PRINTF("not needed for delay rebuild\n");
- continue;
- }
-
- if (max_offset != ROSE_BOUND_INF) {
- u64a min_report = literalMinReportOffset(build, lit, info);
- if (min_report > max_offset) {
- DEBUG_PRINTF("min report offset=%llu exceeds "
- "max_offset=%u\n", min_report, max_offset);
- continue;
- }
- }
-
- used_lit_ids.push_back(id);
- }
-
- if (used_lit_ids.empty()) {
- continue; // next fragment.
- }
-
- // Build our fragment (for the HWLM matcher) from the first literal.
- addFragmentLiteral(build, mp, f, used_lit_ids.front(), max_len);
-
- for (u32 id : used_lit_ids) {
- const rose_literal_id &lit = build.literals.at(id);
- assert(id < build.literal_info.size());
- const auto &info = build.literal_info.at(id);
-
- // All literals contribute accel information.
- addAccelLiteral(mp, lit, info, max_len);
-
- // All literals contribute to history requirement in streaming mode.
- if (build.cc.streaming) {
- size_t lit_hist_len =
- max(lit.msk.size(), min(lit.s.length(), max_len));
- lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
- DEBUG_PRINTF("lit requires %zu bytes of history\n",
- lit_hist_len);
- assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
- mp.history_required = max(mp.history_required, lit_hist_len);
- }
- }
- }
-
- sort_and_unique(mp.lits);
- sort_and_unique(mp.accel_lits);
-
- return mp;
-}
-
-void MatcherProto::insert(const MatcherProto &a) {
- ::ue2::insert(&lits, lits.end(), a.lits);
- ::ue2::insert(&accel_lits, accel_lits.end(), a.accel_lits);
- sort_and_unique(lits);
- sort_and_unique(accel_lits);
- history_required = max(history_required, a.history_required);
-}
-
-static
-void buildAccel(const RoseBuildImpl &build,
- const vector<AccelString> &accel_lits, HWLM &hwlm) {
- if (!build.cc.grey.hamsterAccelForward) {
- return;
- }
-
- if (hwlm.type == HWLM_ENGINE_NOOD) {
- return;
- }
-
- buildForwardAccel(&hwlm, accel_lits, build.getInitialGroups());
-}
-
-bytecode_ptr<HWLM>
-buildHWLMMatcher(const RoseBuildImpl &build, LitProto *litProto) {
- if (!litProto) {
- return nullptr;
- }
- auto hwlm = hwlmBuild(*litProto->hwlmProto, build.cc,
- build.getInitialGroups());
- if (!hwlm) {
- throw CompileError("Unable to generate bytecode.");
- }
-
- buildAccel(build, litProto->accel_lits, *hwlm);
-
- DEBUG_PRINTF("built eod-anchored literal table size %zu bytes\n",
- hwlm.size());
- return hwlm;
-}
-
-unique_ptr<LitProto>
-buildFloatingMatcherProto(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments,
- size_t longLitLengthThreshold,
- rose_group *fgroups,
- size_t *historyRequired) {
- DEBUG_PRINTF("Floating literal matcher\n");
- *fgroups = 0;
-
- auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
- longLitLengthThreshold);
- if (mp.lits.empty()) {
- DEBUG_PRINTF("empty floating matcher\n");
- return nullptr;
- }
- dumpMatcherLiterals(mp.lits, "floating", build.cc.grey);
-
- for (const hwlmLiteral &lit : mp.lits) {
- *fgroups |= lit.groups;
- }
-
- if (build.cc.streaming) {
- DEBUG_PRINTF("history_required=%zu\n", mp.history_required);
- assert(mp.history_required <= build.cc.grey.maxHistoryAvailable);
- *historyRequired = max(*historyRequired, mp.history_required);
- }
-
- auto proto = hwlmBuildProto(mp.lits, false, build.cc);
-
- if (!proto) {
- throw CompileError("Unable to generate literal matcher proto.");
- }
-
- return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
-}
-
-unique_ptr<LitProto>
-buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments,
- size_t longLitLengthThreshold) {
- DEBUG_PRINTF("Delay literal matcher\n");
- if (!build.cc.streaming) {
- DEBUG_PRINTF("not streaming\n");
- return nullptr;
- }
-
- auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, true,
- longLitLengthThreshold);
- if (mp.lits.empty()) {
- DEBUG_PRINTF("empty delay rebuild matcher\n");
- return nullptr;
- }
- dumpMatcherLiterals(mp.lits, "delay_rebuild", build.cc.grey);
-
-
- auto proto = hwlmBuildProto(mp.lits, false, build.cc);
-
- if (!proto) {
- throw CompileError("Unable to generate literal matcher proto.");
- }
-
- return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
-}
-
-unique_ptr<LitProto>
-buildSmallBlockMatcherProto(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments) {
- DEBUG_PRINTF("Small block literal matcher\n");
- if (build.cc.streaming) {
- DEBUG_PRINTF("streaming mode\n");
- return nullptr;
- }
-
- u32 float_min = findMinWidth(build, ROSE_FLOATING);
- if (float_min > ROSE_SMALL_BLOCK_LEN) {
- DEBUG_PRINTF("floating table has large min width %u, fail\n",
- float_min);
- return nullptr;
- }
-
- auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
- ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
- if (mp.lits.empty()) {
- DEBUG_PRINTF("no floating table\n");
- return nullptr;
- } else if (mp.lits.size() == 1) {
- DEBUG_PRINTF("single floating literal, noodle will be fast enough\n");
- return nullptr;
- }
-
- auto mp_anchored = makeMatcherProto(build, fragments,
- ROSE_ANCHORED_SMALL_BLOCK, false,
- ROSE_SMALL_BLOCK_LEN,
- ROSE_SMALL_BLOCK_LEN);
- if (mp_anchored.lits.empty()) {
- DEBUG_PRINTF("no small-block anchored literals\n");
- return nullptr;
- }
-
- mp.insert(mp_anchored);
- dumpMatcherLiterals(mp.lits, "smallblock", build.cc.grey);
-
- // None of our literals should be longer than the small block limit.
- assert(all_of(begin(mp.lits), end(mp.lits), [](const hwlmLiteral &lit) {
- return lit.s.length() <= ROSE_SMALL_BLOCK_LEN;
- }));
-
- if (mp.lits.empty()) {
- DEBUG_PRINTF("no literals shorter than small block len\n");
- return nullptr;
- }
-
- auto proto = hwlmBuildProto(mp.lits, false, build.cc);
-
- if (!proto) {
- throw CompileError("Unable to generate literal matcher proto.");
- }
-
- return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
-}
-
-unique_ptr<LitProto>
-buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
- const vector<LitFragment> &fragments) {
- DEBUG_PRINTF("Eod anchored literal matcher\n");
- auto mp = makeMatcherProto(build, fragments, ROSE_EOD_ANCHORED, false,
- build.ematcher_region_size);
-
- if (mp.lits.empty()) {
- DEBUG_PRINTF("no eod anchored literals\n");
- assert(!build.ematcher_region_size);
- return nullptr;
- }
- dumpMatcherLiterals(mp.lits, "eod", build.cc.grey);
-
- assert(build.ematcher_region_size);
-
- auto proto = hwlmBuildProto(mp.lits, false, build.cc);
-
- if (!proto) {
- throw CompileError("Unable to generate literal matcher proto.");
- }
-
- return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
-}
-
-} // namespace ue2
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose build: code for constructing literal tables.
+ */
+
+#include "rose_build_matchers.h"
+
+#include "rose_build_dump.h"
+#include "rose_build_impl.h"
+#include "rose_build_lit_accel.h"
+#include "rose_build_width.h"
+#include "hwlm/hwlm_build.h"
+#include "hwlm/hwlm_internal.h"
+#include "hwlm/hwlm_literal.h"
+#include "nfa/castlecompile.h"
+#include "nfa/nfa_api_queue.h"
+#include "util/charreach_util.h"
+#include "util/compile_context.h"
+#include "util/compile_error.h"
+#include "util/dump_charclass.h"
+#include "util/make_unique.h"
+#include "util/report.h"
+#include "util/report_manager.h"
+#include "util/verify_types.h"
+#include "ue2common.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/adaptor/reversed.hpp>
+
+using namespace std;
+using boost::adaptors::map_values;
+
+namespace ue2 {
+
+static const size_t MAX_ACCEL_STRING_LEN = 16;
+
+#if defined(DEBUG) || defined(DUMP_SUPPORT)
+static UNUSED
+string dumpMask(const vector<u8> &v) {
+ ostringstream oss;
+ for (u8 e : v) {
+ oss << setfill('0') << setw(2) << hex << (unsigned int)e;
+ }
+ return oss.str();
+}
+#endif
+
+static
+bool maskFromLeftGraph(const LeftEngInfo &left, vector<u8> &msk,
+ vector<u8> &cmp) {
+ const u32 lag = left.lag;
+ const ReportID report = left.leftfix_report;
+
+ DEBUG_PRINTF("leftfix with lag %u, report %u\n", lag, report);
+
+ assert(left.graph);
+ const NGHolder &h = *left.graph;
+ assert(in_degree(h.acceptEod, h) == 1); // no eod reports
+
+ // Start with the set of reporter vertices for this leftfix.
+ set<NFAVertex> curr;
+ for (auto u : inv_adjacent_vertices_range(h.accept, h)) {
+ if (contains(h[u].reports, report)) {
+ curr.insert(u);
+ }
+ }
+ assert(!curr.empty());
+
+ size_t i = HWLM_MASKLEN - lag - 1;
+ do {
+ if (curr.empty() || contains(curr, h.start)
+ || contains(curr, h.startDs)) {
+ DEBUG_PRINTF("end of the road\n");
+ break;
+ }
+
+ set<NFAVertex> next;
+ CharReach cr;
+ for (NFAVertex v : curr) {
+ const auto &v_cr = h[v].char_reach;
+ DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index,
+ describeClass(v_cr).c_str());
+ cr |= v_cr;
+ insert(&next, inv_adjacent_vertices(v, h));
+ }
+ make_and_cmp_mask(cr, &msk.at(i), &cmp.at(i));
+ DEBUG_PRINTF("%zu: reach=%s, msk=%u, cmp=%u\n", i,
+ describeClass(cr).c_str(), msk[i], cmp[i]);
+ curr.swap(next);
+ } while (i-- > 0);
+
+ return true;
+}
+
+static
+bool maskFromLeftCastle(const LeftEngInfo &left, vector<u8> &msk,
+ vector<u8> &cmp) {
+ const u32 lag = left.lag;
+ const ReportID report = left.leftfix_report;
+
+ DEBUG_PRINTF("leftfix with lag %u, report %u\n", lag, report);
+
+ assert(left.castle);
+ const CastleProto &c = *left.castle;
+
+ depth min_width(depth::infinity());
+ for (const PureRepeat &repeat : c.repeats | map_values) {
+ if (contains(repeat.reports, report)) {
+ min_width = min(min_width, repeat.bounds.min);
+ }
+ }
+
+ DEBUG_PRINTF("castle min width for this report is %s\n",
+ min_width.str().c_str());
+
+ if (!min_width.is_finite() || min_width == depth(0)) {
+ DEBUG_PRINTF("bad min width\n");
+ return false;
+ }
+
+ u32 len = min_width;
+ u32 end = HWLM_MASKLEN - lag;
+ for (u32 i = end; i > end - min(end, len); i--) {
+ make_and_cmp_mask(c.reach(), &msk.at(i - 1), &cmp.at(i - 1));
+ }
+
+ return true;
+}
+
+static
+bool maskFromLeft(const LeftEngInfo &left, vector<u8> &msk, vector<u8> &cmp) {
+ if (left.lag >= HWLM_MASKLEN) {
+ DEBUG_PRINTF("too much lag\n");
+ return false;
+ }
+
+ if (left.graph) {
+ return maskFromLeftGraph(left, msk, cmp);
+ } else if (left.castle) {
+ return maskFromLeftCastle(left, msk, cmp);
+ }
+
+ return false;
+}
+
+static
+bool maskFromPreds(const RoseBuildImpl &build, const rose_literal_id &id,
+ const RoseVertex v, vector<u8> &msk, vector<u8> &cmp) {
+ const RoseGraph &g = build.g;
+
+ // For right now, wuss out and only handle cases with one pred.
+ if (in_degree(v, g) != 1) {
+ return false;
+ }
+
+ // Root successors have no literal before them.
+ if (build.isRootSuccessor(v)) {
+ return false;
+ }
+
+ // If we have a single predecessor with a short bound, we may be able to
+ // fill out a mask with the trailing bytes of the previous literal. This
+ // allows us to improve literals like the 'bar' in 'fo.bar'.
+
+ RoseEdge e = *(in_edges(v, g).first);
+ u32 bound = g[e].maxBound;
+ if (bound != g[e].minBound || bound >= HWLM_MASKLEN) {
+ return false;
+ }
+
+ bound += id.s.length();
+ if (bound >= HWLM_MASKLEN) {
+ return false;
+ }
+
+ DEBUG_PRINTF("bound %u\n", bound);
+
+ RoseVertex u = source(e, g);
+ if (g[u].literals.size() != 1) {
+ DEBUG_PRINTF("u has %zu literals\n", g[u].literals.size());
+ return false;
+ }
+
+ u32 u_lit_id = *(g[u].literals.begin());
+ const rose_literal_id &u_id = build.literals.at(u_lit_id);
+ DEBUG_PRINTF("u has lit: %s\n", escapeString(u_id.s).c_str());
+
+ // Number of characters to take from the back of u's literal.
+ size_t u_len = u_id.s.length();
+ size_t u_sublen = min(u_len, (size_t)HWLM_MASKLEN - bound);
+
+ size_t i = HWLM_MASKLEN - (bound + u_sublen);
+
+ ue2_literal::const_iterator it, ite;
+ for (it = u_id.s.begin() + (u_len - u_sublen), ite = u_id.s.end();
+ it != ite; ++it) {
+ make_and_cmp_mask(*it, &msk.at(i), &cmp.at(i));
+ ++i;
+ }
+
+ return true;
+}
+
+static
+bool addSurroundingMask(const RoseBuildImpl &build, const rose_literal_id &id,
+ const RoseVertex v, vector<u8> &msk, vector<u8> &cmp) {
+ // Start with zero masks.
+ msk.assign(HWLM_MASKLEN, 0);
+ cmp.assign(HWLM_MASKLEN, 0);
+
+ const LeftEngInfo &left = build.g[v].left;
+ if (left && left.lag < HWLM_MASKLEN) {
+ if (maskFromLeft(left, msk, cmp)) {
+ DEBUG_PRINTF("mask from a leftfix!\n");
+ return true;
+ }
+ }
+
+ if (id.s.length() < HWLM_MASKLEN) {
+ if (maskFromPreds(build, id, v, msk, cmp)) {
+ DEBUG_PRINTF("mask from preds!\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static
+bool hamsterMaskCombine(vector<u8> &msk, vector<u8> &cmp,
+ const vector<u8> &v_msk, const vector<u8> &v_cmp) {
+ assert(msk.size() == HWLM_MASKLEN && cmp.size() == HWLM_MASKLEN);
+ assert(v_msk.size() == HWLM_MASKLEN && v_cmp.size() == HWLM_MASKLEN);
+
+ u8 all_masks = 0;
+
+ for (size_t i = 0; i < HWLM_MASKLEN; i++) {
+ u8 filter = ~(cmp[i] ^ v_cmp[i]);
+ msk[i] &= v_msk[i];
+ msk[i] &= filter;
+ cmp[i] &= filter;
+
+ all_masks |= msk[i];
+ }
+
+ // Return false if we have no bits on in any mask elements.
+ return all_masks != 0;
+}
+
+static
+bool addSurroundingMask(const RoseBuildImpl &build, const rose_literal_id &id,
+ const rose_literal_info &info, vector<u8> &msk,
+ vector<u8> &cmp) {
+ if (!build.cc.grey.roseHamsterMasks) {
+ return false;
+ }
+
+ if (!info.delayed_ids.empty()) {
+ // Not safe to add masks to delayed literals at this late stage.
+ return false;
+ }
+
+ msk.assign(HWLM_MASKLEN, 0);
+ cmp.assign(HWLM_MASKLEN, 0);
+
+ size_t num = 0;
+ vector<u8> v_msk, v_cmp;
+
+ for (RoseVertex v : info.vertices) {
+ if (!addSurroundingMask(build, id, v, v_msk, v_cmp)) {
+ DEBUG_PRINTF("no mask\n");
+ return false;
+ }
+
+ if (!num++) {
+ // First (or only) vertex, this becomes the mask/cmp pair.
+ msk = v_msk;
+ cmp = v_cmp;
+ } else {
+ // Multiple vertices with potentially different masks. We combine
+ // them into an 'advisory' mask.
+ if (!hamsterMaskCombine(msk, cmp, v_msk, v_cmp)) {
+ DEBUG_PRINTF("mask went to zero\n");
+ return false;
+ }
+ }
+ }
+
+ normaliseLiteralMask(id.s, msk, cmp);
+
+ if (msk.empty()) {
+ DEBUG_PRINTF("no mask\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("msk=%s, cmp=%s\n", dumpMask(msk).c_str(),
+ dumpMask(cmp).c_str());
+ return true;
+}
+
+void findMoreLiteralMasks(RoseBuildImpl &build) {
+ if (!build.cc.grey.roseHamsterMasks) {
+ return;
+ }
+
+ vector<u32> candidates;
+ for (u32 id = 0; id < build.literals.size(); id++) {
+ const auto &lit = build.literals.at(id);
+
+ if (lit.delay || build.isDelayed(id)) {
+ continue;
+ }
+
+ // Literal masks are only allowed for literals that will end up in an
+ // HWLM table.
+ switch (lit.table) {
+ case ROSE_FLOATING:
+ case ROSE_EOD_ANCHORED:
+ case ROSE_ANCHORED_SMALL_BLOCK:
+ break;
+ default:
+ continue;
+ }
+
+ candidates.push_back(id);
+ }
+
+ for (const u32 &id : candidates) {
+ const auto &lit = build.literals.at(id);
+ auto &lit_info = build.literal_info.at(id);
+
+ vector<u8> msk, cmp;
+ if (!addSurroundingMask(build, lit, lit_info, msk, cmp)) {
+ continue;
+ }
+ DEBUG_PRINTF("found surrounding mask for lit_id=%u (%s)\n", id,
+ dumpString(lit.s).c_str());
+ u32 new_id = build.getLiteralId(lit.s, msk, cmp, lit.delay, lit.table);
+ if (new_id == id) {
+ continue;
+ }
+ DEBUG_PRINTF("replacing with new lit_id=%u\n", new_id);
+
+ // Note that our new literal may already exist and have vertices, etc.
+ // We assume that this transform is happening prior to group assignment.
+ assert(lit_info.group_mask == 0);
+ auto &new_info = build.literal_info.at(new_id);
+
+ // Move the vertices across.
+ new_info.vertices.insert(begin(lit_info.vertices),
+ end(lit_info.vertices));
+ for (auto v : lit_info.vertices) {
+ build.g[v].literals.erase(id);
+ build.g[v].literals.insert(new_id);
+ }
+ lit_info.vertices.clear();
+
+ // Preserve other properties.
+ new_info.requires_benefits = lit_info.requires_benefits;
+ }
+}
+
+// The mask already associated with the literal and any mask due to
+// mixed-case is mandatory.
+static
+void addLiteralMask(const rose_literal_id &id, vector<u8> &msk,
+ vector<u8> &cmp) {
+ const size_t suffix_len = min(id.s.length(), size_t{HWLM_MASKLEN});
+ bool mixed_suffix = mixed_sensitivity_in(id.s.end() - suffix_len,
+ id.s.end());
+
+ if (id.msk.empty() && !mixed_suffix) {
+ return;
+ }
+
+ while (msk.size() < HWLM_MASKLEN) {
+ msk.insert(msk.begin(), 0);
+ cmp.insert(cmp.begin(), 0);
+ }
+
+ if (!id.msk.empty()) {
+ assert(id.msk.size() <= HWLM_MASKLEN);
+ assert(id.msk.size() == id.cmp.size());
+ for (size_t i = 0; i < id.msk.size(); i++) {
+ size_t mand_offset = msk.size() - i - 1;
+ size_t lit_offset = id.msk.size() - i - 1;
+ msk[mand_offset] = id.msk[lit_offset];
+ cmp[mand_offset] = id.cmp[lit_offset];
+ }
+ }
+
+ if (mixed_suffix) {
+ auto it = id.s.rbegin();
+ for (size_t i = 0; i < suffix_len; ++i, ++it) {
+ const auto &c = *it;
+ if (!c.nocase) {
+ size_t offset = HWLM_MASKLEN - i - 1;
+ DEBUG_PRINTF("offset %zu must match 0x%02x exactly\n", offset,
+ c.c);
+ make_and_cmp_mask(c, &msk[offset], &cmp[offset]);
+ }
+ }
+ }
+
+ normaliseLiteralMask(id.s, msk, cmp);
+}
+
+static
+bool isDirectHighlander(const RoseBuildImpl &build, const u32 id,
+ const rose_literal_info &info) {
+ if (!build.isDirectReport(id)) {
+ return false;
+ }
+
+ auto is_simple_exhaustible = [&build](ReportID rid) {
+ const Report &report = build.rm.getReport(rid);
+ return isSimpleExhaustible(report);
+ };
+
+ assert(!info.vertices.empty());
+ for (const auto &v : info.vertices) {
+ const auto &reports = build.g[v].reports;
+ assert(!reports.empty());
+ if (!all_of(begin(reports), end(reports),
+ is_simple_exhaustible)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Called by isNoRunsLiteral below.
+static
+bool isNoRunsVertex(const RoseBuildImpl &build, RoseVertex u) {
+ const RoseGraph &g = build.g;
+ if (!g[u].isBoring()) {
+ DEBUG_PRINTF("u=%zu is not boring\n", g[u].index);
+ return false;
+ }
+
+ if (!g[u].reports.empty()) {
+ DEBUG_PRINTF("u=%zu has accept\n", g[u].index);
+ return false;
+ }
+
+ /* TODO: handle non-root roles as well. It can't be that difficult... */
+
+ if (in_degree(u, g) != 1) {
+ DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index);
+ return false;
+ }
+
+ RoseEdge e = edge(build.root, u, g);
+
+ if (!e) {
+ DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index);
+ return false;
+ }
+
+ if (g[e].minBound != 0 || g[e].maxBound != ROSE_BOUND_INF) {
+ DEBUG_PRINTF("u=%zu has bounds from root\n", g[u].index);
+ return false;
+ }
+
+ for (const auto &oe : out_edges_range(u, g)) {
+ RoseVertex v = target(oe, g);
+ if (g[oe].maxBound != ROSE_BOUND_INF) {
+ DEBUG_PRINTF("edge (%zu,%zu) has max bound\n", g[u].index,
+ g[v].index);
+ return false;
+ }
+ if (g[v].left) {
+ DEBUG_PRINTF("v=%zu has rose prefix\n", g[v].index);
+ return false;
+ }
+ }
+ return true;
+}
+
+static
+bool isNoRunsLiteral(const RoseBuildImpl &build, const u32 id,
+ const rose_literal_info &info, const size_t max_len) {
+ DEBUG_PRINTF("lit id %u\n", id);
+
+ if (info.requires_benefits) {
+ DEBUG_PRINTF("requires benefits\n"); // which would need confirm
+ return false;
+ }
+
+ size_t len = build.literals.at(id).s.length();
+ if (len > max_len) {
+ DEBUG_PRINTF("long literal, requires confirm\n");
+ return false;
+ }
+
+ if (len > ROSE_SHORT_LITERAL_LEN_MAX) {
+ DEBUG_PRINTF("medium-length literal, requires confirm\n");
+ return false;
+ }
+
+ if (isDirectHighlander(build, id, info)) {
+ DEBUG_PRINTF("highlander direct report\n");
+ return true;
+ }
+
+ // Undelayed vertices.
+ for (RoseVertex v : info.vertices) {
+ if (!isNoRunsVertex(build, v)) {
+ return false;
+ }
+ }
+
+ // Delayed vertices.
+ for (u32 d : info.delayed_ids) {
+ assert(d < build.literal_info.size());
+ const rose_literal_info &delayed_info = build.literal_info.at(d);
+ assert(delayed_info.undelayed_id == id);
+ for (RoseVertex v : delayed_info.vertices) {
+ if (!isNoRunsVertex(build, v)) {
+ return false;
+ }
+ }
+ }
+
+ DEBUG_PRINTF("is no-runs literal\n");
+ return true;
+}
+
+static
+bool isNoRunsFragment(const RoseBuildImpl &build, const LitFragment &f,
+ const size_t max_len) {
+ // For the fragment to be marked "no runs", every literal it fires must
+ // need no further confirmation work.
+ return all_of_in(f.lit_ids, [&](u32 lit_id) {
+ const auto &info = build.literal_info.at(lit_id);
+ return isNoRunsLiteral(build, lit_id, info, max_len);
+ });
+}
+
+static
+const raw_puff &getChainedPuff(const RoseBuildImpl &build,
+ const Report &report) {
+ DEBUG_PRINTF("chained report, event %u\n", report.onmatch);
+
+ // MPV has already been moved to the outfixes vector.
+ assert(!build.mpv_outfix);
+
+ auto mpv_outfix_it = find_if(
+ begin(build.outfixes), end(build.outfixes),
+ [](const OutfixInfo &outfix) { return outfix.is_nonempty_mpv(); });
+ assert(mpv_outfix_it != end(build.outfixes));
+ const auto *mpv = mpv_outfix_it->mpv();
+
+ u32 puff_index = report.onmatch - MQE_TOP_FIRST;
+ assert(puff_index < mpv->triggered_puffettes.size());
+ return mpv->triggered_puffettes.at(puff_index);
+}
+
+/**
+ * \brief Returns a conservative estimate of the minimum offset at which the
+ * given literal can lead to a report.
+ *
+ * TODO: This could be made more precise by calculating a "distance to accept"
+ * for every vertex in the graph; right now we're only accurate for leaf nodes.
+ */
+static
+u64a literalMinReportOffset(const RoseBuildImpl &build,
+ const rose_literal_id &lit,
+ const rose_literal_info &info) {
+ const auto &g = build.g;
+
+ const u32 lit_len = verify_u32(lit.elength());
+
+ u64a lit_min_offset = UINT64_MAX;
+
+ for (const auto &v : info.vertices) {
+ DEBUG_PRINTF("vertex %zu min_offset=%u\n", g[v].index, g[v].min_offset);
+
+ u64a vert_offset = g[v].min_offset;
+
+ if (vert_offset >= lit_min_offset) {
+ continue;
+ }
+
+ u64a min_offset = UINT64_MAX;
+
+ for (const auto &id : g[v].reports) {
+ const Report &report = build.rm.getReport(id);
+ DEBUG_PRINTF("report id %u, min offset=%llu\n", id,
+ report.minOffset);
+ if (report.type == INTERNAL_ROSE_CHAIN) {
+ // This vertex triggers an MPV, which will fire reports after
+ // repeating for a while.
+ assert(report.minOffset == 0); // Should not have bounds.
+ const auto &puff = getChainedPuff(build, report);
+ DEBUG_PRINTF("chained puff repeats=%u\n", puff.repeats);
+ const Report &puff_report = build.rm.getReport(puff.report);
+ DEBUG_PRINTF("puff report %u, min offset=%llu\n", puff.report,
+ puff_report.minOffset);
+ min_offset = min(min_offset, max(vert_offset + puff.repeats,
+ puff_report.minOffset));
+ } else {
+ DEBUG_PRINTF("report min offset=%llu\n", report.minOffset);
+ min_offset = min(min_offset, max(vert_offset,
+ report.minOffset));
+ }
+ }
+
+ if (g[v].suffix) {
+ depth suffix_width = findMinWidth(g[v].suffix, g[v].suffix.top);
+ assert(suffix_width.is_reachable());
+ DEBUG_PRINTF("suffix with width %s\n", suffix_width.str().c_str());
+ min_offset = min(min_offset, vert_offset + suffix_width);
+ }
+
+ if (!isLeafNode(v, g) || min_offset == UINT64_MAX) {
+ min_offset = vert_offset;
+ }
+
+ lit_min_offset = min(lit_min_offset, min_offset);
+ }
+
+ // If this literal in the undelayed literal corresponding to some delayed
+ // literals, we must take their minimum offsets into account.
+ for (const u32 &delayed_id : info.delayed_ids) {
+ const auto &delayed_lit = build.literals.at(delayed_id);
+ const auto &delayed_info = build.literal_info.at(delayed_id);
+ u64a delayed_min_offset = literalMinReportOffset(build, delayed_lit,
+ delayed_info);
+ DEBUG_PRINTF("delayed_id=%u, min_offset = %llu\n", delayed_id,
+ delayed_min_offset);
+ lit_min_offset = min(lit_min_offset, delayed_min_offset);
+ }
+
+ // If we share a vertex with a shorter literal, our min offset might dip
+ // below the length of this one.
+ lit_min_offset = max(lit_min_offset, u64a{lit_len});
+
+ return lit_min_offset;
+}
+
+template<class Container>
+void trim_to_suffix(Container &c, size_t len) {
+ if (c.size() <= len) {
+ return;
+ }
+
+ size_t suffix_len = c.size() - len;
+ c.erase(c.begin(), c.begin() + suffix_len);
+}
+
+namespace {
+
+/** \brief Prototype for literal matcher construction. */
+struct MatcherProto {
+ /** \brief Literal fragments used to construct the literal matcher. */
+ vector<hwlmLiteral> lits;
+
+ /** \brief Longer literals used for acceleration analysis. */
+ vector<AccelString> accel_lits;
+
+ /** \brief The history required by the literal matcher. */
+ size_t history_required = 0;
+
+ /** \brief Insert the contents of another MatcherProto. */
+ void insert(const MatcherProto &a);
+};
+}
+
+static
+void addFragmentLiteral(const RoseBuildImpl &build, MatcherProto &mp,
+ const LitFragment &f, u32 id, size_t max_len) {
+ const rose_literal_id &lit = build.literals.at(id);
+
+ DEBUG_PRINTF("lit='%s' (len %zu)\n", dumpString(lit.s).c_str(),
+ lit.s.length());
+
+ vector<u8> msk = lit.msk; // copy
+ vector<u8> cmp = lit.cmp; // copy
+
+ bool noruns = isNoRunsFragment(build, f, max_len);
+ DEBUG_PRINTF("fragment is %s\n", noruns ? "noruns" : "not noruns");
+
+ auto lit_final = lit.s; // copy
+
+ if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
+ DEBUG_PRINTF("truncating to tail of length %zu\n",
+ size_t{ROSE_SHORT_LITERAL_LEN_MAX});
+ lit_final.erase(0, lit_final.length() - ROSE_SHORT_LITERAL_LEN_MAX);
+ // We shouldn't have set a threshold below 8 chars.
+ assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
+ assert(!noruns);
+ }
+
+ addLiteralMask(lit, msk, cmp);
+
+ const auto &s_final = lit_final.get_string();
+ bool nocase = lit_final.any_nocase();
+
+ DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, cmp=%s\n",
+ f.fragment_id, escapeString(s_final).c_str(), (int)nocase,
+ noruns, dumpMask(msk).c_str(), dumpMask(cmp).c_str());
+
+ if (!maskIsConsistent(s_final, nocase, msk, cmp)) {
+ DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
+ return;
+ }
+
+ const auto &groups = f.groups;
+
+ mp.lits.emplace_back(move(s_final), nocase, noruns, f.fragment_id,
+ groups, msk, cmp);
+}
+
+static
+void addAccelLiteral(MatcherProto &mp, const rose_literal_id &lit,
+ const rose_literal_info &info, size_t max_len) {
+ const auto &s = lit.s; // copy
+
+ DEBUG_PRINTF("lit='%s' (len %zu)\n", dumpString(s).c_str(), s.length());
+
+ vector<u8> msk = lit.msk; // copy
+ vector<u8> cmp = lit.cmp; // copy
+ addLiteralMask(lit, msk, cmp);
+
+ if (!maskIsConsistent(s.get_string(), s.any_nocase(), msk, cmp)) {
+ DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
+ return;
+ }
+
+ // Literals used for acceleration must be limited to max_len, as that's all
+ // we can see in history.
+ string s_final = lit.s.get_string();
+ trim_to_suffix(s_final, max_len);
+ trim_to_suffix(msk, max_len);
+ trim_to_suffix(cmp, max_len);
+
+ mp.accel_lits.emplace_back(s_final, lit.s.any_nocase(), msk, cmp,
+ info.group_mask);
+}
+
+/**
+ * \brief Build up a vector of literals (and associated other data) for the
+ * given table.
+ *
+ * If max_offset is specified (and not ROSE_BOUND_INF), then literals that can
+ * only lead to a pattern match after max_offset may be excluded.
+ */
+static
+MatcherProto makeMatcherProto(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments,
+ rose_literal_table table, bool delay_rebuild,
+ size_t max_len, u32 max_offset = ROSE_BOUND_INF) {
+ MatcherProto mp;
+
+ if (delay_rebuild) {
+ assert(table == ROSE_FLOATING);
+ assert(build.cc.streaming);
+ }
+
+ vector<u32> used_lit_ids;
+
+ for (const auto &f : fragments) {
+ assert(!f.lit_ids.empty());
+
+ // All literals that share a fragment are in the same table.
+ if (build.literals.at(f.lit_ids.front()).table != table) {
+ continue; // next fragment.
+ }
+
+ DEBUG_PRINTF("fragment %u, %zu lit_ids\n", f.fragment_id,
+ f.lit_ids.size());
+
+ used_lit_ids.clear();
+ for (u32 id : f.lit_ids) {
+ const rose_literal_id &lit = build.literals.at(id);
+ assert(id < build.literal_info.size());
+ const auto &info = build.literal_info.at(id);
+ if (lit.delay) {
+ continue; /* delay id's are virtual-ish */
+ }
+
+ // When building the delay rebuild table, we only want to include
+ // literals that have delayed variants.
+ if (delay_rebuild && info.delayed_ids.empty()) {
+ DEBUG_PRINTF("not needed for delay rebuild\n");
+ continue;
+ }
+
+ if (max_offset != ROSE_BOUND_INF) {
+ u64a min_report = literalMinReportOffset(build, lit, info);
+ if (min_report > max_offset) {
+ DEBUG_PRINTF("min report offset=%llu exceeds "
+ "max_offset=%u\n", min_report, max_offset);
+ continue;
+ }
+ }
+
+ used_lit_ids.push_back(id);
+ }
+
+ if (used_lit_ids.empty()) {
+ continue; // next fragment.
+ }
+
+ // Build our fragment (for the HWLM matcher) from the first literal.
+ addFragmentLiteral(build, mp, f, used_lit_ids.front(), max_len);
+
+ for (u32 id : used_lit_ids) {
+ const rose_literal_id &lit = build.literals.at(id);
+ assert(id < build.literal_info.size());
+ const auto &info = build.literal_info.at(id);
+
+ // All literals contribute accel information.
+ addAccelLiteral(mp, lit, info, max_len);
+
+ // All literals contribute to history requirement in streaming mode.
+ if (build.cc.streaming) {
+ size_t lit_hist_len =
+ max(lit.msk.size(), min(lit.s.length(), max_len));
+ lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
+ DEBUG_PRINTF("lit requires %zu bytes of history\n",
+ lit_hist_len);
+ assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
+ mp.history_required = max(mp.history_required, lit_hist_len);
+ }
+ }
+ }
+
+ sort_and_unique(mp.lits);
+ sort_and_unique(mp.accel_lits);
+
+ return mp;
+}
+
+void MatcherProto::insert(const MatcherProto &a) {
+ ::ue2::insert(&lits, lits.end(), a.lits);
+ ::ue2::insert(&accel_lits, accel_lits.end(), a.accel_lits);
+ sort_and_unique(lits);
+ sort_and_unique(accel_lits);
+ history_required = max(history_required, a.history_required);
+}
+
+static
+void buildAccel(const RoseBuildImpl &build,
+ const vector<AccelString> &accel_lits, HWLM &hwlm) {
+ if (!build.cc.grey.hamsterAccelForward) {
+ return;
+ }
+
+ if (hwlm.type == HWLM_ENGINE_NOOD) {
+ return;
+ }
+
+ buildForwardAccel(&hwlm, accel_lits, build.getInitialGroups());
+}
+
+bytecode_ptr<HWLM>
+buildHWLMMatcher(const RoseBuildImpl &build, LitProto *litProto) {
+ if (!litProto) {
+ return nullptr;
+ }
+ auto hwlm = hwlmBuild(*litProto->hwlmProto, build.cc,
+ build.getInitialGroups());
+ if (!hwlm) {
+ throw CompileError("Unable to generate bytecode.");
+ }
+
+ buildAccel(build, litProto->accel_lits, *hwlm);
+
+ DEBUG_PRINTF("built eod-anchored literal table size %zu bytes\n",
+ hwlm.size());
+ return hwlm;
+}
+
+unique_ptr<LitProto>
+buildFloatingMatcherProto(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments,
+ size_t longLitLengthThreshold,
+ rose_group *fgroups,
+ size_t *historyRequired) {
+ DEBUG_PRINTF("Floating literal matcher\n");
+ *fgroups = 0;
+
+ auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
+ longLitLengthThreshold);
+ if (mp.lits.empty()) {
+ DEBUG_PRINTF("empty floating matcher\n");
+ return nullptr;
+ }
+ dumpMatcherLiterals(mp.lits, "floating", build.cc.grey);
+
+ for (const hwlmLiteral &lit : mp.lits) {
+ *fgroups |= lit.groups;
+ }
+
+ if (build.cc.streaming) {
+ DEBUG_PRINTF("history_required=%zu\n", mp.history_required);
+ assert(mp.history_required <= build.cc.grey.maxHistoryAvailable);
+ *historyRequired = max(*historyRequired, mp.history_required);
+ }
+
+ auto proto = hwlmBuildProto(mp.lits, false, build.cc);
+
+ if (!proto) {
+ throw CompileError("Unable to generate literal matcher proto.");
+ }
+
+ return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
+}
+
+unique_ptr<LitProto>
+buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments,
+ size_t longLitLengthThreshold) {
+ DEBUG_PRINTF("Delay literal matcher\n");
+ if (!build.cc.streaming) {
+ DEBUG_PRINTF("not streaming\n");
+ return nullptr;
+ }
+
+ auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, true,
+ longLitLengthThreshold);
+ if (mp.lits.empty()) {
+ DEBUG_PRINTF("empty delay rebuild matcher\n");
+ return nullptr;
+ }
+ dumpMatcherLiterals(mp.lits, "delay_rebuild", build.cc.grey);
+
+
+ auto proto = hwlmBuildProto(mp.lits, false, build.cc);
+
+ if (!proto) {
+ throw CompileError("Unable to generate literal matcher proto.");
+ }
+
+ return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
+}
+
+unique_ptr<LitProto>
+buildSmallBlockMatcherProto(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments) {
+ DEBUG_PRINTF("Small block literal matcher\n");
+ if (build.cc.streaming) {
+ DEBUG_PRINTF("streaming mode\n");
+ return nullptr;
+ }
+
+ u32 float_min = findMinWidth(build, ROSE_FLOATING);
+ if (float_min > ROSE_SMALL_BLOCK_LEN) {
+ DEBUG_PRINTF("floating table has large min width %u, fail\n",
+ float_min);
+ return nullptr;
+ }
+
+ auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
+ ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
+ if (mp.lits.empty()) {
+ DEBUG_PRINTF("no floating table\n");
+ return nullptr;
+ } else if (mp.lits.size() == 1) {
+ DEBUG_PRINTF("single floating literal, noodle will be fast enough\n");
+ return nullptr;
+ }
+
+ auto mp_anchored = makeMatcherProto(build, fragments,
+ ROSE_ANCHORED_SMALL_BLOCK, false,
+ ROSE_SMALL_BLOCK_LEN,
+ ROSE_SMALL_BLOCK_LEN);
+ if (mp_anchored.lits.empty()) {
+ DEBUG_PRINTF("no small-block anchored literals\n");
+ return nullptr;
+ }
+
+ mp.insert(mp_anchored);
+ dumpMatcherLiterals(mp.lits, "smallblock", build.cc.grey);
+
+ // None of our literals should be longer than the small block limit.
+ assert(all_of(begin(mp.lits), end(mp.lits), [](const hwlmLiteral &lit) {
+ return lit.s.length() <= ROSE_SMALL_BLOCK_LEN;
+ }));
+
+ if (mp.lits.empty()) {
+ DEBUG_PRINTF("no literals shorter than small block len\n");
+ return nullptr;
+ }
+
+ auto proto = hwlmBuildProto(mp.lits, false, build.cc);
+
+ if (!proto) {
+ throw CompileError("Unable to generate literal matcher proto.");
+ }
+
+ return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
+}
+
+unique_ptr<LitProto>
+buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
+ const vector<LitFragment> &fragments) {
+ DEBUG_PRINTF("Eod anchored literal matcher\n");
+ auto mp = makeMatcherProto(build, fragments, ROSE_EOD_ANCHORED, false,
+ build.ematcher_region_size);
+
+ if (mp.lits.empty()) {
+ DEBUG_PRINTF("no eod anchored literals\n");
+ assert(!build.ematcher_region_size);
+ return nullptr;
+ }
+ dumpMatcherLiterals(mp.lits, "eod", build.cc.grey);
+
+ assert(build.ematcher_region_size);
+
+ auto proto = hwlmBuildProto(mp.lits, false, build.cc);
+
+ if (!proto) {
+ throw CompileError("Unable to generate literal matcher proto.");
+ }
+
+ return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_matchers.h b/contrib/libs/hyperscan/src/rose/rose_build_matchers.h
index 8fb70d68ac7..ef8999ed01e 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_matchers.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_matchers.h
@@ -1,129 +1,129 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Rose build: code for constructing literal tables.
- */
-
-#ifndef ROSE_BUILD_MATCHERS_H
-#define ROSE_BUILD_MATCHERS_H
-
-#include "rose_build_impl.h"
-#include "rose_build_lit_accel.h"
-#include "hwlm/hwlm_build.h"
-#include "util/bytecode_ptr.h"
-#include "util/ue2string.h"
-
-#include <vector>
-
-struct Grey;
-struct HWLM;
-
-namespace ue2 {
-
-static constexpr u32 INVALID_FRAG_ID = ~0U;
-
-struct LitFragment {
- LitFragment(u32 fragment_id_in, ue2_literal s_in,
- rose_group groups_in, u32 lit_id)
- : fragment_id(fragment_id_in), s(s_in), groups(groups_in),
- lit_ids({lit_id}) {}
- LitFragment(u32 fragment_id_in, ue2_literal s_in,
- rose_group groups_in, std::vector<u32> lit_ids_in)
- : fragment_id(fragment_id_in), s(s_in), groups(groups_in),
- lit_ids(std::move(lit_ids_in)) {}
- u32 fragment_id;
-
- /**
- * \brief literal fragment.
- */
- ue2_literal s;
-
- /**
- * \brief FDR confirm squash mask for included literals.
- */
- u8 squash = 0;
-
- /**
- * \brief FDR confirm squash mask for included literals (Delayed
- * literals only).
- */
- u8 delay_squash = 0;
-
- /**
- * \brief Fragment id of included literal.
- */
- u32 included_frag_id = INVALID_FRAG_ID;
-
- /**
- * \brief Fragment Id of included literal (Delayed literals only).
- */
- u32 included_delay_frag_id = INVALID_FRAG_ID;
- rose_group groups;
- std::vector<u32> lit_ids;
- u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
- u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
-};
-
-struct LitProto {
- LitProto(std::unique_ptr<HWLMProto> hwlmProto_in,
- std::vector<AccelString> &accel_lits_in)
- : hwlmProto(std::move(hwlmProto_in)), accel_lits(accel_lits_in) {}
-
- std::unique_ptr<HWLMProto> hwlmProto;
- std::vector<AccelString> accel_lits;
-};
-
-bytecode_ptr<HWLM>
-buildHWLMMatcher(const RoseBuildImpl &build, LitProto *proto);
-
-std::unique_ptr<LitProto>
-buildFloatingMatcherProto(const RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments,
- size_t longLitLengthThreshold,
- rose_group *fgroups,
- size_t *historyRequired);
-
-std::unique_ptr<LitProto>
-buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments,
- size_t longLitLengthThreshold);
-std::unique_ptr<LitProto>
-buildSmallBlockMatcherProto(const RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments);
-
-std::unique_ptr<LitProto>
-buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
- const std::vector<LitFragment> &fragments);
-
-void findMoreLiteralMasks(RoseBuildImpl &build);
-
-} // namespace ue2
-
-#endif // ROSE_BUILD_MATCHERS_H
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Rose build: code for constructing literal tables.
+ */
+
+#ifndef ROSE_BUILD_MATCHERS_H
+#define ROSE_BUILD_MATCHERS_H
+
+#include "rose_build_impl.h"
+#include "rose_build_lit_accel.h"
+#include "hwlm/hwlm_build.h"
+#include "util/bytecode_ptr.h"
+#include "util/ue2string.h"
+
+#include <vector>
+
+struct Grey;
+struct HWLM;
+
+namespace ue2 {
+
+static constexpr u32 INVALID_FRAG_ID = ~0U;
+
+struct LitFragment {
+ LitFragment(u32 fragment_id_in, ue2_literal s_in,
+ rose_group groups_in, u32 lit_id)
+ : fragment_id(fragment_id_in), s(s_in), groups(groups_in),
+ lit_ids({lit_id}) {}
+ LitFragment(u32 fragment_id_in, ue2_literal s_in,
+ rose_group groups_in, std::vector<u32> lit_ids_in)
+ : fragment_id(fragment_id_in), s(s_in), groups(groups_in),
+ lit_ids(std::move(lit_ids_in)) {}
+ u32 fragment_id;
+
+ /**
+ * \brief literal fragment.
+ */
+ ue2_literal s;
+
+ /**
+ * \brief FDR confirm squash mask for included literals.
+ */
+ u8 squash = 0;
+
+ /**
+ * \brief FDR confirm squash mask for included literals (Delayed
+ * literals only).
+ */
+ u8 delay_squash = 0;
+
+ /**
+ * \brief Fragment id of included literal.
+ */
+ u32 included_frag_id = INVALID_FRAG_ID;
+
+ /**
+ * \brief Fragment Id of included literal (Delayed literals only).
+ */
+ u32 included_delay_frag_id = INVALID_FRAG_ID;
+ rose_group groups;
+ std::vector<u32> lit_ids;
+ u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
+ u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
+};
+
+struct LitProto {
+ LitProto(std::unique_ptr<HWLMProto> hwlmProto_in,
+ std::vector<AccelString> &accel_lits_in)
+ : hwlmProto(std::move(hwlmProto_in)), accel_lits(accel_lits_in) {}
+
+ std::unique_ptr<HWLMProto> hwlmProto;
+ std::vector<AccelString> accel_lits;
+};
+
+bytecode_ptr<HWLM>
+buildHWLMMatcher(const RoseBuildImpl &build, LitProto *proto);
+
+std::unique_ptr<LitProto>
+buildFloatingMatcherProto(const RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments,
+ size_t longLitLengthThreshold,
+ rose_group *fgroups,
+ size_t *historyRequired);
+
+std::unique_ptr<LitProto>
+buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments,
+ size_t longLitLengthThreshold);
+std::unique_ptr<LitProto>
+buildSmallBlockMatcherProto(const RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments);
+
+std::unique_ptr<LitProto>
+buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
+ const std::vector<LitFragment> &fragments);
+
+void findMoreLiteralMasks(RoseBuildImpl &build);
+
+} // namespace ue2
+
+#endif // ROSE_BUILD_MATCHERS_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_merge.cpp b/contrib/libs/hyperscan/src/rose/rose_build_merge.cpp
index 0045782cfb2..5066dbd5781 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_merge.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_merge.cpp
@@ -63,12 +63,12 @@
#include "util/container.h"
#include "util/dump_charclass.h"
#include "util/graph_range.h"
-#include "util/hash.h"
-#include "util/insertion_ordered.h"
+#include "util/hash.h"
+#include "util/insertion_ordered.h"
#include "util/order_check.h"
#include "util/report_manager.h"
#include "util/ue2string.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <algorithm>
#include <functional>
@@ -84,7 +84,7 @@
using namespace std;
using boost::adaptors::map_values;
-using boost::adaptors::map_keys;
+using boost::adaptors::map_keys;
namespace ue2 {
@@ -94,7 +94,7 @@ static const size_t SMALL_MERGE_MAX_VERTICES_BLOCK = 64;
static const size_t SMALL_ROSE_THRESHOLD_STREAM = 32;
static const size_t SMALL_ROSE_THRESHOLD_BLOCK = 10;
static const size_t MERGE_GROUP_SIZE_MAX = 200;
-static const size_t MERGE_CASTLE_GROUP_SIZE_MAX = 1000;
+static const size_t MERGE_CASTLE_GROUP_SIZE_MAX = 1000;
/** \brief Max number of DFAs (McClellan, Haig) to pairwise merge together. */
static const size_t DFA_CHUNK_SIZE_MAX = 200;
@@ -102,10 +102,10 @@ static const size_t DFA_CHUNK_SIZE_MAX = 200;
/** \brief Max DFA states in a merged DFA. */
static const size_t DFA_MERGE_MAX_STATES = 8000;
-/** \brief In block mode, merge two prefixes even if they don't have identical
- * literal sets if they have fewer than this many states and the merged graph
- * is also small. */
-static constexpr size_t MAX_BLOCK_PREFIX_MERGE_VERTICES = 32;
+/** \brief In block mode, merge two prefixes even if they don't have identical
+ * literal sets if they have fewer than this many states and the merged graph
+ * is also small. */
+static constexpr size_t MAX_BLOCK_PREFIX_MERGE_VERTICES = 32;
static
size_t small_merge_max_vertices(const CompileContext &cc) {
@@ -124,17 +124,17 @@ size_t small_rose_threshold(const CompileContext &cc) {
* reports should not contribute to the hash.
*/
static
-size_t hashLeftfix(const left_id &left) {
+size_t hashLeftfix(const left_id &left) {
size_t val = 0;
- if (left.castle()) {
- hash_combine(val, left.castle()->reach());
- for (const auto &pr : left.castle()->repeats) {
+ if (left.castle()) {
+ hash_combine(val, left.castle()->reach());
+ for (const auto &pr : left.castle()->repeats) {
hash_combine(val, pr.first); // top
hash_combine(val, pr.second.bounds);
}
- } else if (left.graph()) {
- hash_combine(val, hash_holder(*left.graph()));
+ } else if (left.graph()) {
+ hash_combine(val, hash_holder(*left.graph()));
}
return val;
@@ -150,7 +150,7 @@ struct RoseGroup {
const RoseGraph &g = build.g;
assert(in_degree(v, g) == 1);
RoseVertex u = *inv_adjacent_vertices(v, g).first;
- parent = g[u].index;
+ parent = g[u].index;
}
bool operator<(const RoseGroup &b) const {
@@ -180,24 +180,24 @@ private:
};
/**
- * Intended to find graphs that are identical except for their report
- * IDs. Relies on vertex and edge indices to pick up graphs that have been
- * messily put together in different orderings. Only implemented for castles and
- * holders.
+ * Intended to find graphs that are identical except for their report
+ * IDs. Relies on vertex and edge indices to pick up graphs that have been
+ * messily put together in different orderings. Only implemented for castles and
+ * holders.
*/
-static
-bool is_equal(const left_id &u_left, ReportID u_report,
- const left_id &v_left, ReportID v_report) {
- if (u_left.castle() && v_left.castle()) {
- return is_equal(*u_left.castle(), u_report, *v_left.castle(), v_report);
- }
+static
+bool is_equal(const left_id &u_left, ReportID u_report,
+ const left_id &v_left, ReportID v_report) {
+ if (u_left.castle() && v_left.castle()) {
+ return is_equal(*u_left.castle(), u_report, *v_left.castle(), v_report);
+ }
- if (!u_left.graph() || !v_left.graph()) {
- return false;
+ if (!u_left.graph() || !v_left.graph()) {
+ return false;
}
- return is_equal(*u_left.graph(), u_report, *v_left.graph(), v_report);
-}
+ return is_equal(*u_left.graph(), u_report, *v_left.graph(), v_report);
+}
} // namespace
@@ -212,8 +212,8 @@ bool is_equal(const left_id &u_left, ReportID u_report,
*
* Note: only roles with a single predecessor vertex are considered for this
* transform - it should probably be generalised to work for roles which share
- * the same set of predecessor roles as for \ref dedupeLeftfixesVariableLag or
- * it should be retired entirely.
+ * the same set of predecessor roles as for \ref dedupeLeftfixesVariableLag or
+ * it should be retired entirely.
*/
bool dedupeLeftfixes(RoseBuildImpl &tbi) {
DEBUG_PRINTF("deduping leftfixes\n");
@@ -248,7 +248,7 @@ bool dedupeLeftfixes(RoseBuildImpl &tbi) {
for (deque<RoseVertex> &verts : roses | map_values) {
DEBUG_PRINTF("group has %zu vertices\n", verts.size());
- unordered_set<left_id> seen;
+ unordered_set<left_id> seen;
for (auto jt = verts.begin(), jte = verts.end(); jt != jte; ++jt) {
RoseVertex v = *jt;
@@ -260,16 +260,16 @@ bool dedupeLeftfixes(RoseBuildImpl &tbi) {
}
// Scan the rest of the list for dupes.
- for (auto kt = std::next(jt); kt != jte; ++kt) {
- if (g[v].left == g[*kt].left
- || !is_equal(g[v].left, g[v].left.leftfix_report,
- g[*kt].left, g[*kt].left.leftfix_report)) {
+ for (auto kt = std::next(jt); kt != jte; ++kt) {
+ if (g[v].left == g[*kt].left
+ || !is_equal(g[v].left, g[v].left.leftfix_report,
+ g[*kt].left, g[*kt].left.leftfix_report)) {
continue;
}
// Dupe found.
DEBUG_PRINTF("rose at vertex %zu is a dupe of %zu\n",
- g[*kt].index, g[v].index);
+ g[*kt].index, g[v].index);
assert(g[v].left.lag == g[*kt].left.lag);
g[*kt].left = g[v].left;
work_done = true;
@@ -320,7 +320,7 @@ bool is_equal(const suffix_id &s1, const suffix_id &s2) {
void dedupeSuffixes(RoseBuildImpl &tbi) {
DEBUG_PRINTF("deduping suffixes\n");
- unordered_map<suffix_id, set<RoseVertex>> suffix_map;
+ unordered_map<suffix_id, set<RoseVertex>> suffix_map;
map<pair<size_t, set<ReportID>>, vector<suffix_id>> part;
// Collect suffixes into groups.
@@ -387,7 +387,7 @@ template<class EngineRef>
class Bouquet {
private:
list<EngineRef> ordering; // Unique list in insert order.
- using BouquetMap = ue2_unordered_map<EngineRef, deque<RoseVertex>>;
+ using BouquetMap = ue2_unordered_map<EngineRef, deque<RoseVertex>>;
BouquetMap bouquet;
public:
void insert(const EngineRef &h, RoseVertex v) {
@@ -485,246 +485,246 @@ static void chunkBouquets(const Bouquet<EngineRef> &in,
}
}
-static
-bool stringsCanFinishAtSameSpot(const ue2_literal &u,
- ue2_literal::const_iterator v_b,
- ue2_literal::const_iterator v_e) {
- ue2_literal::const_iterator u_e = u.end();
- ue2_literal::const_iterator u_b = u.begin();
-
- while (u_e != u_b && v_e != v_b) {
- --u_e;
- --v_e;
-
- if (!overlaps(*u_e, *v_e)) {
- return false;
- }
- }
-
- return true;
-}
-
+static
+bool stringsCanFinishAtSameSpot(const ue2_literal &u,
+ ue2_literal::const_iterator v_b,
+ ue2_literal::const_iterator v_e) {
+ ue2_literal::const_iterator u_e = u.end();
+ ue2_literal::const_iterator u_b = u.begin();
+
+ while (u_e != u_b && v_e != v_b) {
+ --u_e;
+ --v_e;
+
+ if (!overlaps(*u_e, *v_e)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/**
- * Check that if after u has been seen, that it is impossible for the arrival of
- * v to require the inspection of an engine earlier than u did.
+ * Check that if after u has been seen, that it is impossible for the arrival of
+ * v to require the inspection of an engine earlier than u did.
+ *
+ * Let delta be the earliest that v can be seen after u (may be zero)
*
- * Let delta be the earliest that v can be seen after u (may be zero)
- *
- * ie, we require u_loc - ulag <= v_loc - vlag (v_loc = u_loc + delta)
- * ==> - ulag <= delta - vlag
- * ==> vlag - ulag <= delta
+ * ie, we require u_loc - ulag <= v_loc - vlag (v_loc = u_loc + delta)
+ * ==> - ulag <= delta - vlag
+ * ==> vlag - ulag <= delta
*/
static
bool checkPrefix(const rose_literal_id &ul, const u32 ulag,
const rose_literal_id &vl, const u32 vlag) {
- DEBUG_PRINTF("'%s'-%u '%s'-%u\n", escapeString(ul.s).c_str(), ulag,
- escapeString(vl.s).c_str(), vlag);
-
- if (vl.delay || ul.delay) {
- /* engine related literals should not be delayed anyway */
+ DEBUG_PRINTF("'%s'-%u '%s'-%u\n", escapeString(ul.s).c_str(), ulag,
+ escapeString(vl.s).c_str(), vlag);
+
+ if (vl.delay || ul.delay) {
+ /* engine related literals should not be delayed anyway */
return false;
}
- if (ulag >= vlag) {
- assert(maxOverlap(ul, vl) <= vl.elength() - vlag + ulag);
- return true;
- }
-
- size_t min_allowed_delta = vlag - ulag;
- DEBUG_PRINTF("min allow distace %zu\n", min_allowed_delta);
-
- for (size_t i = 0; i < min_allowed_delta; i++) {
- if (stringsCanFinishAtSameSpot(ul.s, vl.s.begin(), vl.s.end() - i)) {
- DEBUG_PRINTF("v can follow u at a (too close) distance of %zu\n", i);
- return false;
- }
- }
-
- DEBUG_PRINTF("OK\n");
- return true;
-}
-
-static
-bool hasSameEngineType(const RoseVertexProps &u_prop,
- const RoseVertexProps &v_prop) {
- const left_id u_left = u_prop.left;
- const left_id v_left = v_prop.left;
-
- return !u_left.haig() == !v_left.haig()
- && !u_left.dfa() == !v_left.dfa()
- && !u_left.castle() == !v_left.castle()
- && !u_left.graph() == !v_left.graph();
-}
-
-/**
- * Verifies that merging the leftfix of vertices does not cause conflicts due
- * to the literals on the right.
- *
- * The main concern is that the lags of the literals and overlap between them
- * allow the engine check offset to potentially regress.
- *
- * Parameters are vectors of literals + lag pairs.
- *
+ if (ulag >= vlag) {
+ assert(maxOverlap(ul, vl) <= vl.elength() - vlag + ulag);
+ return true;
+ }
+
+ size_t min_allowed_delta = vlag - ulag;
+ DEBUG_PRINTF("min allow distace %zu\n", min_allowed_delta);
+
+ for (size_t i = 0; i < min_allowed_delta; i++) {
+ if (stringsCanFinishAtSameSpot(ul.s, vl.s.begin(), vl.s.end() - i)) {
+ DEBUG_PRINTF("v can follow u at a (too close) distance of %zu\n", i);
+ return false;
+ }
+ }
+
+ DEBUG_PRINTF("OK\n");
+ return true;
+}
+
+static
+bool hasSameEngineType(const RoseVertexProps &u_prop,
+ const RoseVertexProps &v_prop) {
+ const left_id u_left = u_prop.left;
+ const left_id v_left = v_prop.left;
+
+ return !u_left.haig() == !v_left.haig()
+ && !u_left.dfa() == !v_left.dfa()
+ && !u_left.castle() == !v_left.castle()
+ && !u_left.graph() == !v_left.graph();
+}
+
+/**
+ * Verifies that merging the leftfix of vertices does not cause conflicts due
+ * to the literals on the right.
+ *
+ * The main concern is that the lags of the literals and overlap between them
+ * allow the engine check offset to potentially regress.
+ *
+ * Parameters are vectors of literals + lag pairs.
+ *
* Note: if more constraints of when the leftfixes were going to be checked
- * (mandatory lookarounds passing, offset checks), more merges may be allowed.
- */
-static
-bool compatibleLiteralsForMerge(
- const vector<pair<const rose_literal_id *, u32>> &ulits,
- const vector<pair<const rose_literal_id *, u32>> &vlits) {
- assert(!ulits.empty());
- assert(!vlits.empty());
-
- // We cannot merge engines that prefix literals in different tables.
- if (ulits[0].first->table != vlits[0].first->table) {
+ * (mandatory lookarounds passing, offset checks), more merges may be allowed.
+ */
+static
+bool compatibleLiteralsForMerge(
+ const vector<pair<const rose_literal_id *, u32>> &ulits,
+ const vector<pair<const rose_literal_id *, u32>> &vlits) {
+ assert(!ulits.empty());
+ assert(!vlits.empty());
+
+ // We cannot merge engines that prefix literals in different tables.
+ if (ulits[0].first->table != vlits[0].first->table) {
DEBUG_PRINTF("literals in different tables\n");
return false;
}
- // We don't handle delayed cases yet.
- for (const auto &ue : ulits) {
- const rose_literal_id &ul = *ue.first;
- if (ul.delay) {
+ // We don't handle delayed cases yet.
+ for (const auto &ue : ulits) {
+ const rose_literal_id &ul = *ue.first;
+ if (ul.delay) {
return false;
}
}
- for (const auto &ve : vlits) {
- const rose_literal_id &vl = *ve.first;
- if (vl.delay) {
+ for (const auto &ve : vlits) {
+ const rose_literal_id &vl = *ve.first;
+ if (vl.delay) {
return false;
}
}
- /* An engine requires that all accesses to it are ordered by offsets. (ie,
- we can not check an engine's state at offset Y, if we have already
- checked its status at offset X and X > Y). If we can not establish that
+ /* An engine requires that all accesses to it are ordered by offsets. (ie,
+ we can not check an engine's state at offset Y, if we have already
+ checked its status at offset X and X > Y). If we can not establish that
the literals used for triggering will satisfy this property, then it is
- not safe to merge the engine. */
- for (const auto &ue : ulits) {
- const rose_literal_id &ul = *ue.first;
- u32 ulag = ue.second;
-
- for (const auto &ve : vlits) {
- const rose_literal_id &vl = *ve.first;
- u32 vlag = ve.second;
-
- if (!checkPrefix(ul, ulag, vl, vlag)
- || !checkPrefix(vl, vlag, ul, ulag)) {
- DEBUG_PRINTF("prefix check failed\n");
- return false;
- }
- }
- }
-
- return true;
-}
-
-/**
- * True if this graph has few enough accel states to be implemented as an NFA
- * with all of those states actually becoming accel schemes.
- */
-static
-bool isAccelerableLeftfix(const RoseBuildImpl &build, const NGHolder &g) {
- u32 num = countAccelStates(g, &build.rm, build.cc);
- DEBUG_PRINTF("graph with %zu vertices has %u accel states\n",
- num_vertices(g), num);
- return num <= NFA_MAX_ACCEL_STATES;
-}
-
-/**
- * In block mode, we want to be a little more selective -- We will only merge
- * prefix engines when the literal sets are the same or if the merged graph
- * has only grown by a small amount.
- */
-static
-bool safeBlockModeMerge(const RoseBuildImpl &build, RoseVertex u,
- RoseVertex v) {
- assert(!build.cc.streaming);
- assert(build.isRootSuccessor(u) == build.isRootSuccessor(v));
-
- // Always merge infixes if we can (subject to the other criteria in
- // mergeableRoseVertices).
- if (!build.isRootSuccessor(u)) {
- return true;
- }
-
- const RoseGraph &g = build.g;
-
- // Merge prefixes with identical literal sets (as we'd have to run them
- // both when we see those literals anyway).
- if (g[u].literals == g[v].literals) {
- return true;
- }
-
- // The rest of this function only deals with the case when both vertices
- // have graph leftfixes.
- if (!g[u].left.graph || !g[v].left.graph) {
- return false;
- }
-
- const size_t u_count = num_vertices(*g[u].left.graph);
- const size_t v_count = num_vertices(*g[v].left.graph);
- DEBUG_PRINTF("u prefix has %zu vertices, v prefix has %zu vertices\n",
- u_count, v_count);
- if (u_count > MAX_BLOCK_PREFIX_MERGE_VERTICES ||
- v_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
- DEBUG_PRINTF("prefixes too big already\n");
- return false;
- }
-
- DEBUG_PRINTF("trying merge\n");
- NGHolder h;
- cloneHolder(h, *g[v].left.graph);
- if (!mergeNfaPair(*g[u].left.graph, h, nullptr, build.cc)) {
- DEBUG_PRINTF("couldn't merge\n");
- return false;
- }
-
- const size_t merged_count = num_vertices(h);
- DEBUG_PRINTF("merged result has %zu vertices\n", merged_count);
- if (merged_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
- DEBUG_PRINTF("exceeded limit\n");
- return false;
- }
-
- // We want to only perform merges that take advantage of some
- // commonality in the two input graphs, so we check that the number of
- // vertices has only grown a small amount: somewhere between the sum
- // (no commonality) and the max (no growth at all) of the vertex counts
- // of the input graphs.
- const size_t max_size = u_count + v_count;
- const size_t min_size = max(u_count, v_count);
- const size_t max_growth = ((max_size - min_size) * 25) / 100;
- if (merged_count > min_size + max_growth) {
- DEBUG_PRINTF("grew too much\n");
- return false;
- }
-
- // We don't want to squander any chances at accelerating.
- if (!isAccelerableLeftfix(build, h) &&
- (isAccelerableLeftfix(build, *g[u].left.graph) ||
- isAccelerableLeftfix(build, *g[v].left.graph))) {
- DEBUG_PRINTF("would lose accel property\n");
- return false;
- }
-
- DEBUG_PRINTF("safe to merge\n");
- return true;
-}
-
-bool mergeableRoseVertices(const RoseBuildImpl &tbi, RoseVertex u,
- RoseVertex v) {
- assert(u != v);
-
- if (!hasSameEngineType(tbi.g[u], tbi.g[v])) {
- return false;
- }
-
- if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, u, v)) {
- return false;
- }
-
+ not safe to merge the engine. */
+ for (const auto &ue : ulits) {
+ const rose_literal_id &ul = *ue.first;
+ u32 ulag = ue.second;
+
+ for (const auto &ve : vlits) {
+ const rose_literal_id &vl = *ve.first;
+ u32 vlag = ve.second;
+
+ if (!checkPrefix(ul, ulag, vl, vlag)
+ || !checkPrefix(vl, vlag, ul, ulag)) {
+ DEBUG_PRINTF("prefix check failed\n");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * True if this graph has few enough accel states to be implemented as an NFA
+ * with all of those states actually becoming accel schemes.
+ */
+static
+bool isAccelerableLeftfix(const RoseBuildImpl &build, const NGHolder &g) {
+ u32 num = countAccelStates(g, &build.rm, build.cc);
+ DEBUG_PRINTF("graph with %zu vertices has %u accel states\n",
+ num_vertices(g), num);
+ return num <= NFA_MAX_ACCEL_STATES;
+}
+
+/**
+ * In block mode, we want to be a little more selective -- We will only merge
+ * prefix engines when the literal sets are the same or if the merged graph
+ * has only grown by a small amount.
+ */
+static
+bool safeBlockModeMerge(const RoseBuildImpl &build, RoseVertex u,
+ RoseVertex v) {
+ assert(!build.cc.streaming);
+ assert(build.isRootSuccessor(u) == build.isRootSuccessor(v));
+
+ // Always merge infixes if we can (subject to the other criteria in
+ // mergeableRoseVertices).
+ if (!build.isRootSuccessor(u)) {
+ return true;
+ }
+
+ const RoseGraph &g = build.g;
+
+ // Merge prefixes with identical literal sets (as we'd have to run them
+ // both when we see those literals anyway).
+ if (g[u].literals == g[v].literals) {
+ return true;
+ }
+
+ // The rest of this function only deals with the case when both vertices
+ // have graph leftfixes.
+ if (!g[u].left.graph || !g[v].left.graph) {
+ return false;
+ }
+
+ const size_t u_count = num_vertices(*g[u].left.graph);
+ const size_t v_count = num_vertices(*g[v].left.graph);
+ DEBUG_PRINTF("u prefix has %zu vertices, v prefix has %zu vertices\n",
+ u_count, v_count);
+ if (u_count > MAX_BLOCK_PREFIX_MERGE_VERTICES ||
+ v_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
+ DEBUG_PRINTF("prefixes too big already\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("trying merge\n");
+ NGHolder h;
+ cloneHolder(h, *g[v].left.graph);
+ if (!mergeNfaPair(*g[u].left.graph, h, nullptr, build.cc)) {
+ DEBUG_PRINTF("couldn't merge\n");
+ return false;
+ }
+
+ const size_t merged_count = num_vertices(h);
+ DEBUG_PRINTF("merged result has %zu vertices\n", merged_count);
+ if (merged_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
+ DEBUG_PRINTF("exceeded limit\n");
+ return false;
+ }
+
+ // We want to only perform merges that take advantage of some
+ // commonality in the two input graphs, so we check that the number of
+ // vertices has only grown a small amount: somewhere between the sum
+ // (no commonality) and the max (no growth at all) of the vertex counts
+ // of the input graphs.
+ const size_t max_size = u_count + v_count;
+ const size_t min_size = max(u_count, v_count);
+ const size_t max_growth = ((max_size - min_size) * 25) / 100;
+ if (merged_count > min_size + max_growth) {
+ DEBUG_PRINTF("grew too much\n");
+ return false;
+ }
+
+ // We don't want to squander any chances at accelerating.
+ if (!isAccelerableLeftfix(build, h) &&
+ (isAccelerableLeftfix(build, *g[u].left.graph) ||
+ isAccelerableLeftfix(build, *g[v].left.graph))) {
+ DEBUG_PRINTF("would lose accel property\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("safe to merge\n");
+ return true;
+}
+
+bool mergeableRoseVertices(const RoseBuildImpl &tbi, RoseVertex u,
+ RoseVertex v) {
+ assert(u != v);
+
+ if (!hasSameEngineType(tbi.g[u], tbi.g[v])) {
+ return false;
+ }
+
+ if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, u, v)) {
+ return false;
+ }
+
/* We cannot merge prefixes/vertices if they are successors of different
* root vertices */
if (tbi.isRootSuccessor(u)) {
@@ -739,105 +739,105 @@ bool mergeableRoseVertices(const RoseBuildImpl &tbi, RoseVertex u,
}
}
- u32 ulag = tbi.g[u].left.lag;
- vector<pair<const rose_literal_id *, u32>> ulits;
- ulits.reserve(tbi.g[u].literals.size());
- for (u32 id : tbi.g[u].literals) {
- ulits.emplace_back(&tbi.literals.at(id), ulag);
- }
+ u32 ulag = tbi.g[u].left.lag;
+ vector<pair<const rose_literal_id *, u32>> ulits;
+ ulits.reserve(tbi.g[u].literals.size());
+ for (u32 id : tbi.g[u].literals) {
+ ulits.emplace_back(&tbi.literals.at(id), ulag);
+ }
- u32 vlag = tbi.g[v].left.lag;
- vector<pair<const rose_literal_id *, u32>> vlits;
- vlits.reserve(tbi.g[v].literals.size());
- for (u32 id : tbi.g[v].literals) {
- vlits.emplace_back(&tbi.literals.at(id), vlag);
- }
+ u32 vlag = tbi.g[v].left.lag;
+ vector<pair<const rose_literal_id *, u32>> vlits;
+ vlits.reserve(tbi.g[v].literals.size());
+ for (u32 id : tbi.g[v].literals) {
+ vlits.emplace_back(&tbi.literals.at(id), vlag);
+ }
- if (!compatibleLiteralsForMerge(ulits, vlits)) {
- return false;
+ if (!compatibleLiteralsForMerge(ulits, vlits)) {
+ return false;
}
- DEBUG_PRINTF("roses on %zu and %zu are mergeable\n", tbi.g[u].index,
- tbi.g[v].index);
+ DEBUG_PRINTF("roses on %zu and %zu are mergeable\n", tbi.g[u].index,
+ tbi.g[v].index);
return true;
}
-/* We cannot merge an engine, if a trigger literal and a post literal overlap
- * in such a way that engine status needs to be check at a point before the
- * engine's current location.
- *
- * i.e., for a trigger literal u and a pos literal v,
- * where delta is the earliest v can appear after t,
- * we require that v_loc - v_lag >= u_loc
- * ==> u_loc + delta - v_lag >= u_loc
- * ==> delta >= v_lag
- *
- */
+/* We cannot merge an engine, if a trigger literal and a post literal overlap
+ * in such a way that engine status needs to be check at a point before the
+ * engine's current location.
+ *
+ * i.e., for a trigger literal u and a pos literal v,
+ * where delta is the earliest v can appear after t,
+ * we require that v_loc - v_lag >= u_loc
+ * ==> u_loc + delta - v_lag >= u_loc
+ * ==> delta >= v_lag
+ *
+ */
static
-bool checkPredDelay(const rose_literal_id &ul, const rose_literal_id &vl,
- u32 vlag) {
- DEBUG_PRINTF("%s %s (lag %u)\n", escapeString(ul.s).c_str(),
- escapeString(vl.s).c_str(), vlag);
-
- for (size_t i = 0; i < vlag; i++) {
- if (stringsCanFinishAtSameSpot(ul.s, vl.s.begin(), vl.s.end() - i)) {
- DEBUG_PRINTF("v can follow u at a (too close) distance of %zu\n", i);
- return false;
+bool checkPredDelay(const rose_literal_id &ul, const rose_literal_id &vl,
+ u32 vlag) {
+ DEBUG_PRINTF("%s %s (lag %u)\n", escapeString(ul.s).c_str(),
+ escapeString(vl.s).c_str(), vlag);
+
+ for (size_t i = 0; i < vlag; i++) {
+ if (stringsCanFinishAtSameSpot(ul.s, vl.s.begin(), vl.s.end() - i)) {
+ DEBUG_PRINTF("v can follow u at a (too close) distance of %zu\n", i);
+ return false;
}
}
-
- DEBUG_PRINTF("OK\n");
+
+ DEBUG_PRINTF("OK\n");
return true;
}
-template<typename VertexCont>
-static never_inline
-bool checkPredDelays(const RoseBuildImpl &build, const VertexCont &v1,
- const VertexCont &v2) {
- flat_set<RoseVertex> preds;
+template<typename VertexCont>
+static never_inline
+bool checkPredDelays(const RoseBuildImpl &build, const VertexCont &v1,
+ const VertexCont &v2) {
+ flat_set<RoseVertex> preds;
for (auto v : v1) {
- insert(&preds, inv_adjacent_vertices(v, build.g));
- }
-
- flat_set<u32> pred_lits;
-
- /* No need to examine delays of a common pred - as it must already have
- * survived the delay checks.
- *
- * This is important when the pred is in the anchored table as
- * the literal is no longer available. */
- flat_set<RoseVertex> known_good_preds;
- for (auto v : v2) {
- insert(&known_good_preds, inv_adjacent_vertices(v, build.g));
- }
-
+ insert(&preds, inv_adjacent_vertices(v, build.g));
+ }
+
+ flat_set<u32> pred_lits;
+
+ /* No need to examine delays of a common pred - as it must already have
+ * survived the delay checks.
+ *
+ * This is important when the pred is in the anchored table as
+ * the literal is no longer available. */
+ flat_set<RoseVertex> known_good_preds;
+ for (auto v : v2) {
+ insert(&known_good_preds, inv_adjacent_vertices(v, build.g));
+ }
+
for (auto u : preds) {
- if (!contains(known_good_preds, u)) {
- insert(&pred_lits, build.g[u].literals);
- }
- }
-
- vector<const rose_literal_id *> pred_rose_lits;
- pred_rose_lits.reserve(pred_lits.size());
- for (const auto &p : pred_lits) {
- pred_rose_lits.push_back(&build.literals.at(p));
- }
-
- for (auto v : v2) {
- u32 vlag = build.g[v].left.lag;
- if (!vlag) {
- continue;
- }
-
- for (const u32 vlit : build.g[v].literals) {
- const rose_literal_id &vl = build.literals.at(vlit);
- assert(!vl.delay); // this should never have got this far?
- for (const auto &ul : pred_rose_lits) {
- assert(!ul->delay); // this should never have got this far?
-
- if (!checkPredDelay(*ul, vl, vlag)) {
- return false;
- }
+ if (!contains(known_good_preds, u)) {
+ insert(&pred_lits, build.g[u].literals);
+ }
+ }
+
+ vector<const rose_literal_id *> pred_rose_lits;
+ pred_rose_lits.reserve(pred_lits.size());
+ for (const auto &p : pred_lits) {
+ pred_rose_lits.push_back(&build.literals.at(p));
+ }
+
+ for (auto v : v2) {
+ u32 vlag = build.g[v].left.lag;
+ if (!vlag) {
+ continue;
+ }
+
+ for (const u32 vlit : build.g[v].literals) {
+ const rose_literal_id &vl = build.literals.at(vlit);
+ assert(!vl.delay); // this should never have got this far?
+ for (const auto &ul : pred_rose_lits) {
+ assert(!ul->delay); // this should never have got this far?
+
+ if (!checkPredDelay(*ul, vl, vlag)) {
+ return false;
+ }
}
}
}
@@ -849,65 +849,65 @@ static
bool mergeableRoseVertices(const RoseBuildImpl &tbi,
const deque<RoseVertex> &verts1,
const deque<RoseVertex> &verts2) {
- assert(!verts1.empty());
- assert(!verts2.empty());
-
- RoseVertex u_front = verts1.front();
- RoseVertex v_front = verts2.front();
-
- /* all vertices must have the same engine type: assume all verts in each
- * group are already of the same type */
- if (!hasSameEngineType(tbi.g[u_front], tbi.g[v_front])) {
- return false;
- }
-
- bool is_prefix = tbi.isRootSuccessor(u_front);
-
- /* We cannot merge prefixes/vertices if they are successors of different
- * root vertices: similarly, assume the grouped vertices are compatible */
- if (is_prefix) {
- assert(tbi.isRootSuccessor(v_front));
- set<RoseVertex> u_preds;
- set<RoseVertex> v_preds;
- insert(&u_preds, inv_adjacent_vertices(u_front, tbi.g));
- insert(&v_preds, inv_adjacent_vertices(v_front, tbi.g));
-
- if (u_preds != v_preds) {
- return false;
- }
- }
-
- vector<pair<const rose_literal_id *, u32>> ulits; /* lit + lag pairs */
- for (auto a : verts1) {
- if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, v_front, a)) {
- return false;
- }
-
- u32 ulag = tbi.g[a].left.lag;
- for (u32 id : tbi.g[a].literals) {
- ulits.emplace_back(&tbi.literals.at(id), ulag);
- }
- }
-
- vector<pair<const rose_literal_id *, u32>> vlits;
- for (auto a : verts2) {
- if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, u_front, a)) {
- return false;
- }
-
- u32 vlag = tbi.g[a].left.lag;
- for (u32 id : tbi.g[a].literals) {
- vlits.emplace_back(&tbi.literals.at(id), vlag);
- }
- }
-
- if (!compatibleLiteralsForMerge(ulits, vlits)) {
- return false;
- }
-
+ assert(!verts1.empty());
+ assert(!verts2.empty());
+
+ RoseVertex u_front = verts1.front();
+ RoseVertex v_front = verts2.front();
+
+ /* all vertices must have the same engine type: assume all verts in each
+ * group are already of the same type */
+ if (!hasSameEngineType(tbi.g[u_front], tbi.g[v_front])) {
+ return false;
+ }
+
+ bool is_prefix = tbi.isRootSuccessor(u_front);
+
+ /* We cannot merge prefixes/vertices if they are successors of different
+ * root vertices: similarly, assume the grouped vertices are compatible */
+ if (is_prefix) {
+ assert(tbi.isRootSuccessor(v_front));
+ set<RoseVertex> u_preds;
+ set<RoseVertex> v_preds;
+ insert(&u_preds, inv_adjacent_vertices(u_front, tbi.g));
+ insert(&v_preds, inv_adjacent_vertices(v_front, tbi.g));
+
+ if (u_preds != v_preds) {
+ return false;
+ }
+ }
+
+ vector<pair<const rose_literal_id *, u32>> ulits; /* lit + lag pairs */
+ for (auto a : verts1) {
+ if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, v_front, a)) {
+ return false;
+ }
+
+ u32 ulag = tbi.g[a].left.lag;
+ for (u32 id : tbi.g[a].literals) {
+ ulits.emplace_back(&tbi.literals.at(id), ulag);
+ }
+ }
+
+ vector<pair<const rose_literal_id *, u32>> vlits;
+ for (auto a : verts2) {
+ if (!tbi.cc.streaming && !safeBlockModeMerge(tbi, u_front, a)) {
+ return false;
+ }
+
+ u32 vlag = tbi.g[a].left.lag;
+ for (u32 id : tbi.g[a].literals) {
+ vlits.emplace_back(&tbi.literals.at(id), vlag);
+ }
+ }
+
+ if (!compatibleLiteralsForMerge(ulits, vlits)) {
+ return false;
+ }
+
// Check preds are compatible as well.
- if (!checkPredDelays(tbi, verts1, verts2)
- || !checkPredDelays(tbi, verts2, verts1)) {
+ if (!checkPredDelays(tbi, verts1, verts2)
+ || !checkPredDelays(tbi, verts2, verts1)) {
return false;
}
@@ -968,35 +968,35 @@ struct RoseMergeCandidate {
}
static
-bool mergeLeftfixPair(RoseBuildImpl &build, left_id &r1, left_id &r2,
- const vector<RoseVertex> &verts1,
- const vector<RoseVertex> &verts2) {
+bool mergeLeftfixPair(RoseBuildImpl &build, left_id &r1, left_id &r2,
+ const vector<RoseVertex> &verts1,
+ const vector<RoseVertex> &verts2) {
assert(!verts1.empty() && !verts2.empty());
- DEBUG_PRINTF("merging pair of leftfixes:\n");
- DEBUG_PRINTF(" A:%016zx: tops %s\n", r1.hash(),
- as_string_list(all_tops(r1)).c_str());
- DEBUG_PRINTF(" B:%016zx: tops %s\n", r2.hash(),
- as_string_list(all_tops(r2)).c_str());
+ DEBUG_PRINTF("merging pair of leftfixes:\n");
+ DEBUG_PRINTF(" A:%016zx: tops %s\n", r1.hash(),
+ as_string_list(all_tops(r1)).c_str());
+ DEBUG_PRINTF(" B:%016zx: tops %s\n", r2.hash(),
+ as_string_list(all_tops(r2)).c_str());
+
+ RoseGraph &g = build.g;
- RoseGraph &g = build.g;
-
if (r1.graph()) {
assert(r2.graph());
assert(r1.graph()->kind == r2.graph()->kind);
- if (!mergeNfaPair(*r1.graph(), *r2.graph(), nullptr, build.cc)) {
+ if (!mergeNfaPair(*r1.graph(), *r2.graph(), nullptr, build.cc)) {
DEBUG_PRINTF("nfa merge failed\n");
return false;
}
- /* The graph in r1 has been merged into the graph in r2. Update r1's
- * vertices with the new graph ptr. mergeNfaPair() does not alter the
- * tops from the input graph so no need to update top values.
- *
- * It is the responsibility of the caller to ensure that the tops are
- * distinct when they have different trigger conditions.
- * [Note: mergeLeftfixesVariableLag() should have a common parent set]
- */
+ /* The graph in r1 has been merged into the graph in r2. Update r1's
+ * vertices with the new graph ptr. mergeNfaPair() does not alter the
+ * tops from the input graph so no need to update top values.
+ *
+ * It is the responsibility of the caller to ensure that the tops are
+ * distinct when they have different trigger conditions.
+ * [Note: mergeLeftfixesVariableLag() should have a common parent set]
+ */
shared_ptr<NGHolder> &h = g[verts2.front()].left.graph;
for (RoseVertex v : verts1) {
g[v].left.graph = h;
@@ -1005,7 +1005,7 @@ bool mergeLeftfixPair(RoseBuildImpl &build, left_id &r1, left_id &r2,
return true;
} else if (r1.castle()) {
assert(r2.castle());
- assert(build.cc.grey.allowCastle);
+ assert(build.cc.grey.allowCastle);
map<u32, u32> top_map;
if (!mergeCastle(*r2.castle(), *r1.castle(), top_map)) {
@@ -1029,200 +1029,200 @@ bool mergeLeftfixPair(RoseBuildImpl &build, left_id &r1, left_id &r2,
return false;
}
-/**
- * Checks that there is no problem due to the involved vertices if we merge two
- * leftfix engines.
- *
- * This functions takes the vertices on the right of the two engines.
- *
- * Unlike mergeableRoseVertices(), this does not:
- * - check that engines themselves can be merged
- * - use heuristics to find out if merging the engines is wise.
- */
+/**
+ * Checks that there is no problem due to the involved vertices if we merge two
+ * leftfix engines.
+ *
+ * This functions takes the vertices on the right of the two engines.
+ *
+ * Unlike mergeableRoseVertices(), this does not:
+ * - check that engines themselves can be merged
+ * - use heuristics to find out if merging the engines is wise.
+ */
static
-bool checkVerticesOkForLeftfixMerge(const RoseBuildImpl &build,
- const vector<RoseVertex> &targets_1,
- const vector<RoseVertex> &targets_2) {
- assert(!targets_1.empty());
- assert(!targets_2.empty());
-
- vector<pair<const rose_literal_id *, u32>> ulits; /* lit + lag pairs */
- for (auto a : targets_1) {
- u32 ulag = build.g[a].left.lag;
- for (u32 id : build.g[a].literals) {
- ulits.emplace_back(&build.literals.at(id), ulag);
- }
- }
-
- vector<pair<const rose_literal_id *, u32>> vlits;
- for (auto a : targets_2) {
- u32 vlag = build.g[a].left.lag;
- for (u32 id : build.g[a].literals) {
- vlits.emplace_back(&build.literals.at(id), vlag);
- }
- }
-
- if (!compatibleLiteralsForMerge(ulits, vlits)) {
- return false;
- }
-
- // Check preds are compatible as well.
- if (!checkPredDelays(build, targets_1, targets_2)
- || !checkPredDelays(build, targets_2, targets_1)) {
- return false;
- }
-
- DEBUG_PRINTF("vertex sets are mergeable\n");
- return true;
-}
-
-/**
- * In block mode, we want to be a little more selective -- we will only merge
- * prefix engines when the literal sets are the same or if the merged graph
- * has only grown by a small amount.
- */
-static
-bool goodBlockModeMerge(const RoseBuildImpl &build,
- const vector<RoseVertex> &u_verts, const left_id &u_eng,
- const vector<RoseVertex> &v_verts,
- const left_id &v_eng) {
- assert(!build.cc.streaming);
-
- // Always merge infixes if we can (subject to the other criteria in
- // mergeableRoseVertices).
- if (!build.isRootSuccessor(u_verts.front())) {
- return true;
- }
-
- const RoseGraph &g = build.g;
-
- flat_set<u32> u_lits;
- for (RoseVertex u : u_verts) {
- insert(&u_lits, g[u].literals);
- }
-
- flat_set<u32> v_lits;
- for (RoseVertex v : v_verts) {
- insert(&v_lits, g[v].literals);
- }
-
- // Merge prefixes with identical literal sets (as we'd have to run them
- // both when we see those literals anyway).
- if (u_lits == v_lits) {
- return true;
- }
-
- // The rest of this function only deals with the case when have graph
- // leftfixes.
- if (!u_eng.graph()) {
- return false;
- }
- assert(v_eng.graph());
- const NGHolder &ug = *u_eng.graph();
- const NGHolder &vg = *v_eng.graph();
-
- size_t u_count = num_vertices(ug);
- size_t v_count = num_vertices(vg);
- DEBUG_PRINTF("u prefix has %zu vertices, v prefix has %zu vertices\n",
- u_count, v_count);
- if (u_count > MAX_BLOCK_PREFIX_MERGE_VERTICES ||
- v_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
- DEBUG_PRINTF("prefixes too big already\n");
- return false;
- }
-
- DEBUG_PRINTF("trying merge\n");
- NGHolder h;
- cloneHolder(h, vg);
- if (!mergeNfaPair(ug, h, nullptr, build.cc)) {
- DEBUG_PRINTF("couldn't merge\n");
- return false;
- }
-
- const size_t merged_count = num_vertices(h);
- DEBUG_PRINTF("merged result has %zu vertices\n", merged_count);
- if (merged_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
- DEBUG_PRINTF("exceeded limit\n");
- return false;
- }
-
- // We want to only perform merges that take advantage of some
- // commonality in the two input graphs, so we check that the number of
- // vertices has only grown a small amount: somewhere between the sum
- // (no commonality) and the max (no growth at all) of the vertex counts
- // of the input graphs.
- size_t max_size = u_count + v_count;
- size_t min_size = max(u_count, v_count);
- size_t max_growth = ((max_size - min_size) * 25) / 100;
- if (merged_count > min_size + max_growth) {
- DEBUG_PRINTF("grew too much\n");
- return false;
- }
-
- // We don't want to squander any chances at accelerating.
- if (!isAccelerableLeftfix(build, h)
- && (isAccelerableLeftfix(build, ug)
- || isAccelerableLeftfix(build, vg))) {
- DEBUG_PRINTF("would lose accel property\n");
- return false;
- }
-
- DEBUG_PRINTF("safe to merge\n");
- return true;
-}
-
-/**
- * Merge r1 into r2 if safe and appropriate. Returns true on success.
- */
-static
-bool mergeLeftVL_tryMergeCandidate(RoseBuildImpl &build, left_id &r1,
- const vector<RoseVertex> &targets_1,
- left_id &r2,
- const vector<RoseVertex> &targets_2) {
- if (targets_1.empty() || targets_2.empty()) {
- /* one of the engines has already been merged away */
- return false;
- }
-
- assert(!r1.graph() == !r2.graph());
- if (r1.graph()) {
- NGHolder *h1 = r1.graph();
- NGHolder *h2 = r2.graph();
- CharReach stop1 = findStopAlphabet(*h1, SOM_NONE);
- CharReach stop2 = findStopAlphabet(*h2, SOM_NONE);
- CharReach stopboth = stop1 & stop2;
- DEBUG_PRINTF("stop1=%zu, stop2=%zu, stopboth=%zu\n", stop1.count(),
- stop2.count(), stopboth.count());
- if (stopboth.count() < 10
- && (stop1.count() > 10 || stop2.count() > 10)) {
- DEBUG_PRINTF("skip merge, would kill stop alphabet\n");
- return false;
- }
- size_t maxstop = max(stop1.count(), stop2.count());
- if (maxstop > 200 && stopboth.count() < 200) {
- DEBUG_PRINTF("skip merge, would reduce stop alphabet\n");
- return false;
- }
- }
-
- /* Rechecking that the targets are compatible, as we may have already
- * merged new states into r1 or r2 and we need to verify that this
- * candidate is still ok. */
- if (!checkVerticesOkForLeftfixMerge(build, targets_1, targets_2)) {
- return false;
- }
-
- if (!build.cc.streaming
- && !goodBlockModeMerge(build, targets_1, r1, targets_2, r2)) {
- return false;
- }
-
- return mergeLeftfixPair(build, r1, r2, targets_1, targets_2);
+bool checkVerticesOkForLeftfixMerge(const RoseBuildImpl &build,
+ const vector<RoseVertex> &targets_1,
+ const vector<RoseVertex> &targets_2) {
+ assert(!targets_1.empty());
+ assert(!targets_2.empty());
+
+ vector<pair<const rose_literal_id *, u32>> ulits; /* lit + lag pairs */
+ for (auto a : targets_1) {
+ u32 ulag = build.g[a].left.lag;
+ for (u32 id : build.g[a].literals) {
+ ulits.emplace_back(&build.literals.at(id), ulag);
+ }
+ }
+
+ vector<pair<const rose_literal_id *, u32>> vlits;
+ for (auto a : targets_2) {
+ u32 vlag = build.g[a].left.lag;
+ for (u32 id : build.g[a].literals) {
+ vlits.emplace_back(&build.literals.at(id), vlag);
+ }
+ }
+
+ if (!compatibleLiteralsForMerge(ulits, vlits)) {
+ return false;
+ }
+
+ // Check preds are compatible as well.
+ if (!checkPredDelays(build, targets_1, targets_2)
+ || !checkPredDelays(build, targets_2, targets_1)) {
+ return false;
+ }
+
+ DEBUG_PRINTF("vertex sets are mergeable\n");
+ return true;
+}
+
+/**
+ * In block mode, we want to be a little more selective -- we will only merge
+ * prefix engines when the literal sets are the same or if the merged graph
+ * has only grown by a small amount.
+ */
+static
+bool goodBlockModeMerge(const RoseBuildImpl &build,
+ const vector<RoseVertex> &u_verts, const left_id &u_eng,
+ const vector<RoseVertex> &v_verts,
+ const left_id &v_eng) {
+ assert(!build.cc.streaming);
+
+ // Always merge infixes if we can (subject to the other criteria in
+ // mergeableRoseVertices).
+ if (!build.isRootSuccessor(u_verts.front())) {
+ return true;
+ }
+
+ const RoseGraph &g = build.g;
+
+ flat_set<u32> u_lits;
+ for (RoseVertex u : u_verts) {
+ insert(&u_lits, g[u].literals);
+ }
+
+ flat_set<u32> v_lits;
+ for (RoseVertex v : v_verts) {
+ insert(&v_lits, g[v].literals);
+ }
+
+ // Merge prefixes with identical literal sets (as we'd have to run them
+ // both when we see those literals anyway).
+ if (u_lits == v_lits) {
+ return true;
+ }
+
+ // The rest of this function only deals with the case when have graph
+ // leftfixes.
+ if (!u_eng.graph()) {
+ return false;
+ }
+ assert(v_eng.graph());
+ const NGHolder &ug = *u_eng.graph();
+ const NGHolder &vg = *v_eng.graph();
+
+ size_t u_count = num_vertices(ug);
+ size_t v_count = num_vertices(vg);
+ DEBUG_PRINTF("u prefix has %zu vertices, v prefix has %zu vertices\n",
+ u_count, v_count);
+ if (u_count > MAX_BLOCK_PREFIX_MERGE_VERTICES ||
+ v_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
+ DEBUG_PRINTF("prefixes too big already\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("trying merge\n");
+ NGHolder h;
+ cloneHolder(h, vg);
+ if (!mergeNfaPair(ug, h, nullptr, build.cc)) {
+ DEBUG_PRINTF("couldn't merge\n");
+ return false;
+ }
+
+ const size_t merged_count = num_vertices(h);
+ DEBUG_PRINTF("merged result has %zu vertices\n", merged_count);
+ if (merged_count > MAX_BLOCK_PREFIX_MERGE_VERTICES) {
+ DEBUG_PRINTF("exceeded limit\n");
+ return false;
+ }
+
+ // We want to only perform merges that take advantage of some
+ // commonality in the two input graphs, so we check that the number of
+ // vertices has only grown a small amount: somewhere between the sum
+ // (no commonality) and the max (no growth at all) of the vertex counts
+ // of the input graphs.
+ size_t max_size = u_count + v_count;
+ size_t min_size = max(u_count, v_count);
+ size_t max_growth = ((max_size - min_size) * 25) / 100;
+ if (merged_count > min_size + max_growth) {
+ DEBUG_PRINTF("grew too much\n");
+ return false;
+ }
+
+ // We don't want to squander any chances at accelerating.
+ if (!isAccelerableLeftfix(build, h)
+ && (isAccelerableLeftfix(build, ug)
+ || isAccelerableLeftfix(build, vg))) {
+ DEBUG_PRINTF("would lose accel property\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("safe to merge\n");
+ return true;
+}
+
+/**
+ * Merge r1 into r2 if safe and appropriate. Returns true on success.
+ */
+static
+bool mergeLeftVL_tryMergeCandidate(RoseBuildImpl &build, left_id &r1,
+ const vector<RoseVertex> &targets_1,
+ left_id &r2,
+ const vector<RoseVertex> &targets_2) {
+ if (targets_1.empty() || targets_2.empty()) {
+ /* one of the engines has already been merged away */
+ return false;
+ }
+
+ assert(!r1.graph() == !r2.graph());
+ if (r1.graph()) {
+ NGHolder *h1 = r1.graph();
+ NGHolder *h2 = r2.graph();
+ CharReach stop1 = findStopAlphabet(*h1, SOM_NONE);
+ CharReach stop2 = findStopAlphabet(*h2, SOM_NONE);
+ CharReach stopboth = stop1 & stop2;
+ DEBUG_PRINTF("stop1=%zu, stop2=%zu, stopboth=%zu\n", stop1.count(),
+ stop2.count(), stopboth.count());
+ if (stopboth.count() < 10
+ && (stop1.count() > 10 || stop2.count() > 10)) {
+ DEBUG_PRINTF("skip merge, would kill stop alphabet\n");
+ return false;
+ }
+ size_t maxstop = max(stop1.count(), stop2.count());
+ if (maxstop > 200 && stopboth.count() < 200) {
+ DEBUG_PRINTF("skip merge, would reduce stop alphabet\n");
+ return false;
+ }
+ }
+
+ /* Rechecking that the targets are compatible, as we may have already
+ * merged new states into r1 or r2 and we need to verify that this
+ * candidate is still ok. */
+ if (!checkVerticesOkForLeftfixMerge(build, targets_1, targets_2)) {
+ return false;
+ }
+
+ if (!build.cc.streaming
+ && !goodBlockModeMerge(build, targets_1, r1, targets_2, r2)) {
+ return false;
+ }
+
+ return mergeLeftfixPair(build, r1, r2, targets_1, targets_2);
}
static
bool nfaHasNarrowStart(const NGHolder &g) {
- if (out_degree(g.startDs, g) > 1) {
+ if (out_degree(g.startDs, g) > 1) {
return false; // unanchored
}
@@ -1267,91 +1267,91 @@ bool hasReformedStartDotStar(const NGHolder &h, const Grey &grey) {
static
u32 commonPrefixLength(left_id &r1, left_id &r2) {
if (r1.graph() && r2.graph()) {
- return commonPrefixLength(*r1.graph(), *r2.graph());
+ return commonPrefixLength(*r1.graph(), *r2.graph());
} else if (r1.castle() && r2.castle()) {
return min(findMinWidth(*r1.castle()), findMinWidth(*r2.castle()));
}
return 0;
}
-namespace {
-struct MergeKey {
- MergeKey(const left_id &left, flat_set<RoseVertex> parents_in) :
- parents(std::move(parents_in)) {
-
- // We want to distinguish prefixes (but not infixes) on whether they
- // have a narrow start or max width.
- if (left.graph() && !is_triggered(*left.graph())) {
- const NGHolder &h = *left.graph();
- narrowStart = nfaHasNarrowStart(h);
- hasMaxWidth = nfaHasFiniteMaxWidth(h);
- } else {
- narrowStart = false;
- hasMaxWidth = false;
- }
-
- if (left.castle()) {
- /* castles should have a non-empty reach */
- assert(left.castle()->reach().any());
- castle_cr = left.castle()->reach();
- } else {
- assert(left.graph());
- }
- }
-
- bool operator<(const MergeKey &b) const {
- const MergeKey &a = *this;
- ORDER_CHECK(narrowStart);
- ORDER_CHECK(hasMaxWidth);
- ORDER_CHECK(castle_cr);
- ORDER_CHECK(parents);
- return false;
- }
-
- // NOTE: these two bool discriminators are only used for prefixes, not
- // infixes.
- bool narrowStart;
- bool hasMaxWidth;
- CharReach castle_cr; /* empty for graphs, reach (non-empty) for castles. */
-
- flat_set<RoseVertex> parents;
-};
-}
-
-template <typename T>
-static
-void chunk(vector<T> in, vector<vector<T>> *out, size_t chunk_size) {
- if (in.size() <= chunk_size) {
- out->push_back(std::move(in));
- return;
- }
-
- out->push_back(vector<T>());
- out->back().reserve(chunk_size);
- for (const auto &t : in) {
- if (out->back().size() >= chunk_size) {
- out->push_back(vector<T>());
- out->back().reserve(chunk_size);
- }
- out->back().push_back(std::move(t));
- }
-}
-
-static
-insertion_ordered_map<left_id, vector<RoseVertex>> get_eng_verts(RoseGraph &g) {
- insertion_ordered_map<left_id, vector<RoseVertex>> eng_verts;
- for (auto v : vertices_range(g)) {
- const auto &left = g[v].left;
- if (!left) {
- continue;
- }
- assert(contains(all_reports(left), left.leftfix_report));
- eng_verts[left].push_back(v);
- }
-
- return eng_verts;
-}
-
+namespace {
+struct MergeKey {
+ MergeKey(const left_id &left, flat_set<RoseVertex> parents_in) :
+ parents(std::move(parents_in)) {
+
+ // We want to distinguish prefixes (but not infixes) on whether they
+ // have a narrow start or max width.
+ if (left.graph() && !is_triggered(*left.graph())) {
+ const NGHolder &h = *left.graph();
+ narrowStart = nfaHasNarrowStart(h);
+ hasMaxWidth = nfaHasFiniteMaxWidth(h);
+ } else {
+ narrowStart = false;
+ hasMaxWidth = false;
+ }
+
+ if (left.castle()) {
+ /* castles should have a non-empty reach */
+ assert(left.castle()->reach().any());
+ castle_cr = left.castle()->reach();
+ } else {
+ assert(left.graph());
+ }
+ }
+
+ bool operator<(const MergeKey &b) const {
+ const MergeKey &a = *this;
+ ORDER_CHECK(narrowStart);
+ ORDER_CHECK(hasMaxWidth);
+ ORDER_CHECK(castle_cr);
+ ORDER_CHECK(parents);
+ return false;
+ }
+
+ // NOTE: these two bool discriminators are only used for prefixes, not
+ // infixes.
+ bool narrowStart;
+ bool hasMaxWidth;
+ CharReach castle_cr; /* empty for graphs, reach (non-empty) for castles. */
+
+ flat_set<RoseVertex> parents;
+};
+}
+
+template <typename T>
+static
+void chunk(vector<T> in, vector<vector<T>> *out, size_t chunk_size) {
+ if (in.size() <= chunk_size) {
+ out->push_back(std::move(in));
+ return;
+ }
+
+ out->push_back(vector<T>());
+ out->back().reserve(chunk_size);
+ for (const auto &t : in) {
+ if (out->back().size() >= chunk_size) {
+ out->push_back(vector<T>());
+ out->back().reserve(chunk_size);
+ }
+ out->back().push_back(std::move(t));
+ }
+}
+
+static
+insertion_ordered_map<left_id, vector<RoseVertex>> get_eng_verts(RoseGraph &g) {
+ insertion_ordered_map<left_id, vector<RoseVertex>> eng_verts;
+ for (auto v : vertices_range(g)) {
+ const auto &left = g[v].left;
+ if (!left) {
+ continue;
+ }
+ assert(contains(all_reports(left), left.leftfix_report));
+ eng_verts[left].push_back(v);
+ }
+
+ return eng_verts;
+}
+
/**
* This pass attempts to merge prefix/infix engines which share a common set of
* parent vertices.
@@ -1363,9 +1363,9 @@ insertion_ordered_map<left_id, vector<RoseVertex>> get_eng_verts(RoseGraph &g) {
* the stop alphabet.
*
* Infixes:
- * - It is expected that when this is run all infixes are still at the single
- * top stage as we have not yet merged unrelated infixes together. After
- * execution, castles may have multiple (but equivalent) tops.
+ * - It is expected that when this is run all infixes are still at the single
+ * top stage as we have not yet merged unrelated infixes together. After
+ * execution, castles may have multiple (but equivalent) tops.
*
* Prefixes:
* - transient prefixes are not considered.
@@ -1375,48 +1375,48 @@ insertion_ordered_map<left_id, vector<RoseVertex>> get_eng_verts(RoseGraph &g) {
* - merges are not considered in cases where dot star start state will be
* reformed to optimise a leading repeat.
*/
-void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
- if (!build.cc.grey.mergeRose) {
+void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
+ if (!build.cc.grey.mergeRose) {
return;
}
- assert(!hasOrphanedTops(build));
+ assert(!hasOrphanedTops(build));
- RoseGraph &g = build.g;
+ RoseGraph &g = build.g;
DEBUG_PRINTF("-----\n");
DEBUG_PRINTF("entry\n");
DEBUG_PRINTF("-----\n");
- auto eng_verts = get_eng_verts(g);
+ auto eng_verts = get_eng_verts(g);
- map<MergeKey, vector<left_id>> engine_groups;
- for (const auto &e : eng_verts) {
- const left_id &left = e.first;
- const auto &verts = e.second;
+ map<MergeKey, vector<left_id>> engine_groups;
+ for (const auto &e : eng_verts) {
+ const left_id &left = e.first;
+ const auto &verts = e.second;
// Only non-transient for the moment.
- if (contains(build.transient, left)) {
+ if (contains(build.transient, left)) {
continue;
}
// No forced McClellan or Haig infix merges.
- if (left.dfa() || left.haig()) {
+ if (left.dfa() || left.haig()) {
continue;
}
- assert(left.graph() || left.castle());
+ assert(left.graph() || left.castle());
- if (left.graph()) {
- const NGHolder &h = *left.graph();
- /* we should not have merged yet */
- assert(!is_triggered(h) || onlyOneTop(h));
+ if (left.graph()) {
+ const NGHolder &h = *left.graph();
+ /* we should not have merged yet */
+ assert(!is_triggered(h) || onlyOneTop(h));
- if (hasReformedStartDotStar(h, build.cc.grey)) {
+ if (hasReformedStartDotStar(h, build.cc.grey)) {
continue; // preserve the optimisation of the leading repeat
}
- } else {
- assert(left.castle());
+ } else {
+ assert(left.castle());
- if (!build.cc.grey.allowCastle) {
- DEBUG_PRINTF("castle merging disallowed by greybox\n");
+ if (!build.cc.grey.allowCastle) {
+ DEBUG_PRINTF("castle merging disallowed by greybox\n");
continue;
}
}
@@ -1425,20 +1425,20 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
// parents, so that we can merge differently-anchored prefix roses
// together. (Prompted by UE-2100)
- flat_set<RoseVertex> parents;
- for (RoseVertex v : verts) {
- insert(&parents, inv_adjacent_vertices_range(v, g));
+ flat_set<RoseVertex> parents;
+ for (RoseVertex v : verts) {
+ insert(&parents, inv_adjacent_vertices_range(v, g));
}
- if (contains(parents, build.anchored_root)) {
- parents.erase(build.anchored_root);
- parents.insert(build.root);
+ if (contains(parents, build.anchored_root)) {
+ parents.erase(build.anchored_root);
+ parents.insert(build.root);
}
- assert(!parents.empty());
-
+ assert(!parents.empty());
+
#ifndef _WIN32
- engine_groups[MergeKey(left, parents)].push_back(left);
+ engine_groups[MergeKey(left, parents)].push_back(left);
#else
// On windows, when passing MergeKey object into map 'engine_groups',
// it will not be copied, but will be freed along with
@@ -1452,59 +1452,59 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
#endif
}
- vector<vector<left_id>> chunks;
- for (auto &raw_group : engine_groups | map_values) {
- chunk(move(raw_group), &chunks, MERGE_GROUP_SIZE_MAX);
- }
- engine_groups.clear();
-
- DEBUG_PRINTF("chunked roses into %zu groups\n", chunks.size());
-
- for (auto &roses : chunks) {
- if (roses.size() < 2) {
+ vector<vector<left_id>> chunks;
+ for (auto &raw_group : engine_groups | map_values) {
+ chunk(move(raw_group), &chunks, MERGE_GROUP_SIZE_MAX);
+ }
+ engine_groups.clear();
+
+ DEBUG_PRINTF("chunked roses into %zu groups\n", chunks.size());
+
+ for (auto &roses : chunks) {
+ if (roses.size() < 2) {
continue;
}
- // All pairs on the prio queue.
- u32 tie_breaker = 0;
- priority_queue<RoseMergeCandidate> pq;
- for (auto it = roses.begin(), ite = roses.end(); it != ite; ++it) {
- left_id r1 = *it;
- const vector<RoseVertex> &targets_1 = eng_verts[r1];
-
- for (auto jt = next(it); jt != ite; ++jt) {
- left_id r2 = *jt;
-
- /* we should have already split on engine types and reach */
- assert(!r1.castle() == !r2.castle());
- assert(!r1.graph() == !r2.graph());
- assert(!r1.castle()
- || r1.castle()->reach() == r2.castle()->reach());
-
- const vector<RoseVertex> &targets_2 = eng_verts[r2];
- if (!checkVerticesOkForLeftfixMerge(build, targets_1,
- targets_2)) {
- continue; // No point queueing unmergeable cases.
- }
-
- u32 cpl = commonPrefixLength(r1, r2);
- pq.push(RoseMergeCandidate(r1, r2, cpl, tie_breaker++));
- }
- }
-
- DEBUG_PRINTF("merge queue has %zu entries\n", pq.size());
-
- while (!pq.empty()) {
- left_id r1 = pq.top().r1;
- left_id r2 = pq.top().r2;
- DEBUG_PRINTF("pq pop h1=%p, h2=%p, cpl=%u, states=%u\n",
- r1.graph(), r2.graph(), pq.top().cpl, pq.top().states);
- pq.pop();
- vector<RoseVertex> &targets_1 = eng_verts[r1];
- vector<RoseVertex> &targets_2 = eng_verts[r2];
- if (mergeLeftVL_tryMergeCandidate(build, r1, targets_1, r2,
- targets_2)) {
- insert(&targets_2, targets_2.end(), targets_1);
- targets_1.clear();
+ // All pairs on the prio queue.
+ u32 tie_breaker = 0;
+ priority_queue<RoseMergeCandidate> pq;
+ for (auto it = roses.begin(), ite = roses.end(); it != ite; ++it) {
+ left_id r1 = *it;
+ const vector<RoseVertex> &targets_1 = eng_verts[r1];
+
+ for (auto jt = next(it); jt != ite; ++jt) {
+ left_id r2 = *jt;
+
+ /* we should have already split on engine types and reach */
+ assert(!r1.castle() == !r2.castle());
+ assert(!r1.graph() == !r2.graph());
+ assert(!r1.castle()
+ || r1.castle()->reach() == r2.castle()->reach());
+
+ const vector<RoseVertex> &targets_2 = eng_verts[r2];
+ if (!checkVerticesOkForLeftfixMerge(build, targets_1,
+ targets_2)) {
+ continue; // No point queueing unmergeable cases.
+ }
+
+ u32 cpl = commonPrefixLength(r1, r2);
+ pq.push(RoseMergeCandidate(r1, r2, cpl, tie_breaker++));
+ }
+ }
+
+ DEBUG_PRINTF("merge queue has %zu entries\n", pq.size());
+
+ while (!pq.empty()) {
+ left_id r1 = pq.top().r1;
+ left_id r2 = pq.top().r2;
+ DEBUG_PRINTF("pq pop h1=%p, h2=%p, cpl=%u, states=%u\n",
+ r1.graph(), r2.graph(), pq.top().cpl, pq.top().states);
+ pq.pop();
+ vector<RoseVertex> &targets_1 = eng_verts[r1];
+ vector<RoseVertex> &targets_2 = eng_verts[r2];
+ if (mergeLeftVL_tryMergeCandidate(build, r1, targets_1, r2,
+ targets_2)) {
+ insert(&targets_2, targets_2.end(), targets_1);
+ targets_1.clear();
}
}
}
@@ -1512,7 +1512,7 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
DEBUG_PRINTF("-----\n");
DEBUG_PRINTF("exit\n");
DEBUG_PRINTF("-----\n");
- assert(!hasOrphanedTops(build));
+ assert(!hasOrphanedTops(build));
}
namespace {
@@ -1521,15 +1521,15 @@ namespace {
* Key used to group sets of leftfixes for the dedupeLeftfixesVariableLag path.
*/
struct DedupeLeftKey {
- DedupeLeftKey(const RoseBuildImpl &build,
- flat_set<pair<size_t, u32>> preds_in, const left_id &left)
- : left_hash(hashLeftfix(left)), preds(move(preds_in)),
- transient(contains(build.transient, left)) {
+ DedupeLeftKey(const RoseBuildImpl &build,
+ flat_set<pair<size_t, u32>> preds_in, const left_id &left)
+ : left_hash(hashLeftfix(left)), preds(move(preds_in)),
+ transient(contains(build.transient, left)) {
}
bool operator<(const DedupeLeftKey &b) const {
- return tie(left_hash, preds, transient)
- < tie(b.left_hash, b.preds, b.transient);
+ return tie(left_hash, preds, transient)
+ < tie(b.left_hash, b.preds, b.transient);
}
private:
@@ -1538,23 +1538,23 @@ private:
size_t left_hash;
/** For each in-edge, the pair of (parent index, edge top). */
- flat_set<pair<size_t, u32>> preds;
-
- /** We don't want to combine transient with non-transient. */
- bool transient;
+ flat_set<pair<size_t, u32>> preds;
+
+ /** We don't want to combine transient with non-transient. */
+ bool transient;
};
} // namespace
-static
-flat_set<pair<size_t, u32>> get_pred_tops(RoseVertex v, const RoseGraph &g) {
- flat_set<pair<size_t, u32>> preds;
- for (const auto &e : in_edges_range(v, g)) {
- preds.emplace(g[source(e, g)].index, g[e].rose_top);
- }
- return preds;
-}
-
+static
+flat_set<pair<size_t, u32>> get_pred_tops(RoseVertex v, const RoseGraph &g) {
+ flat_set<pair<size_t, u32>> preds;
+ for (const auto &e : in_edges_range(v, g)) {
+ preds.emplace(g[source(e, g)].index, g[e].rose_top);
+ }
+ return preds;
+}
+
/**
* This is a generalisation of \ref dedupeLeftfixes which relaxes two
* restrictions: multiple predecessor roles are allowed and the delay used by
@@ -1572,99 +1572,99 @@ flat_set<pair<size_t, u32>> get_pred_tops(RoseVertex v, const RoseGraph &g) {
* successor may want to inspect it; the overlap relationships between the
* involved literals are examined to ensure that this property holds.
*
- * Note: this is unable to dedupe when delayed literals are involved unlike
- * dedupeLeftfixes.
+ * Note: this is unable to dedupe when delayed literals are involved unlike
+ * dedupeLeftfixes.
*/
-void dedupeLeftfixesVariableLag(RoseBuildImpl &build) {
+void dedupeLeftfixesVariableLag(RoseBuildImpl &build) {
DEBUG_PRINTF("entry\n");
- RoseGraph &g = build.g;
- auto eng_verts = get_eng_verts(g);
+ RoseGraph &g = build.g;
+ auto eng_verts = get_eng_verts(g);
- map<DedupeLeftKey, vector<left_id>> engine_groups;
- for (const auto &e : eng_verts) {
- const left_id &left = e.first;
- const auto &verts = e.second;
+ map<DedupeLeftKey, vector<left_id>> engine_groups;
+ for (const auto &e : eng_verts) {
+ const left_id &left = e.first;
+ const auto &verts = e.second;
- /* There should only be one report on an engine as no merges have
- * happened yet. (aside from eod prefixes) */
- if (all_reports(left).size() != 1) {
- assert(any_of_in(adjacent_vertices_range(verts.front(), g),
- [&](RoseVertex w) { return g[w].eod_accept; }));
+ /* There should only be one report on an engine as no merges have
+ * happened yet. (aside from eod prefixes) */
+ if (all_reports(left).size() != 1) {
+ assert(any_of_in(adjacent_vertices_range(verts.front(), g),
+ [&](RoseVertex w) { return g[w].eod_accept; }));
continue;
}
- if (left.haig()) {
- /* TODO: allow deduping of identical haigs */
+ if (left.haig()) {
+ /* TODO: allow deduping of identical haigs */
continue;
}
- if (left.graph()) {
- /* we should not have merged yet */
- assert(!is_triggered(*left.graph()) || onlyOneTop(*left.graph()));
- }
-
- auto preds = get_pred_tops(verts.front(), g);
- for (RoseVertex v : verts) {
- if (preds != get_pred_tops(v, g)) {
- DEBUG_PRINTF("distinct pred sets\n");
- continue;
- }
- }
- engine_groups[DedupeLeftKey(build, move(preds), left)].push_back(left);
- }
-
- /* We don't bother chunking as we expect deduping to be successful if the
- * hashes match */
-
- for (auto &group : engine_groups | map_values) {
- DEBUG_PRINTF("group of %zu roses\n", group.size());
-
- if (group.size() < 2) {
+ if (left.graph()) {
+ /* we should not have merged yet */
+ assert(!is_triggered(*left.graph()) || onlyOneTop(*left.graph()));
+ }
+
+ auto preds = get_pred_tops(verts.front(), g);
+ for (RoseVertex v : verts) {
+ if (preds != get_pred_tops(v, g)) {
+ DEBUG_PRINTF("distinct pred sets\n");
+ continue;
+ }
+ }
+ engine_groups[DedupeLeftKey(build, move(preds), left)].push_back(left);
+ }
+
+ /* We don't bother chunking as we expect deduping to be successful if the
+ * hashes match */
+
+ for (auto &group : engine_groups | map_values) {
+ DEBUG_PRINTF("group of %zu roses\n", group.size());
+
+ if (group.size() < 2) {
continue;
}
- for (auto it = group.begin(); it != group.end(); ++it) {
+ for (auto it = group.begin(); it != group.end(); ++it) {
left_id r1 = *it;
- vector<RoseVertex> &verts1 = eng_verts[r1];
- assert(!verts1.empty()); /* cleared engines should be behind us */
+ vector<RoseVertex> &verts1 = eng_verts[r1];
+ assert(!verts1.empty()); /* cleared engines should be behind us */
+
+ assert(all_reports(r1).size() == 1);
+ ReportID r1_report = *all_reports(r1).begin();
- assert(all_reports(r1).size() == 1);
- ReportID r1_report = *all_reports(r1).begin();
-
- for (auto jt = next(it); jt != group.end(); ++jt) {
+ for (auto jt = next(it); jt != group.end(); ++jt) {
left_id r2 = *jt;
- vector<RoseVertex> &verts2 = eng_verts[r2];
- assert(!verts2.empty());
- assert(all_reports(r2).size() == 1);
- ReportID r2_report = *all_reports(r2).begin();
+ vector<RoseVertex> &verts2 = eng_verts[r2];
+ assert(!verts2.empty());
+ assert(all_reports(r2).size() == 1);
+ ReportID r2_report = *all_reports(r2).begin();
- if (!is_equal(r1, r1_report, r2, r2_report)) {
+ if (!is_equal(r1, r1_report, r2, r2_report)) {
continue;
}
- if (!checkVerticesOkForLeftfixMerge(build, verts1, verts2)) {
+ if (!checkVerticesOkForLeftfixMerge(build, verts1, verts2)) {
continue;
}
DEBUG_PRINTF("%p and %p are dupes\n", r1.graph(), r2.graph());
- // Replace r1 with r2.
+ // Replace r1 with r2.
for (auto v : verts1) {
DEBUG_PRINTF("replacing report %u with %u on %zu\n",
- r2_report, r1_report, g[v].index);
+ r2_report, r1_report, g[v].index);
u32 orig_lag = g[v].left.lag;
- g[v].left = g[verts2.front()].left;
+ g[v].left = g[verts2.front()].left;
g[v].left.lag = orig_lag;
}
-
- insert(&verts2, verts2.end(), verts1);
- verts1.clear();
-
- /* remove stale entry from transient set, if present */
- build.transient.erase(r1);
-
+
+ insert(&verts2, verts2.end(), verts1);
+ verts1.clear();
+
+ /* remove stale entry from transient set, if present */
+ build.transient.erase(r1);
+
break;
}
}
@@ -1672,7 +1672,7 @@ void dedupeLeftfixesVariableLag(RoseBuildImpl &build) {
}
static
-u32 findUnusedTop(const flat_set<u32> &tops) {
+u32 findUnusedTop(const flat_set<u32> &tops) {
u32 i = 0;
while (contains(tops, i)) {
i++;
@@ -1688,19 +1688,19 @@ void replaceTops(NGHolder &h, const map<u32, u32> &top_mapping) {
if (v == h.startDs) {
continue;
}
- flat_set<u32> new_tops;
- for (u32 t : h[e].tops) {
- DEBUG_PRINTF("vertex %zu has top %u\n", h[v].index, t);
- new_tops.insert(top_mapping.at(t));
- }
- h[e].tops = std::move(new_tops);
+ flat_set<u32> new_tops;
+ for (u32 t : h[e].tops) {
+ DEBUG_PRINTF("vertex %zu has top %u\n", h[v].index, t);
+ new_tops.insert(top_mapping.at(t));
+ }
+ h[e].tops = std::move(new_tops);
}
}
static
bool setDistinctTops(NGHolder &h1, const NGHolder &h2,
map<u32, u32> &top_mapping) {
- flat_set<u32> tops1 = getTops(h1), tops2 = getTops(h2);
+ flat_set<u32> tops1 = getTops(h1), tops2 = getTops(h2);
DEBUG_PRINTF("before: h1 has %zu tops, h2 has %zu tops\n", tops1.size(),
tops2.size());
@@ -1738,7 +1738,7 @@ bool setDistinctRoseTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2,
}
for (auto v : verts1) {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
assert(!g[v].left.haig);
assert(!g[v].left.dfa);
for (const auto &e : in_edges_range(v, g)) {
@@ -1747,7 +1747,7 @@ bool setDistinctRoseTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2,
assert(contains(top_mapping, t));
g[e].rose_top = top_mapping[t];
DEBUG_PRINTF("edge (%zu,%zu) went from top %u to %u\n",
- g[source(e, g)].index, g[target(e, g)].index, t,
+ g[source(e, g)].index, g[target(e, g)].index, t,
top_mapping[t]);
}
}
@@ -1768,7 +1768,7 @@ bool setDistinctSuffixTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2,
}
for (auto v : verts1) {
- DEBUG_PRINTF("vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("vertex %zu\n", g[v].index);
u32 t = g[v].suffix.top;
assert(contains(top_mapping, t));
g[v].suffix.top = top_mapping[t];
@@ -1796,7 +1796,7 @@ void mergeNfaLeftfixes(RoseBuildImpl &tbi, LeftfixBouquet &roses) {
// We track the number of accelerable states for each graph in a map and
// only recompute them when the graph is modified.
- unordered_map<left_id, u32> accel_count;
+ unordered_map<left_id, u32> accel_count;
for (const auto &rose : roses) {
assert(rose.graph()->kind == NFA_INFIX);
accel_count[rose] = estimatedAccelStates(tbi, *rose.graph());
@@ -1965,109 +1965,109 @@ void mergeSmallLeftfixes(RoseBuildImpl &tbi) {
}
}
-static
-void mergeCastleChunk(RoseBuildImpl &build, vector<left_id> &cands,
- insertion_ordered_map<left_id, vector<RoseVertex>> &eng_verts) {
- /* caller must have already ensured that candidates have the same reach */
- RoseGraph &g = build.g;
- DEBUG_PRINTF("%zu castle leftfix merge candidates\n", cands.size());
-
- for (auto it = cands.begin(); it != cands.end(); ++it) {
- left_id &cand_1 = *it;
- vector<RoseVertex> &verts_1 = eng_verts[cand_1];
- if (verts_1.empty()) {
- continue;
- }
-
- for (auto jt = next(it); jt != cands.end(); ++jt) {
- const left_id &cand_2 = *jt;
- vector<RoseVertex> &verts_2 = eng_verts[cand_2];
- if (verts_2.empty()) {
- continue;
- }
-
- assert(cand_1.castle()->reach() == cand_2.castle()->reach());
-
- if (!checkVerticesOkForLeftfixMerge(build, verts_1, verts_2)) {
- DEBUG_PRINTF("not mergeable\n");
- continue; // next cand_2
- }
-
- DEBUG_PRINTF("castle1=%p (size %zu)\n", cand_1.castle(),
- cand_1.castle()->repeats.size());
- DEBUG_PRINTF("castle2=%p (size %zu)\n", cand_2.castle(),
- cand_2.castle()->repeats.size());
-
- map<u32, u32> top_map;
- if (!mergeCastle(*cand_1.castle(), *cand_2.castle(), top_map)) {
- DEBUG_PRINTF("couldn't merge\n");
- continue; // next cand_2
- }
-
- // Update castle2's roses to point to castle1 now.
- shared_ptr<CastleProto> winner = g[verts_1.front()].left.castle;
- for (auto v : verts_2) {
- assert(g[v].left.castle.get() == cand_2.castle());
- g[v].left.castle = winner;
- for (const auto &e : in_edges_range(v, g)) {
- g[e].rose_top = top_map.at(g[e].rose_top);
- }
- }
-
- insert(&verts_1, verts_1.end(), verts_2);
- verts_2.clear();
- }
- }
-}
-
-/**
- * Merges castles with the same reach together regardless of where in the rose
- * graph they are. Note: there is no requirement for the castles to have common
- * parent or target vertices.
- *
- * There are no heuristics for reducing block mode merges as castle speed
- * mainly depends on the reach being scanned.
- */
-void mergeCastleLeftfixes(RoseBuildImpl &build) {
+static
+void mergeCastleChunk(RoseBuildImpl &build, vector<left_id> &cands,
+ insertion_ordered_map<left_id, vector<RoseVertex>> &eng_verts) {
+ /* caller must have already ensured that candidates have the same reach */
+ RoseGraph &g = build.g;
+ DEBUG_PRINTF("%zu castle leftfix merge candidates\n", cands.size());
+
+ for (auto it = cands.begin(); it != cands.end(); ++it) {
+ left_id &cand_1 = *it;
+ vector<RoseVertex> &verts_1 = eng_verts[cand_1];
+ if (verts_1.empty()) {
+ continue;
+ }
+
+ for (auto jt = next(it); jt != cands.end(); ++jt) {
+ const left_id &cand_2 = *jt;
+ vector<RoseVertex> &verts_2 = eng_verts[cand_2];
+ if (verts_2.empty()) {
+ continue;
+ }
+
+ assert(cand_1.castle()->reach() == cand_2.castle()->reach());
+
+ if (!checkVerticesOkForLeftfixMerge(build, verts_1, verts_2)) {
+ DEBUG_PRINTF("not mergeable\n");
+ continue; // next cand_2
+ }
+
+ DEBUG_PRINTF("castle1=%p (size %zu)\n", cand_1.castle(),
+ cand_1.castle()->repeats.size());
+ DEBUG_PRINTF("castle2=%p (size %zu)\n", cand_2.castle(),
+ cand_2.castle()->repeats.size());
+
+ map<u32, u32> top_map;
+ if (!mergeCastle(*cand_1.castle(), *cand_2.castle(), top_map)) {
+ DEBUG_PRINTF("couldn't merge\n");
+ continue; // next cand_2
+ }
+
+ // Update castle2's roses to point to castle1 now.
+ shared_ptr<CastleProto> winner = g[verts_1.front()].left.castle;
+ for (auto v : verts_2) {
+ assert(g[v].left.castle.get() == cand_2.castle());
+ g[v].left.castle = winner;
+ for (const auto &e : in_edges_range(v, g)) {
+ g[e].rose_top = top_map.at(g[e].rose_top);
+ }
+ }
+
+ insert(&verts_1, verts_1.end(), verts_2);
+ verts_2.clear();
+ }
+ }
+}
+
+/**
+ * Merges castles with the same reach together regardless of where in the rose
+ * graph they are. Note: there is no requirement for the castles to have common
+ * parent or target vertices.
+ *
+ * There are no heuristics for reducing block mode merges as castle speed
+ * mainly depends on the reach being scanned.
+ */
+void mergeCastleLeftfixes(RoseBuildImpl &build) {
DEBUG_PRINTF("entry\n");
- if (!build.cc.grey.mergeRose || !build.cc.grey.roseMultiTopRoses
- || !build.cc.grey.allowCastle) {
+ if (!build.cc.grey.mergeRose || !build.cc.grey.roseMultiTopRoses
+ || !build.cc.grey.allowCastle) {
return;
}
- RoseGraph &g = build.g;
+ RoseGraph &g = build.g;
- insertion_ordered_map<left_id, vector<RoseVertex>> eng_verts;
+ insertion_ordered_map<left_id, vector<RoseVertex>> eng_verts;
for (auto v : vertices_range(g)) {
- if (!g[v].left.castle) {
+ if (!g[v].left.castle) {
continue;
}
- // Handle infixes only.
- if (build.isRootSuccessor(v)) {
+ // Handle infixes only.
+ if (build.isRootSuccessor(v)) {
continue;
}
- eng_verts[g[v].left].push_back(v);
- }
+ eng_verts[g[v].left].push_back(v);
+ }
- map<CharReach, vector<left_id>> by_reach;
- for (const auto &left : eng_verts | map_keys) {
- by_reach[left.castle()->reach()].push_back(left);
- }
+ map<CharReach, vector<left_id>> by_reach;
+ for (const auto &left : eng_verts | map_keys) {
+ by_reach[left.castle()->reach()].push_back(left);
+ }
- vector<vector<left_id>> chunks;
- for (auto &raw_group : by_reach | map_values) {
- chunk(move(raw_group), &chunks, MERGE_CASTLE_GROUP_SIZE_MAX);
+ vector<vector<left_id>> chunks;
+ for (auto &raw_group : by_reach | map_values) {
+ chunk(move(raw_group), &chunks, MERGE_CASTLE_GROUP_SIZE_MAX);
}
- by_reach.clear();
+ by_reach.clear();
- DEBUG_PRINTF("chunked castles into %zu groups\n", chunks.size());
+ DEBUG_PRINTF("chunked castles into %zu groups\n", chunks.size());
- for (auto &chunk : chunks) {
- mergeCastleChunk(build, chunk, eng_verts);
+ for (auto &chunk : chunks) {
+ mergeCastleChunk(build, chunk, eng_verts);
}
}
@@ -2081,7 +2081,7 @@ void mergeSuffixes(RoseBuildImpl &tbi, SuffixBouquet &suffixes,
// If this isn't an acyclic case, we track the number of accelerable states
// for each graph in a map and only recompute them when the graph is
// modified.
- unordered_map<suffix_id, u32> accel_count;
+ unordered_map<suffix_id, u32> accel_count;
if (!acyclic) {
for (const auto &suffix : suffixes) {
assert(suffix.graph() && suffix.graph()->kind == NFA_SUFFIX);
@@ -2093,11 +2093,11 @@ void mergeSuffixes(RoseBuildImpl &tbi, SuffixBouquet &suffixes,
suffix_id s1 = *it;
const deque<RoseVertex> &verts1 = suffixes.vertices(s1);
assert(s1.graph() && s1.graph()->kind == NFA_SUFFIX);
-
- // Caller should ensure that we don't propose merges of graphs that are
- // already too big.
- assert(num_vertices(*s1.graph()) < small_merge_max_vertices(tbi.cc));
-
+
+ // Caller should ensure that we don't propose merges of graphs that are
+ // already too big.
+ assert(num_vertices(*s1.graph()) < small_merge_max_vertices(tbi.cc));
+
deque<suffix_id> merged;
for (auto jt = next(it); jt != suffixes.end(); ++jt) {
suffix_id s2 = *jt;
@@ -2210,11 +2210,11 @@ void mergeAcyclicSuffixes(RoseBuildImpl &tbi) {
assert(!g[v].suffix.haig);
- if (num_vertices(*h) >= small_merge_max_vertices(tbi.cc)) {
+ if (num_vertices(*h) >= small_merge_max_vertices(tbi.cc)) {
continue;
}
- if (!isAcyclic(*h)) {
+ if (!isAcyclic(*h)) {
continue;
}
@@ -2327,8 +2327,8 @@ map<NGHolder *, NGHolder *> chunkedNfaMerge(RoseBuildImpl &build,
batch.push_back(*it);
assert((*it)->kind == NFA_OUTFIX);
if (batch.size() == MERGE_GROUP_SIZE_MAX || next(it) == ite) {
- auto batch_merged = mergeNfaCluster(batch, &build.rm, build.cc);
- insert(&merged, batch_merged);
+ auto batch_merged = mergeNfaCluster(batch, &build.rm, build.cc);
+ insert(&merged, batch_merged);
batch.clear();
}
}
@@ -2347,9 +2347,9 @@ void mergeOutfixNfas(RoseBuildImpl &tbi, vector<NGHolder *> &nfas) {
map<NGHolder *, size_t> nfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
- auto *holder = outfixes[i].holder();
- if (holder) {
- nfa_mapping[holder] = i;
+ auto *holder = outfixes[i].holder();
+ if (holder) {
+ nfa_mapping[holder] = i;
}
}
@@ -2413,7 +2413,7 @@ private:
template<class RawDfa, class MergeFunctor>
static
void pairwiseDfaMerge(vector<RawDfa *> &dfas,
- unordered_map<RawDfa *, size_t> &dfa_mapping,
+ unordered_map<RawDfa *, size_t> &dfa_mapping,
vector<OutfixInfo> &outfixes,
MergeFunctor merge_func) {
DEBUG_PRINTF("merging group of size %zu\n", dfas.size());
@@ -2441,7 +2441,7 @@ void pairwiseDfaMerge(vector<RawDfa *> &dfas,
RawDfa *dfa_ptr = rdfa.get();
dfa_mapping[dfa_ptr] = dfa_mapping[*it];
dfa_mapping.erase(*it);
- winner.proto = move(rdfa);
+ winner.proto = move(rdfa);
mergeOutfixInfo(winner, victim);
@@ -2455,7 +2455,7 @@ void pairwiseDfaMerge(vector<RawDfa *> &dfas,
template<class RawDfa, class MergeFunctor>
static
void chunkedDfaMerge(vector<RawDfa *> &dfas,
- unordered_map<RawDfa *, size_t> &dfa_mapping,
+ unordered_map<RawDfa *, size_t> &dfa_mapping,
vector<OutfixInfo> &outfixes,
MergeFunctor merge_func) {
DEBUG_PRINTF("begin merge of %zu dfas\n", dfas.size());
@@ -2489,11 +2489,11 @@ void mergeOutfixDfas(RoseBuildImpl &tbi, vector<raw_dfa *> &dfas) {
/* key is index into outfix array as iterators, etc may be invalidated by
* element addition. */
- unordered_map<raw_dfa *, size_t> dfa_mapping;
+ unordered_map<raw_dfa *, size_t> dfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
- auto *rdfa = outfixes[i].rdfa();
- if (rdfa) {
- dfa_mapping[rdfa] = i;
+ auto *rdfa = outfixes[i].rdfa();
+ if (rdfa) {
+ dfa_mapping[rdfa] = i;
}
}
@@ -2514,10 +2514,10 @@ void mergeOutfixCombo(RoseBuildImpl &tbi, const ReportManager &rm,
bool seen_dfa = false;
u32 nfa_count = 0;
for (const auto &outfix : tbi.outfixes) {
- if (outfix.holder()) {
+ if (outfix.holder()) {
DEBUG_PRINTF("nfa\n");
nfa_count++;
- } else if (outfix.rdfa()) {
+ } else if (outfix.rdfa()) {
DEBUG_PRINTF("dfa\n");
seen_dfa = true;
}
@@ -2533,32 +2533,32 @@ void mergeOutfixCombo(RoseBuildImpl &tbi, const ReportManager &rm,
/* key is index into outfix array as iterators, etc may be invalidated by
* element addition. */
size_t new_dfas = 0;
- unordered_map<raw_dfa *, size_t> dfa_mapping;
+ unordered_map<raw_dfa *, size_t> dfa_mapping;
vector<raw_dfa *> dfas;
for (auto it = tbi.outfixes.begin(); it != tbi.outfixes.end(); ++it) {
- auto &outfix = *it;
- assert(!outfix.is_dead());
-
- if (outfix.rdfa()) {
- auto *rdfa = outfix.rdfa();
- dfas.push_back(rdfa);
- dfa_mapping[rdfa] = it - tbi.outfixes.begin();
+ auto &outfix = *it;
+ assert(!outfix.is_dead());
+
+ if (outfix.rdfa()) {
+ auto *rdfa = outfix.rdfa();
+ dfas.push_back(rdfa);
+ dfa_mapping[rdfa] = it - tbi.outfixes.begin();
continue;
}
- if (!outfix.holder()) {
+ if (!outfix.holder()) {
continue;
}
- NGHolder *h = outfix.holder();
+ NGHolder *h = outfix.holder();
assert(h->kind == NFA_OUTFIX);
auto rdfa = buildMcClellan(*h, &rm, grey);
if (rdfa) {
// Transform this outfix into a DFA and add it to the merge set.
dfa_mapping[rdfa.get()] = it - tbi.outfixes.begin();
dfas.push_back(rdfa.get());
- outfix.proto = move(rdfa);
+ outfix.proto = move(rdfa);
new_dfas++;
}
}
@@ -2584,11 +2584,11 @@ void mergeOutfixHaigs(RoseBuildImpl &tbi, vector<raw_som_dfa *> &dfas,
vector<OutfixInfo> &outfixes = tbi.outfixes;
- unordered_map<raw_som_dfa *, size_t> dfa_mapping;
+ unordered_map<raw_som_dfa *, size_t> dfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
- auto *haig = outfixes[i].haig();
- if (haig) {
- dfa_mapping[haig] = i;
+ auto *haig = outfixes[i].haig();
+ if (haig) {
+ dfa_mapping[haig] = i;
}
}
@@ -2613,13 +2613,13 @@ void mergeOutfixes(RoseBuildImpl &tbi) {
vector<raw_dfa *> dfas;
vector<raw_som_dfa *> som_dfas;
- for (auto &outfix : tbi.outfixes) {
- if (outfix.rdfa()) {
- dfas.push_back(outfix.rdfa());
- } else if (outfix.holder()) {
- nfas.push_back(outfix.holder());
- } else if (outfix.haig()) {
- som_dfas.push_back(outfix.haig());
+ for (auto &outfix : tbi.outfixes) {
+ if (outfix.rdfa()) {
+ dfas.push_back(outfix.rdfa());
+ } else if (outfix.holder()) {
+ nfas.push_back(outfix.holder());
+ } else if (outfix.haig()) {
+ som_dfas.push_back(outfix.haig());
}
}
@@ -2644,7 +2644,7 @@ u32 allowedSquashDistance(const CharReach &cr, u32 min_width,
/* TODO: inspect further back in the pattern */
for (u32 lit_id : g[tv].literals) {
- const rose_literal_id &lit = tbi.literals.at(lit_id);
+ const rose_literal_id &lit = tbi.literals.at(lit_id);
if (lit.delay) {
return 0; /* TODO: better */
}
@@ -2724,7 +2724,7 @@ void mergePuffixes(RoseBuildImpl &tbi) {
u32 squashDistance =
allowedSquashDistance(repeat.reach, repeat.bounds.min, tbi, v);
- Report ir = makeMpvTrigger(event, squashDistance);
+ Report ir = makeMpvTrigger(event, squashDistance);
ReportID id = tbi.rm.getInternalId(ir);
DEBUG_PRINTF("puffette event q%u t%u\n", queue, event);
@@ -2736,8 +2736,8 @@ void mergePuffixes(RoseBuildImpl &tbi) {
static
void updateCastleSuffix(RoseGraph &g, const shared_ptr<CastleProto> &m,
u32 top, const vector<RoseVertex> &verts) {
- DEBUG_PRINTF("merged in as top %u of %p, updating %zu vertices\n", top,
- m.get(), verts.size());
+ DEBUG_PRINTF("merged in as top %u of %p, updating %zu vertices\n", top,
+ m.get(), verts.size());
for (auto v : verts) {
assert(g[v].suffix.castle);
@@ -2747,56 +2747,56 @@ void updateCastleSuffix(RoseGraph &g, const shared_ptr<CastleProto> &m,
}
static
-void mergeCastleSuffixChunk(RoseGraph &g, const vector<CastleProto *> &castles,
- const unordered_map<CastleProto *, vector<RoseVertex>> &eng_verts) {
+void mergeCastleSuffixChunk(RoseGraph &g, const vector<CastleProto *> &castles,
+ const unordered_map<CastleProto *, vector<RoseVertex>> &eng_verts) {
if (castles.size() <= 1) {
return;
}
- DEBUG_PRINTF("merging reach %s, %zu elements\n",
- describeClass(castles[0]->reach()).c_str(), castles.size());
+ DEBUG_PRINTF("merging reach %s, %zu elements\n",
+ describeClass(castles[0]->reach()).c_str(), castles.size());
- CastleProto *m = nullptr;
+ CastleProto *m = nullptr;
- for (CastleProto *c : castles) {
+ for (CastleProto *c : castles) {
assert(c->repeats.size() == 1); // Not yet merged.
- assert(g[eng_verts.at(c).front()].suffix.castle.get() == c);
- if (!m) {
- m = c;
+ assert(g[eng_verts.at(c).front()].suffix.castle.get() == c);
+ if (!m) {
+ m = c;
continue;
}
- u32 top = m->merge(c->repeats[0]);
- if (top == CastleProto::max_occupancy) {
+ u32 top = m->merge(c->repeats[0]);
+ if (top == CastleProto::max_occupancy) {
// No room left to merge into 'm'. This one becomes the new 'm'.
DEBUG_PRINTF("next mergee\n");
m = c;
- continue;
+ continue;
}
- updateCastleSuffix(g, g[eng_verts.at(m).front()].suffix.castle, top,
- eng_verts.at(c));
- DEBUG_PRINTF("added to %p, top %u\n", m, top);
+ updateCastleSuffix(g, g[eng_verts.at(m).front()].suffix.castle, top,
+ eng_verts.at(c));
+ DEBUG_PRINTF("added to %p, top %u\n", m, top);
}
}
-void mergeCastleSuffixes(RoseBuildImpl &build) {
+void mergeCastleSuffixes(RoseBuildImpl &build) {
DEBUG_PRINTF("entry\n");
- if (!build.cc.grey.allowCastle || !build.cc.grey.mergeSuffixes) {
+ if (!build.cc.grey.allowCastle || !build.cc.grey.mergeSuffixes) {
return;
}
- unordered_map<CastleProto *, vector<RoseVertex>> eng_verts;
- map<CharReach, vector<CastleProto *>> by_reach;
+ unordered_map<CastleProto *, vector<RoseVertex>> eng_verts;
+ map<CharReach, vector<CastleProto *>> by_reach;
- RoseGraph &g = build.g;
+ RoseGraph &g = build.g;
for (auto v : vertices_range(g)) {
if (!g[v].suffix.castle) {
continue;
}
- CastleProto *c = g[v].suffix.castle.get();
+ CastleProto *c = g[v].suffix.castle.get();
if (c->repeats.size() != 1) {
// This code assumes it's the only place merging is being done.
@@ -2804,14 +2804,14 @@ void mergeCastleSuffixes(RoseBuildImpl &build) {
continue;
}
- if (!contains(eng_verts, c)) {
+ if (!contains(eng_verts, c)) {
by_reach[c->reach()].push_back(c);
}
- eng_verts[c].push_back(v);
+ eng_verts[c].push_back(v);
}
- for (auto &chunk : by_reach | map_values) {
- mergeCastleSuffixChunk(g, chunk, eng_verts);
+ for (auto &chunk : by_reach | map_values) {
+ mergeCastleSuffixChunk(g, chunk, eng_verts);
}
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_merge.h b/contrib/libs/hyperscan/src/rose/rose_build_merge.h
index 216cf50bcc2..6de6c7786a7 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_merge.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_merge.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,8 +27,8 @@
*/
/** \file
- * \brief Rose Build: functions for reducing the number of engines in a Rose
- * graph through merging or deduplicating engines.
+ * \brief Rose Build: functions for reducing the number of engines in a Rose
+ * graph through merging or deduplicating engines.
*/
#ifndef ROSE_BUILD_MERGE_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_misc.cpp b/contrib/libs/hyperscan/src/rose/rose_build_misc.cpp
index 81cfda7ca5a..0b0e689c994 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_misc.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_misc.cpp
@@ -26,17 +26,17 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "rose_build_misc.h"
+#include "rose_build_misc.h"
#include "rose_build_impl.h"
-#include "rose_build_resources.h"
-#include "hwlm/hwlm_literal.h"
+#include "rose_build_resources.h"
+#include "hwlm/hwlm_literal.h"
#include "nfa/castlecompile.h"
#include "nfa/goughcompile.h"
#include "nfa/mcclellancompile_util.h"
#include "nfa/nfa_api.h"
#include "nfa/rdfa.h"
-#include "nfa/tamaramacompile.h"
+#include "nfa/tamaramacompile.h"
#include "nfagraph/ng_holder.h"
#include "nfagraph/ng_limex.h"
#include "nfagraph/ng_reports.h"
@@ -67,9 +67,9 @@ namespace ue2 {
// just to get it out of the header
RoseBuild::~RoseBuild() { }
-RoseBuildImpl::RoseBuildImpl(ReportManager &rm_in,
- SomSlotManager &ssm_in,
- SmallWriteBuild &smwr_in,
+RoseBuildImpl::RoseBuildImpl(ReportManager &rm_in,
+ SomSlotManager &ssm_in,
+ SmallWriteBuild &smwr_in,
const CompileContext &cc_in,
const BoundaryReports &boundary_in)
: cc(cc_in),
@@ -82,7 +82,7 @@ RoseBuildImpl::RoseBuildImpl(ReportManager &rm_in,
max_rose_anchored_floating_overlap(0),
rm(rm_in),
ssm(ssm_in),
- smwr(smwr_in),
+ smwr(smwr_in),
boundary(boundary_in),
next_nfa_report(0) {
// add root vertices to graph
@@ -154,12 +154,12 @@ bool isInTable(const RoseBuildImpl &tbi, RoseVertex v,
// All literals for a given vertex will be in the same table, so we need
// only inspect the first one.
- const auto lit_table = tbi.literals.at(*lit_ids.begin()).table;
+ const auto lit_table = tbi.literals.at(*lit_ids.begin()).table;
// Verify that all literals for this vertex are in the same table.
- assert(all_of_in(lit_ids, [&](u32 lit_id) {
- return tbi.literals.at(lit_id).table == lit_table;
- }));
+ assert(all_of_in(lit_ids, [&](u32 lit_id) {
+ return tbi.literals.at(lit_id).table == lit_table;
+ }));
return lit_table == table;
}
@@ -186,7 +186,7 @@ bool RoseBuildImpl::hasLiteralInTable(RoseVertex v,
bool RoseBuildImpl::hasNoFloatingRoots() const {
for (auto v : adjacent_vertices_range(root, g)) {
if (isFloating(v)) {
- DEBUG_PRINTF("direct floating root %zu\n", g[v].index);
+ DEBUG_PRINTF("direct floating root %zu\n", g[v].index);
return false;
}
}
@@ -194,7 +194,7 @@ bool RoseBuildImpl::hasNoFloatingRoots() const {
/* need to check if the anchored_root has any literals which are too deep */
for (auto v : adjacent_vertices_range(anchored_root, g)) {
if (isFloating(v)) {
- DEBUG_PRINTF("indirect floating root %zu\n", g[v].index);
+ DEBUG_PRINTF("indirect floating root %zu\n", g[v].index);
return false;
}
}
@@ -209,7 +209,7 @@ size_t RoseBuildImpl::maxLiteralLen(RoseVertex v) const {
size_t maxlen = 0;
for (const auto &lit_id : lit_ids) {
- maxlen = max(maxlen, literals.at(lit_id).elength());
+ maxlen = max(maxlen, literals.at(lit_id).elength());
}
return maxlen;
@@ -222,19 +222,19 @@ size_t RoseBuildImpl::minLiteralLen(RoseVertex v) const {
size_t minlen = ROSE_BOUND_INF;
for (const auto &lit_id : lit_ids) {
- minlen = min(minlen, literals.at(lit_id).elength());
+ minlen = min(minlen, literals.at(lit_id).elength());
}
return minlen;
}
// RoseBuild factory
-unique_ptr<RoseBuild> makeRoseBuilder(ReportManager &rm,
- SomSlotManager &ssm,
- SmallWriteBuild &smwr,
+unique_ptr<RoseBuild> makeRoseBuilder(ReportManager &rm,
+ SomSlotManager &ssm,
+ SmallWriteBuild &smwr,
const CompileContext &cc,
const BoundaryReports &boundary) {
- return ue2::make_unique<RoseBuildImpl>(rm, ssm, smwr, cc, boundary);
+ return ue2::make_unique<RoseBuildImpl>(rm, ssm, smwr, cc, boundary);
}
bool roseIsPureLiteral(const RoseEngine *t) {
@@ -285,30 +285,30 @@ size_t maxOverlap(const rose_literal_id &a, const rose_literal_id &b) {
static
const rose_literal_id &getOverlapLiteral(const RoseBuildImpl &tbi,
u32 literal_id) {
- auto it = tbi.anchoredLitSuffix.find(literal_id);
+ auto it = tbi.anchoredLitSuffix.find(literal_id);
if (it != tbi.anchoredLitSuffix.end()) {
return it->second;
}
- return tbi.literals.at(literal_id);
-}
-
-ue2_literal findNonOverlappingTail(const set<ue2_literal> &lits,
- const ue2_literal &s) {
- size_t max_overlap = 0;
-
- for (const auto &lit : lits) {
- size_t overlap = lit != s ? maxStringOverlap(lit, s)
- : maxStringSelfOverlap(s);
- max_overlap = max(max_overlap, overlap);
- }
-
- /* find the tail that doesn't overlap */
- ue2_literal tail = s.substr(max_overlap);
- DEBUG_PRINTF("%zu overlap, tail: '%s'\n", max_overlap,
- dumpString(tail).c_str());
- return tail;
-}
-
+ return tbi.literals.at(literal_id);
+}
+
+ue2_literal findNonOverlappingTail(const set<ue2_literal> &lits,
+ const ue2_literal &s) {
+ size_t max_overlap = 0;
+
+ for (const auto &lit : lits) {
+ size_t overlap = lit != s ? maxStringOverlap(lit, s)
+ : maxStringSelfOverlap(s);
+ max_overlap = max(max_overlap, overlap);
+ }
+
+ /* find the tail that doesn't overlap */
+ ue2_literal tail = s.substr(max_overlap);
+ DEBUG_PRINTF("%zu overlap, tail: '%s'\n", max_overlap,
+ dumpString(tail).c_str());
+ return tail;
+}
+
size_t RoseBuildImpl::maxLiteralOverlap(RoseVertex u, RoseVertex v) const {
size_t overlap = 0;
for (auto u_lit_id : g[u].literals) {
@@ -324,14 +324,14 @@ size_t RoseBuildImpl::maxLiteralOverlap(RoseVertex u, RoseVertex v) const {
void RoseBuildImpl::removeVertices(const vector<RoseVertex> &dead) {
for (auto v : dead) {
assert(!isAnyStart(v));
- DEBUG_PRINTF("removing vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("removing vertex %zu\n", g[v].index);
for (auto lit_id : g[v].literals) {
literal_info[lit_id].vertices.erase(v);
}
- clear_vertex(v, g);
+ clear_vertex(v, g);
remove_vertex(v, g);
}
- renumber_vertices(g);
+ renumber_vertices(g);
}
// Find the maximum bound on the edges to this vertex's successors ignoring
@@ -365,14 +365,14 @@ u32 RoseBuildImpl::calcSuccMaxBound(RoseVertex u) const {
u32 RoseBuildImpl::getLiteralId(const ue2_literal &s, u32 delay,
rose_literal_table table) {
- DEBUG_PRINTF("getting id for %s in table %d\n", dumpString(s).c_str(),
- table);
+ DEBUG_PRINTF("getting id for %s in table %d\n", dumpString(s).c_str(),
+ table);
assert(table != ROSE_ANCHORED);
rose_literal_id key(s, table, delay);
- auto m = literals.insert(key);
- u32 id = m.first;
- bool inserted = m.second;
+ auto m = literals.insert(key);
+ u32 id = m.first;
+ bool inserted = m.second;
if (inserted) {
literal_info.push_back(rose_literal_info());
@@ -452,17 +452,17 @@ rose_literal_id::rose_literal_id(const ue2_literal &s_in,
u32 RoseBuildImpl::getLiteralId(const ue2_literal &s, const vector<u8> &msk,
const vector<u8> &cmp, u32 delay,
rose_literal_table table) {
- DEBUG_PRINTF("getting id for %s in table %d\n", dumpString(s).c_str(),
- table);
+ DEBUG_PRINTF("getting id for %s in table %d\n", dumpString(s).c_str(),
+ table);
assert(table != ROSE_ANCHORED);
rose_literal_id key(s, msk, cmp, table, delay);
/* ue2_literals are always uppercased if nocase and must have an
* alpha char */
- auto m = literals.insert(key);
- u32 id = m.first;
- bool inserted = m.second;
+ auto m = literals.insert(key);
+ u32 id = m.first;
+ bool inserted = m.second;
if (inserted) {
literal_info.push_back(rose_literal_info());
@@ -481,12 +481,12 @@ u32 RoseBuildImpl::getLiteralId(const ue2_literal &s, const vector<u8> &msk,
u32 RoseBuildImpl::getNewLiteralId() {
rose_literal_id key(ue2_literal(), ROSE_ANCHORED, 0);
- u32 numLiterals = verify_u32(literals.size());
+ u32 numLiterals = verify_u32(literals.size());
key.distinctiveness = numLiterals;
- auto m = literals.insert(key);
- assert(m.second);
- u32 id = m.first;
+ auto m = literals.insert(key);
+ assert(m.second);
+ u32 id = m.first;
literal_info.push_back(rose_literal_info());
assert(literal_info.size() == id + 1);
@@ -504,15 +504,15 @@ bool operator<(const RoseEdgeProps &a, const RoseEdgeProps &b) {
}
#ifndef NDEBUG
-bool roseHasTops(const RoseBuildImpl &build, RoseVertex v) {
- const RoseGraph &g = build.g;
+bool roseHasTops(const RoseBuildImpl &build, RoseVertex v) {
+ const RoseGraph &g = build.g;
assert(g[v].left);
set<u32> graph_tops;
- if (!build.isRootSuccessor(v)) {
- for (const auto &e : in_edges_range(v, g)) {
- graph_tops.insert(g[e].rose_top);
- }
+ if (!build.isRootSuccessor(v)) {
+ for (const auto &e : in_edges_range(v, g)) {
+ graph_tops.insert(g[e].rose_top);
+ }
}
return is_subset_of(graph_tops, all_tops(g[v].left));
@@ -527,40 +527,40 @@ u32 OutfixInfo::get_queue(QueueIndexFactory &qif) {
return queue;
}
-namespace {
-class OutfixAllReports : public boost::static_visitor<set<ReportID>> {
-public:
- set<ReportID> operator()(const boost::blank &) const {
- return set<ReportID>();
+namespace {
+class OutfixAllReports : public boost::static_visitor<set<ReportID>> {
+public:
+ set<ReportID> operator()(const boost::blank &) const {
+ return set<ReportID>();
}
-
- template<class T>
- set<ReportID> operator()(const unique_ptr<T> &x) const {
- return all_reports(*x);
+
+ template<class T>
+ set<ReportID> operator()(const unique_ptr<T> &x) const {
+ return all_reports(*x);
}
- set<ReportID> operator()(const MpvProto &mpv) const {
- set<ReportID> reports;
- for (const auto &puff : mpv.puffettes) {
- reports.insert(puff.report);
- }
- for (const auto &puff : mpv.triggered_puffettes) {
- reports.insert(puff.report);
- }
- return reports;
+ set<ReportID> operator()(const MpvProto &mpv) const {
+ set<ReportID> reports;
+ for (const auto &puff : mpv.puffettes) {
+ reports.insert(puff.report);
+ }
+ for (const auto &puff : mpv.triggered_puffettes) {
+ reports.insert(puff.report);
+ }
+ return reports;
}
-};
-}
+};
+}
-set<ReportID> all_reports(const OutfixInfo &outfix) {
- auto reports = boost::apply_visitor(OutfixAllReports(), outfix.proto);
+set<ReportID> all_reports(const OutfixInfo &outfix) {
+ auto reports = boost::apply_visitor(OutfixAllReports(), outfix.proto);
assert(!reports.empty());
return reports;
}
bool RoseSuffixInfo::operator==(const RoseSuffixInfo &b) const {
return top == b.top && graph == b.graph && castle == b.castle &&
- rdfa == b.rdfa && haig == b.haig && tamarama == b.tamarama;
+ rdfa == b.rdfa && haig == b.haig && tamarama == b.tamarama;
}
bool RoseSuffixInfo::operator<(const RoseSuffixInfo &b) const {
@@ -570,15 +570,15 @@ bool RoseSuffixInfo::operator<(const RoseSuffixInfo &b) const {
ORDER_CHECK(castle);
ORDER_CHECK(haig);
ORDER_CHECK(rdfa);
- ORDER_CHECK(tamarama);
+ ORDER_CHECK(tamarama);
assert(a.dfa_min_width == b.dfa_min_width);
assert(a.dfa_max_width == b.dfa_max_width);
return false;
}
-size_t RoseSuffixInfo::hash() const {
- return hash_all(top, graph, castle, rdfa, haig, tamarama);
-}
+size_t RoseSuffixInfo::hash() const {
+ return hash_all(top, graph, castle, rdfa, haig, tamarama);
+}
void RoseSuffixInfo::reset(void) {
top = 0;
@@ -586,16 +586,16 @@ void RoseSuffixInfo::reset(void) {
castle.reset();
rdfa.reset();
haig.reset();
- tamarama.reset();
- dfa_min_width = depth(0);
+ tamarama.reset();
+ dfa_min_width = depth(0);
dfa_max_width = depth::infinity();
}
std::set<ReportID> all_reports(const suffix_id &s) {
assert(s.graph() || s.castle() || s.haig() || s.dfa());
- if (s.tamarama()) {
- return all_reports(*s.tamarama());
- } else if (s.graph()) {
+ if (s.tamarama()) {
+ return all_reports(*s.tamarama());
+ } else if (s.graph()) {
return all_reports(*s.graph());
} else if (s.castle()) {
return all_reports(*s.castle());
@@ -680,9 +680,9 @@ bool has_non_eod_accepts(const suffix_id &s) {
set<u32> all_tops(const suffix_id &s) {
assert(s.graph() || s.castle() || s.haig() || s.dfa());
if (s.graph()) {
- flat_set<u32> tops = getTops(*s.graph());
- assert(!tops.empty());
- return {tops.begin(), tops.end()};
+ flat_set<u32> tops = getTops(*s.graph());
+ assert(!tops.empty());
+ return {tops.begin(), tops.end()};
}
if (s.castle()) {
@@ -694,7 +694,7 @@ set<u32> all_tops(const suffix_id &s) {
}
size_t suffix_id::hash() const {
- return hash_all(g, c, d, h, t);
+ return hash_all(g, c, d, h, t);
}
bool isAnchored(const left_id &r) {
@@ -702,13 +702,13 @@ bool isAnchored(const left_id &r) {
if (r.graph()) {
return isAnchored(*r.graph());
}
- if (r.dfa()) {
- return r.dfa()->start_anchored == DEAD_STATE;
- }
- if (r.haig()) {
- return r.haig()->start_anchored == DEAD_STATE;
- }
-
+ if (r.dfa()) {
+ return r.dfa()->start_anchored == DEAD_STATE;
+ }
+ if (r.haig()) {
+ return r.haig()->start_anchored == DEAD_STATE;
+ }
+
// All other types are explicitly anchored.
return true;
}
@@ -738,8 +738,8 @@ depth findMaxWidth(const left_id &r) {
set<u32> all_tops(const left_id &r) {
assert(r.graph() || r.castle() || r.haig() || r.dfa());
if (r.graph()) {
- flat_set<u32> tops = getTops(*r.graph());
- return {tops.begin(), tops.end()};
+ flat_set<u32> tops = getTops(*r.graph());
+ return {tops.begin(), tops.end()};
}
if (r.castle()) {
@@ -750,25 +750,25 @@ set<u32> all_tops(const left_id &r) {
return {0};
}
-set<u32> all_reports(const left_id &left) {
- assert(left.graph() || left.castle() || left.haig() || left.dfa());
- if (left.graph()) {
- return all_reports(*left.graph());
- } else if (left.castle()) {
- return all_reports(*left.castle());
- } else if (left.dfa()) {
- return all_reports(*left.dfa());
- } else {
- return all_reports(*left.haig());
- }
-}
-
+set<u32> all_reports(const left_id &left) {
+ assert(left.graph() || left.castle() || left.haig() || left.dfa());
+ if (left.graph()) {
+ return all_reports(*left.graph());
+ } else if (left.castle()) {
+ return all_reports(*left.castle());
+ } else if (left.dfa()) {
+ return all_reports(*left.dfa());
+ } else {
+ return all_reports(*left.haig());
+ }
+}
+
u32 num_tops(const left_id &r) {
return all_tops(r).size();
}
size_t left_id::hash() const {
- return hash_all(g, c, d, h);
+ return hash_all(g, c, d, h);
}
u64a findMaxOffset(const set<ReportID> &reports, const ReportManager &rm) {
@@ -785,19 +785,19 @@ u64a findMaxOffset(const set<ReportID> &reports, const ReportManager &rm) {
return maxOffset;
}
-size_t LeftEngInfo::hash() const {
- return hash_all(graph, castle, dfa, haig, tamarama, lag, leftfix_report);
-}
-
+size_t LeftEngInfo::hash() const {
+ return hash_all(graph, castle, dfa, haig, tamarama, lag, leftfix_report);
+}
+
void LeftEngInfo::reset(void) {
graph.reset();
castle.reset();
dfa.reset();
haig.reset();
- tamarama.reset();
+ tamarama.reset();
lag = 0;
leftfix_report = MO_INVALID_IDX;
- dfa_min_width = depth(0);
+ dfa_min_width = depth(0);
dfa_max_width = depth::infinity();
}
@@ -809,16 +809,16 @@ LeftEngInfo::operator bool() const {
return graph || castle || dfa || haig;
}
-u32 roseQuality(const RoseResources &res, const RoseEngine *t) {
+u32 roseQuality(const RoseResources &res, const RoseEngine *t) {
/* Rose is low quality if the atable is a Mcclellan 16 or has multiple DFAs
*/
- if (res.has_anchored) {
- if (res.has_anchored_multiple) {
+ if (res.has_anchored) {
+ if (res.has_anchored_multiple) {
DEBUG_PRINTF("multiple atable engines\n");
return 0;
}
- if (res.has_anchored_large) {
+ if (res.has_anchored_large) {
DEBUG_PRINTF("m16 atable engine\n");
return 0;
}
@@ -827,16 +827,16 @@ u32 roseQuality(const RoseResources &res, const RoseEngine *t) {
/* if we always run multiple engines then we are slow */
u32 always_run = 0;
- if (res.has_anchored) {
+ if (res.has_anchored) {
always_run++;
}
- if (t->eagerIterOffset) {
- /* eager prefixes are always run */
- always_run++;
- }
-
- if (res.has_floating) {
+ if (t->eagerIterOffset) {
+ /* eager prefixes are always run */
+ always_run++;
+ }
+
+ if (res.has_floating) {
/* TODO: ignore conditional ftables, or ftables beyond smwr region */
always_run++;
}
@@ -875,59 +875,59 @@ u32 roseQuality(const RoseResources &res, const RoseEngine *t) {
return 1;
}
-u32 findMinOffset(const RoseBuildImpl &build, u32 lit_id) {
- const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
- assert(!lit_vertices.empty());
-
- u32 min_offset = UINT32_MAX;
- for (const auto &v : lit_vertices) {
- min_offset = min(min_offset, build.g[v].min_offset);
- }
-
- return min_offset;
-}
-
-u32 findMaxOffset(const RoseBuildImpl &build, u32 lit_id) {
- const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
- assert(!lit_vertices.empty());
-
- u32 max_offset = 0;
- for (const auto &v : lit_vertices) {
- max_offset = max(max_offset, build.g[v].max_offset);
- }
-
- return max_offset;
-}
-
-bool canEagerlyReportAtEod(const RoseBuildImpl &build, const RoseEdge &e) {
- const auto &g = build.g;
- const auto v = target(e, g);
-
- if (!build.g[v].eod_accept) {
- return false;
- }
-
- // If there's a graph between us and EOD, we shouldn't be eager.
- if (build.g[v].left) {
- return false;
- }
-
- // Must be exactly at EOD.
- if (g[e].minBound != 0 || g[e].maxBound != 0) {
- return false;
- }
-
- // In streaming mode, we can only eagerly report EOD for literals in the
- // EOD-anchored table, as that's the only time we actually know where EOD
- // is. In block mode, we always have this information.
- const auto u = source(e, g);
- if (build.cc.streaming && !build.isInETable(u)) {
- return false;
- }
-
- return true;
-}
-
+u32 findMinOffset(const RoseBuildImpl &build, u32 lit_id) {
+ const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
+ assert(!lit_vertices.empty());
+
+ u32 min_offset = UINT32_MAX;
+ for (const auto &v : lit_vertices) {
+ min_offset = min(min_offset, build.g[v].min_offset);
+ }
+
+ return min_offset;
+}
+
+u32 findMaxOffset(const RoseBuildImpl &build, u32 lit_id) {
+ const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
+ assert(!lit_vertices.empty());
+
+ u32 max_offset = 0;
+ for (const auto &v : lit_vertices) {
+ max_offset = max(max_offset, build.g[v].max_offset);
+ }
+
+ return max_offset;
+}
+
+bool canEagerlyReportAtEod(const RoseBuildImpl &build, const RoseEdge &e) {
+ const auto &g = build.g;
+ const auto v = target(e, g);
+
+ if (!build.g[v].eod_accept) {
+ return false;
+ }
+
+ // If there's a graph between us and EOD, we shouldn't be eager.
+ if (build.g[v].left) {
+ return false;
+ }
+
+ // Must be exactly at EOD.
+ if (g[e].minBound != 0 || g[e].maxBound != 0) {
+ return false;
+ }
+
+ // In streaming mode, we can only eagerly report EOD for literals in the
+ // EOD-anchored table, as that's the only time we actually know where EOD
+ // is. In block mode, we always have this information.
+ const auto u = source(e, g);
+ if (build.cc.streaming && !build.isInETable(u)) {
+ return false;
+ }
+
+ return true;
+}
+
#ifndef NDEBUG
/** \brief Returns true if all the graphs (NFA, DFA, Haig, etc) in this Rose
* graph are implementable. */
@@ -937,7 +937,7 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) {
// First, check the Rose leftfixes.
for (auto v : vertices_range(g)) {
- DEBUG_PRINTF("leftfix: check vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("leftfix: check vertex %zu\n", g[v].index);
if (g[v].left.castle) {
DEBUG_PRINTF("castle ok\n");
@@ -953,10 +953,10 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) {
}
if (g[v].left.graph) {
assert(g[v].left.graph->kind
- == (tbi.isRootSuccessor(v) ? NFA_PREFIX : NFA_INFIX));
+ == (tbi.isRootSuccessor(v) ? NFA_PREFIX : NFA_INFIX));
if (!isImplementableNFA(*g[v].left.graph, nullptr, tbi.cc)) {
- DEBUG_PRINTF("nfa prefix %zu failed (%zu vertices)\n",
- g[v].index, num_vertices(*g[v].left.graph));
+ DEBUG_PRINTF("nfa prefix %zu failed (%zu vertices)\n",
+ g[v].index, num_vertices(*g[v].left.graph));
return false;
}
}
@@ -965,7 +965,7 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) {
// Suffix graphs.
for (auto v : vertices_range(g)) {
- DEBUG_PRINTF("suffix: check vertex %zu\n", g[v].index);
+ DEBUG_PRINTF("suffix: check vertex %zu\n", g[v].index);
const RoseSuffixInfo &suffix = g[v].suffix;
if (suffix.castle) {
@@ -983,8 +983,8 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) {
if (suffix.graph) {
assert(suffix.graph->kind == NFA_SUFFIX);
if (!isImplementableNFA(*suffix.graph, &tbi.rm, tbi.cc)) {
- DEBUG_PRINTF("nfa suffix %zu failed (%zu vertices)\n",
- g[v].index, num_vertices(*suffix.graph));
+ DEBUG_PRINTF("nfa suffix %zu failed (%zu vertices)\n",
+ g[v].index, num_vertices(*suffix.graph));
return false;
}
}
@@ -992,53 +992,53 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) {
return true;
}
-
+
/**
* \brief True if there is an engine with a top that is not triggered by a
* vertex in the Rose graph. This is a consistency check used in assertions.
*/
-bool hasOrphanedTops(const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
-
+bool hasOrphanedTops(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+
unordered_map<left_id, set<u32>> leftfixes;
- unordered_map<suffix_id, set<u32>> suffixes;
-
- for (auto v : vertices_range(g)) {
- if (g[v].left) {
+ unordered_map<suffix_id, set<u32>> suffixes;
+
+ for (auto v : vertices_range(g)) {
+ if (g[v].left) {
set<u32> &tops = leftfixes[g[v].left];
- if (!build.isRootSuccessor(v)) {
- // Tops for infixes come from the in-edges.
- for (const auto &e : in_edges_range(v, g)) {
- tops.insert(g[e].rose_top);
- }
- }
- }
- if (g[v].suffix) {
- suffixes[g[v].suffix].insert(g[v].suffix.top);
- }
- }
-
+ if (!build.isRootSuccessor(v)) {
+ // Tops for infixes come from the in-edges.
+ for (const auto &e : in_edges_range(v, g)) {
+ tops.insert(g[e].rose_top);
+ }
+ }
+ }
+ if (g[v].suffix) {
+ suffixes[g[v].suffix].insert(g[v].suffix.top);
+ }
+ }
+
for (const auto &e : leftfixes) {
- if (all_tops(e.first) != e.second) {
- DEBUG_PRINTF("rose tops (%s) don't match rose graph (%s)\n",
- as_string_list(all_tops(e.first)).c_str(),
- as_string_list(e.second).c_str());
- return true;
- }
- }
-
- for (const auto &e : suffixes) {
- if (all_tops(e.first) != e.second) {
- DEBUG_PRINTF("suffix tops (%s) don't match rose graph (%s)\n",
- as_string_list(all_tops(e.first)).c_str(),
- as_string_list(e.second).c_str());
- return true;
- }
- }
-
- return false;
-}
-
+ if (all_tops(e.first) != e.second) {
+ DEBUG_PRINTF("rose tops (%s) don't match rose graph (%s)\n",
+ as_string_list(all_tops(e.first)).c_str(),
+ as_string_list(e.second).c_str());
+ return true;
+ }
+ }
+
+ for (const auto &e : suffixes) {
+ if (all_tops(e.first) != e.second) {
+ DEBUG_PRINTF("suffix tops (%s) don't match rose graph (%s)\n",
+ as_string_list(all_tops(e.first)).c_str(),
+ as_string_list(e.second).c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
#endif // NDEBUG
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_misc.h b/contrib/libs/hyperscan/src/rose/rose_build_misc.h
index 203feba871d..f34b8292006 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_misc.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_misc.h
@@ -1,46 +1,46 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_MISC_H
-#define ROSE_BUILD_MISC_H
-
-#include "ue2common.h"
-
-struct RoseEngine;
-
-namespace ue2 {
-
-struct RoseResources;
-
-/* used by heuristics to determine the small write engine. High numbers are
- * intended to indicate a lightweight rose. */
-u32 roseQuality(const RoseResources &res, const RoseEngine *rose);
-
-}
-
-#endif
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_MISC_H
+#define ROSE_BUILD_MISC_H
+
+#include "ue2common.h"
+
+struct RoseEngine;
+
+namespace ue2 {
+
+struct RoseResources;
+
+/* used by heuristics to determine the small write engine. High numbers are
+ * intended to indicate a lightweight rose. */
+u32 roseQuality(const RoseResources &res, const RoseEngine *rose);
+
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_program.cpp b/contrib/libs/hyperscan/src/rose/rose_build_program.cpp
index 4a6e7506ca1..7d1d7ecbb58 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_program.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_program.cpp
@@ -1,318 +1,318 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "rose_build_program.h"
-
-#include "rose_build_engine_blob.h"
-#include "rose_build_instructions.h"
-#include "rose_build_lookaround.h"
-#include "rose_build_resources.h"
-#include "nfa/nfa_api_queue.h"
-#include "nfa/nfa_build_util.h"
-#include "nfa/tamaramacompile.h"
-#include "nfagraph/ng_util.h"
-#include "util/charreach_util.h"
-#include "util/container.h"
-#include "util/compile_context.h"
-#include "util/compile_error.h"
-#include "util/report_manager.h"
-#include "util/unordered.h"
-#include "util/verify_types.h"
-
-#include <boost/range/adaptor/map.hpp>
-
-#include <algorithm>
-#include <cstring>
-
-using namespace std;
-using boost::adaptors::map_values;
-using boost::adaptors::map_keys;
-
-namespace ue2 {
-
-engine_info::engine_info(const NFA *nfa, bool trans)
- : type((NFAEngineType)nfa->type), accepts_eod(nfaAcceptsEod(nfa)),
- stream_size(nfa->streamStateSize),
- scratch_size(nfa->scratchStateSize),
- scratch_align(state_alignment(*nfa)),
- transient(trans) {
- assert(scratch_align);
-}
-
-left_build_info::left_build_info(u32 q, u32 l, u32 t, rose_group sm,
- const std::vector<u8> &stops, u32 max_ql,
- u8 cm_count, const CharReach &cm_cr)
- : queue(q), lag(l), transient(t), squash_mask(sm), stopAlphabet(stops),
- max_queuelen(max_ql), countingMiracleCount(cm_count),
- countingMiracleReach(cm_cr) {
-}
-
-left_build_info::left_build_info(const vector<vector<LookEntry>> &looks)
- : has_lookaround(true), lookaround(looks) {
-}
-
-using OffsetMap = RoseInstruction::OffsetMap;
-
-static
-OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) {
- OffsetMap offset_map;
- u32 offset = 0;
- for (const auto &ri : program) {
- offset = ROUNDUP_N(offset, ROSE_INSTR_MIN_ALIGN);
- DEBUG_PRINTF("instr %p (opcode %d) -> offset %u\n", ri.get(),
- ri->code(), offset);
- assert(!contains(offset_map, ri.get()));
- offset_map.emplace(ri.get(), offset);
- offset += ri->byte_length();
- }
- *total_len = offset;
- return offset_map;
-}
-
-RoseProgram::RoseProgram() {
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "rose_build_program.h"
+
+#include "rose_build_engine_blob.h"
+#include "rose_build_instructions.h"
+#include "rose_build_lookaround.h"
+#include "rose_build_resources.h"
+#include "nfa/nfa_api_queue.h"
+#include "nfa/nfa_build_util.h"
+#include "nfa/tamaramacompile.h"
+#include "nfagraph/ng_util.h"
+#include "util/charreach_util.h"
+#include "util/container.h"
+#include "util/compile_context.h"
+#include "util/compile_error.h"
+#include "util/report_manager.h"
+#include "util/unordered.h"
+#include "util/verify_types.h"
+
+#include <boost/range/adaptor/map.hpp>
+
+#include <algorithm>
+#include <cstring>
+
+using namespace std;
+using boost::adaptors::map_values;
+using boost::adaptors::map_keys;
+
+namespace ue2 {
+
+engine_info::engine_info(const NFA *nfa, bool trans)
+ : type((NFAEngineType)nfa->type), accepts_eod(nfaAcceptsEod(nfa)),
+ stream_size(nfa->streamStateSize),
+ scratch_size(nfa->scratchStateSize),
+ scratch_align(state_alignment(*nfa)),
+ transient(trans) {
+ assert(scratch_align);
+}
+
+left_build_info::left_build_info(u32 q, u32 l, u32 t, rose_group sm,
+ const std::vector<u8> &stops, u32 max_ql,
+ u8 cm_count, const CharReach &cm_cr)
+ : queue(q), lag(l), transient(t), squash_mask(sm), stopAlphabet(stops),
+ max_queuelen(max_ql), countingMiracleCount(cm_count),
+ countingMiracleReach(cm_cr) {
+}
+
+left_build_info::left_build_info(const vector<vector<LookEntry>> &looks)
+ : has_lookaround(true), lookaround(looks) {
+}
+
+using OffsetMap = RoseInstruction::OffsetMap;
+
+static
+OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) {
+ OffsetMap offset_map;
+ u32 offset = 0;
+ for (const auto &ri : program) {
+ offset = ROUNDUP_N(offset, ROSE_INSTR_MIN_ALIGN);
+ DEBUG_PRINTF("instr %p (opcode %d) -> offset %u\n", ri.get(),
+ ri->code(), offset);
+ assert(!contains(offset_map, ri.get()));
+ offset_map.emplace(ri.get(), offset);
+ offset += ri->byte_length();
+ }
+ *total_len = offset;
+ return offset_map;
+}
+
+RoseProgram::RoseProgram() {
prog.push_back(std::make_unique<RoseInstrEnd>());
-}
-
-RoseProgram::~RoseProgram() = default;
-
-RoseProgram::RoseProgram(RoseProgram &&) = default;
-RoseProgram &RoseProgram::operator=(RoseProgram &&) = default;
-
-bool RoseProgram::empty() const {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
- // Empty if we only have one element, the END instruction.
- return next(prog.begin()) == prog.end();
-}
-
-const RoseInstruction *RoseProgram::end_instruction() const {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- return prog.back().get();
-}
-
-void RoseProgram::update_targets(RoseProgram::iterator it,
- RoseProgram::iterator it_end,
- const RoseInstruction *old_target,
- const RoseInstruction *new_target) {
- assert(old_target && new_target && old_target != new_target);
- for (; it != it_end; ++it) {
- unique_ptr<RoseInstruction> &ri = *it;
- assert(ri);
- ri->update_target(old_target, new_target);
- }
-}
-
-RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
- unique_ptr<RoseInstruction> ri) {
- assert(!prog.empty());
- assert(it != end());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- return prog.insert(it, move(ri));
-}
-
-RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
- RoseProgram &&block) {
- assert(!prog.empty());
- assert(it != end());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- if (block.empty()) {
- return it;
- }
-
- const RoseInstruction *end_ptr = block.end_instruction();
- assert(end_ptr->code() == ROSE_INSTR_END);
- block.prog.pop_back();
-
- const RoseInstruction *new_target = it->get();
- update_targets(block.prog.begin(), block.prog.end(), end_ptr, new_target);
-
- // Workaround: container insert() for ranges doesn't return an iterator
- // in the version of the STL distributed with gcc 4.8.
- auto dist = distance(prog.begin(), it);
- prog.insert(it, make_move_iterator(block.prog.begin()),
- make_move_iterator(block.prog.end()));
- it = prog.begin();
- advance(it, dist);
- return it;
-}
-
-RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first,
- RoseProgram::iterator last) {
- return prog.erase(first, last);
-}
-
-void RoseProgram::add_before_end(std::unique_ptr<RoseInstruction> ri) {
- assert(!prog.empty());
- insert(std::prev(prog.end()), std::move(ri));
-}
-
-void RoseProgram::add_before_end(RoseProgram &&block) {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- if (block.empty()) {
- return;
- }
-
- insert(prev(prog.end()), move(block));
-}
-
-void RoseProgram::add_block(RoseProgram &&block) {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- if (block.empty()) {
- return;
- }
-
- // Replace pointers to the current END with pointers to the first
- // instruction in the new sequence.
- const RoseInstruction *end_ptr = end_instruction();
- prog.pop_back();
- update_targets(prog.begin(), prog.end(), end_ptr,
- block.prog.front().get());
- prog.insert(prog.end(), make_move_iterator(block.prog.begin()),
- make_move_iterator(block.prog.end()));
-}
-
-bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
- const RoseProgram &program) {
- u32 total_len = 0;
- const auto offset_map = makeOffsetMap(program, &total_len);
- DEBUG_PRINTF("%zu instructions, len %u\n", program.size(), total_len);
-
- auto bytecode = make_zeroed_bytecode_ptr<char>(total_len,
- ROSE_INSTR_MIN_ALIGN);
- char *ptr = bytecode.get();
-
- for (const auto &ri : program) {
- assert(contains(offset_map, ri.get()));
- const u32 offset = offset_map.at(ri.get());
- ri->write(ptr + offset, blob, offset_map);
- }
-
- return bytecode;
-}
-
-size_t RoseProgramHash::operator()(const RoseProgram &program) const {
- size_t v = 0;
- for (const auto &ri : program) {
- assert(ri);
- hash_combine(v, ri->hash());
- }
- return v;
-}
-
-bool RoseProgramEquivalence::operator()(const RoseProgram &prog1,
- const RoseProgram &prog2) const {
- if (prog1.size() != prog2.size()) {
- return false;
- }
-
- u32 len_1 = 0, len_2 = 0;
- const auto offset_map_1 = makeOffsetMap(prog1, &len_1);
- const auto offset_map_2 = makeOffsetMap(prog2, &len_2);
-
- if (len_1 != len_2) {
- return false;
- }
-
- auto is_equiv = [&](const unique_ptr<RoseInstruction> &a,
- const unique_ptr<RoseInstruction> &b) {
- assert(a && b);
- return a->equiv(*b, offset_map_1, offset_map_2);
- };
-
- return std::equal(prog1.begin(), prog1.end(), prog2.begin(), is_equiv);
-}
-
-/* Removes any CHECK_HANDLED instructions from the given program */
-static
-void stripCheckHandledInstruction(RoseProgram &prog) {
- for (auto it = prog.begin(); it != prog.end();) {
- auto ins = dynamic_cast<const RoseInstrCheckNotHandled *>(it->get());
- if (!ins) {
- ++it;
- continue;
- }
-
- auto next_it = next(it);
- assert(next_it != prog.end()); /* there should always be an end ins */
- auto next_ins = next_it->get();
-
- /* update all earlier instructions which point to ins to instead point
- * to the next instruction. Only need to look at earlier as we only ever
- * jump forward. */
- RoseProgram::update_targets(prog.begin(), it, ins, next_ins);
-
- /* remove check handled instruction */
- it = prog.erase(it, next_it);
- }
-}
-
-
+}
+
+RoseProgram::~RoseProgram() = default;
+
+RoseProgram::RoseProgram(RoseProgram &&) = default;
+RoseProgram &RoseProgram::operator=(RoseProgram &&) = default;
+
+bool RoseProgram::empty() const {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+ // Empty if we only have one element, the END instruction.
+ return next(prog.begin()) == prog.end();
+}
+
+const RoseInstruction *RoseProgram::end_instruction() const {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+
+ return prog.back().get();
+}
+
+void RoseProgram::update_targets(RoseProgram::iterator it,
+ RoseProgram::iterator it_end,
+ const RoseInstruction *old_target,
+ const RoseInstruction *new_target) {
+ assert(old_target && new_target && old_target != new_target);
+ for (; it != it_end; ++it) {
+ unique_ptr<RoseInstruction> &ri = *it;
+ assert(ri);
+ ri->update_target(old_target, new_target);
+ }
+}
+
+RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
+ unique_ptr<RoseInstruction> ri) {
+ assert(!prog.empty());
+ assert(it != end());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+
+ return prog.insert(it, move(ri));
+}
+
+RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
+ RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(it != end());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+
+ if (block.empty()) {
+ return it;
+ }
+
+ const RoseInstruction *end_ptr = block.end_instruction();
+ assert(end_ptr->code() == ROSE_INSTR_END);
+ block.prog.pop_back();
+
+ const RoseInstruction *new_target = it->get();
+ update_targets(block.prog.begin(), block.prog.end(), end_ptr, new_target);
+
+ // Workaround: container insert() for ranges doesn't return an iterator
+ // in the version of the STL distributed with gcc 4.8.
+ auto dist = distance(prog.begin(), it);
+ prog.insert(it, make_move_iterator(block.prog.begin()),
+ make_move_iterator(block.prog.end()));
+ it = prog.begin();
+ advance(it, dist);
+ return it;
+}
+
+RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first,
+ RoseProgram::iterator last) {
+ return prog.erase(first, last);
+}
+
+void RoseProgram::add_before_end(std::unique_ptr<RoseInstruction> ri) {
+ assert(!prog.empty());
+ insert(std::prev(prog.end()), std::move(ri));
+}
+
+void RoseProgram::add_before_end(RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+
+ if (block.empty()) {
+ return;
+ }
+
+ insert(prev(prog.end()), move(block));
+}
+
+void RoseProgram::add_block(RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+
+ if (block.empty()) {
+ return;
+ }
+
+ // Replace pointers to the current END with pointers to the first
+ // instruction in the new sequence.
+ const RoseInstruction *end_ptr = end_instruction();
+ prog.pop_back();
+ update_targets(prog.begin(), prog.end(), end_ptr,
+ block.prog.front().get());
+ prog.insert(prog.end(), make_move_iterator(block.prog.begin()),
+ make_move_iterator(block.prog.end()));
+}
+
+bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
+ const RoseProgram &program) {
+ u32 total_len = 0;
+ const auto offset_map = makeOffsetMap(program, &total_len);
+ DEBUG_PRINTF("%zu instructions, len %u\n", program.size(), total_len);
+
+ auto bytecode = make_zeroed_bytecode_ptr<char>(total_len,
+ ROSE_INSTR_MIN_ALIGN);
+ char *ptr = bytecode.get();
+
+ for (const auto &ri : program) {
+ assert(contains(offset_map, ri.get()));
+ const u32 offset = offset_map.at(ri.get());
+ ri->write(ptr + offset, blob, offset_map);
+ }
+
+ return bytecode;
+}
+
+size_t RoseProgramHash::operator()(const RoseProgram &program) const {
+ size_t v = 0;
+ for (const auto &ri : program) {
+ assert(ri);
+ hash_combine(v, ri->hash());
+ }
+ return v;
+}
+
+bool RoseProgramEquivalence::operator()(const RoseProgram &prog1,
+ const RoseProgram &prog2) const {
+ if (prog1.size() != prog2.size()) {
+ return false;
+ }
+
+ u32 len_1 = 0, len_2 = 0;
+ const auto offset_map_1 = makeOffsetMap(prog1, &len_1);
+ const auto offset_map_2 = makeOffsetMap(prog2, &len_2);
+
+ if (len_1 != len_2) {
+ return false;
+ }
+
+ auto is_equiv = [&](const unique_ptr<RoseInstruction> &a,
+ const unique_ptr<RoseInstruction> &b) {
+ assert(a && b);
+ return a->equiv(*b, offset_map_1, offset_map_2);
+ };
+
+ return std::equal(prog1.begin(), prog1.end(), prog2.begin(), is_equiv);
+}
+
+/* Removes any CHECK_HANDLED instructions from the given program */
+static
+void stripCheckHandledInstruction(RoseProgram &prog) {
+ for (auto it = prog.begin(); it != prog.end();) {
+ auto ins = dynamic_cast<const RoseInstrCheckNotHandled *>(it->get());
+ if (!ins) {
+ ++it;
+ continue;
+ }
+
+ auto next_it = next(it);
+ assert(next_it != prog.end()); /* there should always be an end ins */
+ auto next_ins = next_it->get();
+
+ /* update all earlier instructions which point to ins to instead point
+ * to the next instruction. Only need to look at earlier as we only ever
+ * jump forward. */
+ RoseProgram::update_targets(prog.begin(), it, ins, next_ins);
+
+ /* remove check handled instruction */
+ it = prog.erase(it, next_it);
+ }
+}
+
+
/** Returns true if the program may read the interpreter's work_done flag */
-static
-bool reads_work_done_flag(const RoseProgram &prog) {
- for (const auto &ri : prog) {
- if (dynamic_cast<const RoseInstrSquashGroups *>(ri.get())) {
- return true;
- }
- }
- return false;
-}
-
-void addEnginesEodProgram(u32 eodNfaIterOffset, RoseProgram &program) {
- if (!eodNfaIterOffset) {
- return;
- }
-
- RoseProgram block;
+static
+bool reads_work_done_flag(const RoseProgram &prog) {
+ for (const auto &ri : prog) {
+ if (dynamic_cast<const RoseInstrSquashGroups *>(ri.get())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void addEnginesEodProgram(u32 eodNfaIterOffset, RoseProgram &program) {
+ if (!eodNfaIterOffset) {
+ return;
+ }
+
+ RoseProgram block;
block.add_before_end(std::make_unique<RoseInstrEnginesEod>(eodNfaIterOffset));
- program.add_block(move(block));
-}
-
-void addSuffixesEodProgram(RoseProgram &program) {
- RoseProgram block;
+ program.add_block(move(block));
+}
+
+void addSuffixesEodProgram(RoseProgram &program) {
+ RoseProgram block;
block.add_before_end(std::make_unique<RoseInstrSuffixesEod>());
- program.add_block(move(block));
-}
-
-void addMatcherEodProgram(RoseProgram &program) {
- RoseProgram block;
+ program.add_block(move(block));
+}
+
+void addMatcherEodProgram(RoseProgram &program) {
+ RoseProgram block;
block.add_before_end(std::make_unique<RoseInstrMatcherEod>());
- program.add_block(move(block));
-}
-
+ program.add_block(move(block));
+}
+
void addFlushCombinationProgram(RoseProgram &program) {
program.add_before_end(std::make_unique<RoseInstrFlushCombination>());
}
@@ -321,190 +321,190 @@ void addLastFlushCombinationProgram(RoseProgram &program) {
program.add_before_end(std::make_unique<RoseInstrLastFlushCombination>());
}
-static
-void makeRoleCheckLeftfix(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- RoseVertex v, RoseProgram &program) {
- auto it = leftfix_info.find(v);
- if (it == end(leftfix_info)) {
- return;
- }
- const left_build_info &lni = it->second;
- if (lni.has_lookaround) {
- return; // Leftfix completely implemented by lookaround.
- }
-
- assert(!build.cc.streaming ||
- build.g[v].left.lag <= MAX_STORED_LEFTFIX_LAG);
-
- bool is_prefix = build.isRootSuccessor(v);
- const auto *end_inst = program.end_instruction();
-
- unique_ptr<RoseInstruction> ri;
- if (is_prefix) {
- ri = std::make_unique<RoseInstrCheckPrefix>(lni.queue, build.g[v].left.lag,
- build.g[v].left.leftfix_report,
- end_inst);
- } else {
- ri = std::make_unique<RoseInstrCheckInfix>(lni.queue, build.g[v].left.lag,
- build.g[v].left.leftfix_report,
- end_inst);
- }
- program.add_before_end(move(ri));
-}
-
-static
-void makeAnchoredLiteralDelay(const RoseBuildImpl &build,
- const ProgramBuild &prog_build, u32 lit_id,
- RoseProgram &program) {
- // Only relevant for literals in the anchored table.
- const rose_literal_id &lit = build.literals.at(lit_id);
- if (lit.table != ROSE_ANCHORED) {
- return;
- }
-
- // If this literal match cannot occur after floatingMinLiteralMatchOffset,
- // we do not need this check.
- bool all_too_early = true;
- rose_group groups = 0;
-
- const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
- for (RoseVertex v : lit_vertices) {
- if (build.g[v].max_offset > prog_build.floatingMinLiteralMatchOffset) {
- all_too_early = false;
- }
- groups |= build.g[v].groups;
- }
-
- if (all_too_early) {
- return;
- }
-
- assert(contains(prog_build.anchored_programs, lit_id));
- u32 anch_id = prog_build.anchored_programs.at(lit_id);
-
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrAnchoredDelay>(groups, anch_id, end_inst);
- program.add_before_end(move(ri));
-}
-
-static
-void makeDedupe(const ReportManager &rm, const Report &report,
- RoseProgram &program) {
- const auto *end_inst = program.end_instruction();
- auto ri =
- std::make_unique<RoseInstrDedupe>(report.quashSom, rm.getDkey(report),
- report.offsetAdjust, end_inst);
- program.add_before_end(move(ri));
-}
-
-static
-void makeDedupeSom(const ReportManager &rm, const Report &report,
- RoseProgram &program) {
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrDedupeSom>(report.quashSom,
- rm.getDkey(report),
- report.offsetAdjust, end_inst);
- program.add_before_end(move(ri));
-}
-
-static
-void makeCatchup(const ReportManager &rm, bool needs_catchup,
- const flat_set<ReportID> &reports, RoseProgram &program) {
- if (!needs_catchup) {
- return;
- }
-
- // Everything except the INTERNAL_ROSE_CHAIN report needs catchup to run
- // before reports are triggered.
-
- auto report_needs_catchup = [&](const ReportID &id) {
- const Report &report = rm.getReport(id);
- return report.type != INTERNAL_ROSE_CHAIN;
- };
-
- if (!any_of(begin(reports), end(reports), report_needs_catchup)) {
- DEBUG_PRINTF("none of the given reports needs catchup\n");
- return;
- }
-
+static
+void makeRoleCheckLeftfix(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ RoseVertex v, RoseProgram &program) {
+ auto it = leftfix_info.find(v);
+ if (it == end(leftfix_info)) {
+ return;
+ }
+ const left_build_info &lni = it->second;
+ if (lni.has_lookaround) {
+ return; // Leftfix completely implemented by lookaround.
+ }
+
+ assert(!build.cc.streaming ||
+ build.g[v].left.lag <= MAX_STORED_LEFTFIX_LAG);
+
+ bool is_prefix = build.isRootSuccessor(v);
+ const auto *end_inst = program.end_instruction();
+
+ unique_ptr<RoseInstruction> ri;
+ if (is_prefix) {
+ ri = std::make_unique<RoseInstrCheckPrefix>(lni.queue, build.g[v].left.lag,
+ build.g[v].left.leftfix_report,
+ end_inst);
+ } else {
+ ri = std::make_unique<RoseInstrCheckInfix>(lni.queue, build.g[v].left.lag,
+ build.g[v].left.leftfix_report,
+ end_inst);
+ }
+ program.add_before_end(move(ri));
+}
+
+static
+void makeAnchoredLiteralDelay(const RoseBuildImpl &build,
+ const ProgramBuild &prog_build, u32 lit_id,
+ RoseProgram &program) {
+ // Only relevant for literals in the anchored table.
+ const rose_literal_id &lit = build.literals.at(lit_id);
+ if (lit.table != ROSE_ANCHORED) {
+ return;
+ }
+
+ // If this literal match cannot occur after floatingMinLiteralMatchOffset,
+ // we do not need this check.
+ bool all_too_early = true;
+ rose_group groups = 0;
+
+ const auto &lit_vertices = build.literal_info.at(lit_id).vertices;
+ for (RoseVertex v : lit_vertices) {
+ if (build.g[v].max_offset > prog_build.floatingMinLiteralMatchOffset) {
+ all_too_early = false;
+ }
+ groups |= build.g[v].groups;
+ }
+
+ if (all_too_early) {
+ return;
+ }
+
+ assert(contains(prog_build.anchored_programs, lit_id));
+ u32 anch_id = prog_build.anchored_programs.at(lit_id);
+
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrAnchoredDelay>(groups, anch_id, end_inst);
+ program.add_before_end(move(ri));
+}
+
+static
+void makeDedupe(const ReportManager &rm, const Report &report,
+ RoseProgram &program) {
+ const auto *end_inst = program.end_instruction();
+ auto ri =
+ std::make_unique<RoseInstrDedupe>(report.quashSom, rm.getDkey(report),
+ report.offsetAdjust, end_inst);
+ program.add_before_end(move(ri));
+}
+
+static
+void makeDedupeSom(const ReportManager &rm, const Report &report,
+ RoseProgram &program) {
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrDedupeSom>(report.quashSom,
+ rm.getDkey(report),
+ report.offsetAdjust, end_inst);
+ program.add_before_end(move(ri));
+}
+
+static
+void makeCatchup(const ReportManager &rm, bool needs_catchup,
+ const flat_set<ReportID> &reports, RoseProgram &program) {
+ if (!needs_catchup) {
+ return;
+ }
+
+ // Everything except the INTERNAL_ROSE_CHAIN report needs catchup to run
+ // before reports are triggered.
+
+ auto report_needs_catchup = [&](const ReportID &id) {
+ const Report &report = rm.getReport(id);
+ return report.type != INTERNAL_ROSE_CHAIN;
+ };
+
+ if (!any_of(begin(reports), end(reports), report_needs_catchup)) {
+ DEBUG_PRINTF("none of the given reports needs catchup\n");
+ return;
+ }
+
program.add_before_end(std::make_unique<RoseInstrCatchUp>());
-}
-
-static
-void writeSomOperation(const Report &report, som_operation *op) {
- assert(op);
-
- memset(op, 0, sizeof(*op));
-
- switch (report.type) {
- case EXTERNAL_CALLBACK_SOM_REL:
- op->type = SOM_EXTERNAL_CALLBACK_REL;
- break;
- case INTERNAL_SOM_LOC_SET:
- op->type = SOM_INTERNAL_LOC_SET;
- break;
- case INTERNAL_SOM_LOC_SET_IF_UNSET:
- op->type = SOM_INTERNAL_LOC_SET_IF_UNSET;
- break;
- case INTERNAL_SOM_LOC_SET_IF_WRITABLE:
- op->type = SOM_INTERNAL_LOC_SET_IF_WRITABLE;
- break;
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
- op->type = SOM_INTERNAL_LOC_SET_REV_NFA;
- break;
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
- op->type = SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET;
- break;
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
- op->type = SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE;
- break;
- case INTERNAL_SOM_LOC_COPY:
- op->type = SOM_INTERNAL_LOC_COPY;
- break;
- case INTERNAL_SOM_LOC_COPY_IF_WRITABLE:
- op->type = SOM_INTERNAL_LOC_COPY_IF_WRITABLE;
- break;
- case INTERNAL_SOM_LOC_MAKE_WRITABLE:
- op->type = SOM_INTERNAL_LOC_MAKE_WRITABLE;
- break;
- case EXTERNAL_CALLBACK_SOM_STORED:
- op->type = SOM_EXTERNAL_CALLBACK_STORED;
- break;
- case EXTERNAL_CALLBACK_SOM_ABS:
- op->type = SOM_EXTERNAL_CALLBACK_ABS;
- break;
- case EXTERNAL_CALLBACK_SOM_REV_NFA:
- op->type = SOM_EXTERNAL_CALLBACK_REV_NFA;
- break;
- case INTERNAL_SOM_LOC_SET_FROM:
- op->type = SOM_INTERNAL_LOC_SET_FROM;
- break;
- case INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE:
- op->type = SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE;
- break;
- default:
- // This report doesn't correspond to a SOM operation.
- assert(0);
- throw CompileError("Unable to generate bytecode.");
- }
-
- op->onmatch = report.onmatch;
-
- switch (report.type) {
- case EXTERNAL_CALLBACK_SOM_REV_NFA:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
- op->aux.revNfaIndex = report.revNfaIndex;
- break;
- default:
- op->aux.somDistance = report.somDistance;
- break;
- }
-}
-
-static
+}
+
+static
+void writeSomOperation(const Report &report, som_operation *op) {
+ assert(op);
+
+ memset(op, 0, sizeof(*op));
+
+ switch (report.type) {
+ case EXTERNAL_CALLBACK_SOM_REL:
+ op->type = SOM_EXTERNAL_CALLBACK_REL;
+ break;
+ case INTERNAL_SOM_LOC_SET:
+ op->type = SOM_INTERNAL_LOC_SET;
+ break;
+ case INTERNAL_SOM_LOC_SET_IF_UNSET:
+ op->type = SOM_INTERNAL_LOC_SET_IF_UNSET;
+ break;
+ case INTERNAL_SOM_LOC_SET_IF_WRITABLE:
+ op->type = SOM_INTERNAL_LOC_SET_IF_WRITABLE;
+ break;
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
+ op->type = SOM_INTERNAL_LOC_SET_REV_NFA;
+ break;
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
+ op->type = SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET;
+ break;
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
+ op->type = SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE;
+ break;
+ case INTERNAL_SOM_LOC_COPY:
+ op->type = SOM_INTERNAL_LOC_COPY;
+ break;
+ case INTERNAL_SOM_LOC_COPY_IF_WRITABLE:
+ op->type = SOM_INTERNAL_LOC_COPY_IF_WRITABLE;
+ break;
+ case INTERNAL_SOM_LOC_MAKE_WRITABLE:
+ op->type = SOM_INTERNAL_LOC_MAKE_WRITABLE;
+ break;
+ case EXTERNAL_CALLBACK_SOM_STORED:
+ op->type = SOM_EXTERNAL_CALLBACK_STORED;
+ break;
+ case EXTERNAL_CALLBACK_SOM_ABS:
+ op->type = SOM_EXTERNAL_CALLBACK_ABS;
+ break;
+ case EXTERNAL_CALLBACK_SOM_REV_NFA:
+ op->type = SOM_EXTERNAL_CALLBACK_REV_NFA;
+ break;
+ case INTERNAL_SOM_LOC_SET_FROM:
+ op->type = SOM_INTERNAL_LOC_SET_FROM;
+ break;
+ case INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE:
+ op->type = SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE;
+ break;
+ default:
+ // This report doesn't correspond to a SOM operation.
+ assert(0);
+ throw CompileError("Unable to generate bytecode.");
+ }
+
+ op->onmatch = report.onmatch;
+
+ switch (report.type) {
+ case EXTERNAL_CALLBACK_SOM_REV_NFA:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
+ op->aux.revNfaIndex = report.revNfaIndex;
+ break;
+ default:
+ op->aux.somDistance = report.somDistance;
+ break;
+ }
+}
+
+static
void addLogicalSetRequired(const Report &report, ReportManager &rm,
RoseProgram &program) {
if (report.lkey == INVALID_LKEY) {
@@ -522,60 +522,60 @@ void addLogicalSetRequired(const Report &report, ReportManager &rm,
}
static
-void makeReport(const RoseBuildImpl &build, const ReportID id,
- const bool has_som, RoseProgram &program) {
- assert(id < build.rm.numReports());
- const Report &report = build.rm.getReport(id);
-
- RoseProgram report_block;
- const RoseInstruction *end_inst = report_block.end_instruction();
-
- // Handle min/max offset checks.
- if (report.minOffset > 0 || report.maxOffset < MAX_OFFSET) {
- auto ri = std::make_unique<RoseInstrCheckBounds>(report.minOffset,
- report.maxOffset, end_inst);
- report_block.add_before_end(move(ri));
- }
-
- // If this report has an exhaustion key, we can check it in the program
- // rather than waiting until we're in the callback adaptor.
- if (report.ekey != INVALID_EKEY) {
- auto ri = std::make_unique<RoseInstrCheckExhausted>(report.ekey, end_inst);
- report_block.add_before_end(move(ri));
- }
-
- // External SOM reports that aren't passthrough need their SOM value
- // calculated.
- if (isExternalSomReport(report) &&
- report.type != EXTERNAL_CALLBACK_SOM_PASS) {
- auto ri = std::make_unique<RoseInstrSomFromReport>();
- writeSomOperation(report, &ri->som);
- report_block.add_before_end(move(ri));
- }
-
- // Min length constraint.
- if (report.minLength > 0) {
- assert(build.hasSom);
- auto ri = std::make_unique<RoseInstrCheckMinLength>(
- report.offsetAdjust, report.minLength, end_inst);
- report_block.add_before_end(move(ri));
- }
-
- if (report.quashSom) {
+void makeReport(const RoseBuildImpl &build, const ReportID id,
+ const bool has_som, RoseProgram &program) {
+ assert(id < build.rm.numReports());
+ const Report &report = build.rm.getReport(id);
+
+ RoseProgram report_block;
+ const RoseInstruction *end_inst = report_block.end_instruction();
+
+ // Handle min/max offset checks.
+ if (report.minOffset > 0 || report.maxOffset < MAX_OFFSET) {
+ auto ri = std::make_unique<RoseInstrCheckBounds>(report.minOffset,
+ report.maxOffset, end_inst);
+ report_block.add_before_end(move(ri));
+ }
+
+ // If this report has an exhaustion key, we can check it in the program
+ // rather than waiting until we're in the callback adaptor.
+ if (report.ekey != INVALID_EKEY) {
+ auto ri = std::make_unique<RoseInstrCheckExhausted>(report.ekey, end_inst);
+ report_block.add_before_end(move(ri));
+ }
+
+ // External SOM reports that aren't passthrough need their SOM value
+ // calculated.
+ if (isExternalSomReport(report) &&
+ report.type != EXTERNAL_CALLBACK_SOM_PASS) {
+ auto ri = std::make_unique<RoseInstrSomFromReport>();
+ writeSomOperation(report, &ri->som);
+ report_block.add_before_end(move(ri));
+ }
+
+ // Min length constraint.
+ if (report.minLength > 0) {
+ assert(build.hasSom);
+ auto ri = std::make_unique<RoseInstrCheckMinLength>(
+ report.offsetAdjust, report.minLength, end_inst);
+ report_block.add_before_end(move(ri));
+ }
+
+ if (report.quashSom) {
report_block.add_before_end(std::make_unique<RoseInstrSomZero>());
- }
-
- switch (report.type) {
- case EXTERNAL_CALLBACK:
+ }
+
+ switch (report.type) {
+ case EXTERNAL_CALLBACK:
if (build.rm.numCkeys()) {
addFlushCombinationProgram(report_block);
}
- if (!has_som) {
- // Dedupe is only necessary if this report has a dkey, or if there
- // are SOM reports to catch up.
- bool needs_dedupe = build.rm.getDkey(report) != ~0U || build.hasSom;
- if (report.ekey == INVALID_EKEY) {
- if (needs_dedupe) {
+ if (!has_som) {
+ // Dedupe is only necessary if this report has a dkey, or if there
+ // are SOM reports to catch up.
+ bool needs_dedupe = build.rm.getDkey(report) != ~0U || build.hasSom;
+ if (report.ekey == INVALID_EKEY) {
+ if (needs_dedupe) {
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrDedupeAndReport>(
@@ -584,17 +584,17 @@ void makeReport(const RoseBuildImpl &build, const ReportID id,
} else {
makeDedupe(build.rm, report, report_block);
}
- } else {
+ } else {
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrReport>(
report.onmatch, report.offsetAdjust));
}
- }
- } else {
- if (needs_dedupe) {
- makeDedupe(build.rm, report, report_block);
- }
+ }
+ } else {
+ if (needs_dedupe) {
+ makeDedupe(build.rm, report, report_block);
+ }
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrReportExhaust>(
@@ -603,15 +603,15 @@ void makeReport(const RoseBuildImpl &build, const ReportID id,
report_block.add_before_end(
std::make_unique<RoseInstrSetExhaust>(report.ekey));
}
- }
- } else { // has_som
- makeDedupeSom(build.rm, report, report_block);
- if (report.ekey == INVALID_EKEY) {
+ }
+ } else { // has_som
+ makeDedupeSom(build.rm, report, report_block);
+ if (report.ekey == INVALID_EKEY) {
if (!report.quiet) {
report_block.add_before_end(std::make_unique<RoseInstrReportSom>(
report.onmatch, report.offsetAdjust));
}
- } else {
+ } else {
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrReportSomExhaust>(
@@ -620,53 +620,53 @@ void makeReport(const RoseBuildImpl &build, const ReportID id,
report_block.add_before_end(
std::make_unique<RoseInstrSetExhaust>(report.ekey));
}
- }
- }
+ }
+ }
addLogicalSetRequired(report, build.rm, report_block);
- break;
- case INTERNAL_SOM_LOC_SET:
- case INTERNAL_SOM_LOC_SET_IF_UNSET:
- case INTERNAL_SOM_LOC_SET_IF_WRITABLE:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
- case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
- case INTERNAL_SOM_LOC_COPY:
- case INTERNAL_SOM_LOC_COPY_IF_WRITABLE:
- case INTERNAL_SOM_LOC_MAKE_WRITABLE:
- case INTERNAL_SOM_LOC_SET_FROM:
- case INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE:
+ break;
+ case INTERNAL_SOM_LOC_SET:
+ case INTERNAL_SOM_LOC_SET_IF_UNSET:
+ case INTERNAL_SOM_LOC_SET_IF_WRITABLE:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
+ case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
+ case INTERNAL_SOM_LOC_COPY:
+ case INTERNAL_SOM_LOC_COPY_IF_WRITABLE:
+ case INTERNAL_SOM_LOC_MAKE_WRITABLE:
+ case INTERNAL_SOM_LOC_SET_FROM:
+ case INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE:
if (build.rm.numCkeys()) {
addFlushCombinationProgram(report_block);
}
- if (has_som) {
- auto ri = std::make_unique<RoseInstrReportSomAware>();
- writeSomOperation(report, &ri->som);
- report_block.add_before_end(move(ri));
- } else {
- auto ri = std::make_unique<RoseInstrReportSomInt>();
- writeSomOperation(report, &ri->som);
- report_block.add_before_end(move(ri));
- }
- break;
- case INTERNAL_ROSE_CHAIN: {
+ if (has_som) {
+ auto ri = std::make_unique<RoseInstrReportSomAware>();
+ writeSomOperation(report, &ri->som);
+ report_block.add_before_end(move(ri));
+ } else {
+ auto ri = std::make_unique<RoseInstrReportSomInt>();
+ writeSomOperation(report, &ri->som);
+ report_block.add_before_end(move(ri));
+ }
+ break;
+ case INTERNAL_ROSE_CHAIN: {
report_block.add_before_end(std::make_unique<RoseInstrReportChain>(
- report.onmatch, report.topSquashDistance));
- break;
- }
- case EXTERNAL_CALLBACK_SOM_REL:
- case EXTERNAL_CALLBACK_SOM_STORED:
- case EXTERNAL_CALLBACK_SOM_ABS:
- case EXTERNAL_CALLBACK_SOM_REV_NFA:
+ report.onmatch, report.topSquashDistance));
+ break;
+ }
+ case EXTERNAL_CALLBACK_SOM_REL:
+ case EXTERNAL_CALLBACK_SOM_STORED:
+ case EXTERNAL_CALLBACK_SOM_ABS:
+ case EXTERNAL_CALLBACK_SOM_REV_NFA:
if (build.rm.numCkeys()) {
addFlushCombinationProgram(report_block);
}
- makeDedupeSom(build.rm, report, report_block);
- if (report.ekey == INVALID_EKEY) {
+ makeDedupeSom(build.rm, report, report_block);
+ if (report.ekey == INVALID_EKEY) {
if (!report.quiet) {
report_block.add_before_end(std::make_unique<RoseInstrReportSom>(
report.onmatch, report.offsetAdjust));
}
- } else {
+ } else {
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrReportSomExhaust>(
@@ -675,20 +675,20 @@ void makeReport(const RoseBuildImpl &build, const ReportID id,
report_block.add_before_end(
std::make_unique<RoseInstrSetExhaust>(report.ekey));
}
- }
+ }
addLogicalSetRequired(report, build.rm, report_block);
- break;
- case EXTERNAL_CALLBACK_SOM_PASS:
+ break;
+ case EXTERNAL_CALLBACK_SOM_PASS:
if (build.rm.numCkeys()) {
addFlushCombinationProgram(report_block);
}
- makeDedupeSom(build.rm, report, report_block);
- if (report.ekey == INVALID_EKEY) {
+ makeDedupeSom(build.rm, report, report_block);
+ if (report.ekey == INVALID_EKEY) {
if (!report.quiet) {
report_block.add_before_end(std::make_unique<RoseInstrReportSom>(
report.onmatch, report.offsetAdjust));
}
- } else {
+ } else {
if (!report.quiet) {
report_block.add_before_end(
std::make_unique<RoseInstrReportSomExhaust>(
@@ -697,370 +697,370 @@ void makeReport(const RoseBuildImpl &build, const ReportID id,
report_block.add_before_end(
std::make_unique<RoseInstrSetExhaust>(report.ekey));
}
- }
+ }
addLogicalSetRequired(report, build.rm, report_block);
- break;
-
- default:
- assert(0);
- throw CompileError("Unable to generate bytecode.");
- }
-
- program.add_block(move(report_block));
-}
-
-static
-void makeRoleReports(const RoseBuildImpl &build,
- const std::map<RoseVertex, left_build_info> &leftfix_info,
- bool needs_catchup, RoseVertex v, RoseProgram &program) {
- const auto &g = build.g;
-
- bool report_som = false;
- if (g[v].left.tracksSom()) {
- /* we are a suffaig - need to update role to provide som to the
- * suffix. */
- assert(contains(leftfix_info, v));
- const left_build_info &lni = leftfix_info.at(v);
- program.add_before_end(
- std::make_unique<RoseInstrSomLeftfix>(lni.queue, g[v].left.lag));
- report_som = true;
- } else if (g[v].som_adjust) {
- program.add_before_end(
- std::make_unique<RoseInstrSomAdjust>(g[v].som_adjust));
- report_som = true;
- }
-
- makeCatchup(build.rm, needs_catchup, g[v].reports, program);
-
- RoseProgram report_block;
- for (ReportID id : g[v].reports) {
- makeReport(build, id, report_som, report_block);
- }
- program.add_before_end(move(report_block));
-}
-
-static
-void makeRoleSetState(const unordered_map<RoseVertex, u32> &roleStateIndices,
- RoseVertex v, RoseProgram &program) {
- // We only need this instruction if a state index has been assigned to this
- // vertex.
- auto it = roleStateIndices.find(v);
- if (it == end(roleStateIndices)) {
- return;
- }
+ break;
+
+ default:
+ assert(0);
+ throw CompileError("Unable to generate bytecode.");
+ }
+
+ program.add_block(move(report_block));
+}
+
+static
+void makeRoleReports(const RoseBuildImpl &build,
+ const std::map<RoseVertex, left_build_info> &leftfix_info,
+ bool needs_catchup, RoseVertex v, RoseProgram &program) {
+ const auto &g = build.g;
+
+ bool report_som = false;
+ if (g[v].left.tracksSom()) {
+ /* we are a suffaig - need to update role to provide som to the
+ * suffix. */
+ assert(contains(leftfix_info, v));
+ const left_build_info &lni = leftfix_info.at(v);
+ program.add_before_end(
+ std::make_unique<RoseInstrSomLeftfix>(lni.queue, g[v].left.lag));
+ report_som = true;
+ } else if (g[v].som_adjust) {
+ program.add_before_end(
+ std::make_unique<RoseInstrSomAdjust>(g[v].som_adjust));
+ report_som = true;
+ }
+
+ makeCatchup(build.rm, needs_catchup, g[v].reports, program);
+
+ RoseProgram report_block;
+ for (ReportID id : g[v].reports) {
+ makeReport(build, id, report_som, report_block);
+ }
+ program.add_before_end(move(report_block));
+}
+
+static
+void makeRoleSetState(const unordered_map<RoseVertex, u32> &roleStateIndices,
+ RoseVertex v, RoseProgram &program) {
+ // We only need this instruction if a state index has been assigned to this
+ // vertex.
+ auto it = roleStateIndices.find(v);
+ if (it == end(roleStateIndices)) {
+ return;
+ }
program.add_before_end(std::make_unique<RoseInstrSetState>(it->second));
-}
-
-static
-void makePushDelayedInstructions(const RoseLiteralMap &literals,
- ProgramBuild &prog_build,
- const flat_set<u32> &delayed_ids,
- RoseProgram &program) {
- vector<RoseInstrPushDelayed> delay_instructions;
-
- for (const auto &delayed_lit_id : delayed_ids) {
- DEBUG_PRINTF("delayed lit id %u\n", delayed_lit_id);
- assert(contains(prog_build.delay_programs, delayed_lit_id));
- u32 delay_id = prog_build.delay_programs.at(delayed_lit_id);
- const auto &delay_lit = literals.at(delayed_lit_id);
- delay_instructions.emplace_back(verify_u8(delay_lit.delay), delay_id);
- }
-
- sort_and_unique(delay_instructions, [](const RoseInstrPushDelayed &a,
- const RoseInstrPushDelayed &b) {
- return tie(a.delay, a.index) < tie(b.delay, b.index);
- });
-
- for (const auto &ri : delay_instructions) {
+}
+
+static
+void makePushDelayedInstructions(const RoseLiteralMap &literals,
+ ProgramBuild &prog_build,
+ const flat_set<u32> &delayed_ids,
+ RoseProgram &program) {
+ vector<RoseInstrPushDelayed> delay_instructions;
+
+ for (const auto &delayed_lit_id : delayed_ids) {
+ DEBUG_PRINTF("delayed lit id %u\n", delayed_lit_id);
+ assert(contains(prog_build.delay_programs, delayed_lit_id));
+ u32 delay_id = prog_build.delay_programs.at(delayed_lit_id);
+ const auto &delay_lit = literals.at(delayed_lit_id);
+ delay_instructions.emplace_back(verify_u8(delay_lit.delay), delay_id);
+ }
+
+ sort_and_unique(delay_instructions, [](const RoseInstrPushDelayed &a,
+ const RoseInstrPushDelayed &b) {
+ return tie(a.delay, a.index) < tie(b.delay, b.index);
+ });
+
+ for (const auto &ri : delay_instructions) {
program.add_before_end(std::make_unique<RoseInstrPushDelayed>(ri));
- }
-}
-
-static
-void makeCheckLiteralInstruction(const rose_literal_id &lit,
- size_t longLitLengthThreshold,
- RoseProgram &program,
- const CompileContext &cc) {
- assert(longLitLengthThreshold > 0);
-
- DEBUG_PRINTF("lit=%s, long lit threshold %zu\n", dumpString(lit.s).c_str(),
- longLitLengthThreshold);
-
- if (lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX) {
- DEBUG_PRINTF("lit short enough to not need confirm\n");
- return;
- }
-
- // Check resource limits as well.
- if (lit.s.length() > cc.grey.limitLiteralLength) {
- throw ResourceLimitError();
- }
-
- if (lit.s.length() <= longLitLengthThreshold) {
- DEBUG_PRINTF("is a medium-length literal\n");
- const auto *end_inst = program.end_instruction();
- unique_ptr<RoseInstruction> ri;
- if (lit.s.any_nocase()) {
- ri = std::make_unique<RoseInstrCheckMedLitNocase>(lit.s.get_string(),
- end_inst);
- } else {
- ri = std::make_unique<RoseInstrCheckMedLit>(lit.s.get_string(),
- end_inst);
- }
- program.add_before_end(move(ri));
- return;
- }
-
- // Long literal support should only really be used for the floating table
- // in streaming mode.
- assert(lit.table == ROSE_FLOATING && cc.streaming);
-
- DEBUG_PRINTF("is a long literal\n");
-
- const auto *end_inst = program.end_instruction();
- unique_ptr<RoseInstruction> ri;
- if (lit.s.any_nocase()) {
- ri = std::make_unique<RoseInstrCheckLongLitNocase>(lit.s.get_string(),
- end_inst);
- } else {
- ri = std::make_unique<RoseInstrCheckLongLit>(lit.s.get_string(), end_inst);
- }
- program.add_before_end(move(ri));
-}
-
-static
-void makeRoleCheckNotHandled(ProgramBuild &prog_build, RoseVertex v,
- RoseProgram &program) {
- u32 handled_key;
- if (contains(prog_build.handledKeys, v)) {
- handled_key = prog_build.handledKeys.at(v);
- } else {
- handled_key = verify_u32(prog_build.handledKeys.size());
- prog_build.handledKeys.emplace(v, handled_key);
- }
-
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrCheckNotHandled>(handled_key, end_inst);
- program.add_before_end(move(ri));
-}
-
-static
-void makeRoleCheckBounds(const RoseBuildImpl &build, RoseVertex v,
- const RoseEdge &e, RoseProgram &program) {
- const RoseGraph &g = build.g;
- const RoseVertex u = source(e, g);
-
- // We know that we can trust the anchored table (DFA) to always deliver us
- // literals at the correct offset.
- if (build.isAnchored(v)) {
- DEBUG_PRINTF("literal in anchored table, skipping bounds check\n");
- return;
- }
-
- // Use the minimum literal length.
- u32 lit_length = g[v].eod_accept ? 0 : verify_u32(build.minLiteralLen(v));
-
- u64a min_bound = g[e].minBound + lit_length;
- u64a max_bound = g[e].maxBound == ROSE_BOUND_INF
- ? ROSE_BOUND_INF
- : g[e].maxBound + lit_length;
-
- if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
- assert(g[u].fixedOffset());
- // Make offsets absolute.
- min_bound += g[u].max_offset;
- if (max_bound != ROSE_BOUND_INF) {
- max_bound += g[u].max_offset;
- }
- }
-
- assert(max_bound <= ROSE_BOUND_INF);
- assert(min_bound <= max_bound);
-
- // CHECK_BOUNDS instruction uses 64-bit bounds, so we can use MAX_OFFSET
- // (max value of a u64a) to represent ROSE_BOUND_INF.
- if (max_bound == ROSE_BOUND_INF) {
- max_bound = MAX_OFFSET;
- }
-
- // This instruction should be doing _something_ -- bounds should be tighter
- // than just {length, inf}.
- assert(min_bound > lit_length || max_bound < MAX_OFFSET);
-
- const auto *end_inst = program.end_instruction();
- program.add_before_end(
- std::make_unique<RoseInstrCheckBounds>(min_bound, max_bound, end_inst));
-}
-
-static
-void makeRoleGroups(const RoseGraph &g, ProgramBuild &prog_build,
- RoseVertex v, RoseProgram &program) {
- rose_group groups = g[v].groups;
- if (!groups) {
- return;
- }
-
- // The set of "already on" groups as we process this vertex is the
- // intersection of the groups set by our predecessors.
- assert(in_degree(v, g) > 0);
- rose_group already_on = ~rose_group{0};
- for (const auto &u : inv_adjacent_vertices_range(v, g)) {
- already_on &= prog_build.vertex_group_map.at(u);
- }
-
- DEBUG_PRINTF("already_on=0x%llx\n", already_on);
- DEBUG_PRINTF("squashable=0x%llx\n", prog_build.squashable_groups);
- DEBUG_PRINTF("groups=0x%llx\n", groups);
-
- already_on &= ~prog_build.squashable_groups;
- DEBUG_PRINTF("squashed already_on=0x%llx\n", already_on);
-
- // We don't *have* to mask off the groups that we know are already on, but
- // this will make bugs more apparent.
- groups &= ~already_on;
-
- if (!groups) {
- DEBUG_PRINTF("no new groups to set, skipping\n");
- return;
- }
-
+ }
+}
+
+static
+void makeCheckLiteralInstruction(const rose_literal_id &lit,
+ size_t longLitLengthThreshold,
+ RoseProgram &program,
+ const CompileContext &cc) {
+ assert(longLitLengthThreshold > 0);
+
+ DEBUG_PRINTF("lit=%s, long lit threshold %zu\n", dumpString(lit.s).c_str(),
+ longLitLengthThreshold);
+
+ if (lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX) {
+ DEBUG_PRINTF("lit short enough to not need confirm\n");
+ return;
+ }
+
+ // Check resource limits as well.
+ if (lit.s.length() > cc.grey.limitLiteralLength) {
+ throw ResourceLimitError();
+ }
+
+ if (lit.s.length() <= longLitLengthThreshold) {
+ DEBUG_PRINTF("is a medium-length literal\n");
+ const auto *end_inst = program.end_instruction();
+ unique_ptr<RoseInstruction> ri;
+ if (lit.s.any_nocase()) {
+ ri = std::make_unique<RoseInstrCheckMedLitNocase>(lit.s.get_string(),
+ end_inst);
+ } else {
+ ri = std::make_unique<RoseInstrCheckMedLit>(lit.s.get_string(),
+ end_inst);
+ }
+ program.add_before_end(move(ri));
+ return;
+ }
+
+ // Long literal support should only really be used for the floating table
+ // in streaming mode.
+ assert(lit.table == ROSE_FLOATING && cc.streaming);
+
+ DEBUG_PRINTF("is a long literal\n");
+
+ const auto *end_inst = program.end_instruction();
+ unique_ptr<RoseInstruction> ri;
+ if (lit.s.any_nocase()) {
+ ri = std::make_unique<RoseInstrCheckLongLitNocase>(lit.s.get_string(),
+ end_inst);
+ } else {
+ ri = std::make_unique<RoseInstrCheckLongLit>(lit.s.get_string(), end_inst);
+ }
+ program.add_before_end(move(ri));
+}
+
+static
+void makeRoleCheckNotHandled(ProgramBuild &prog_build, RoseVertex v,
+ RoseProgram &program) {
+ u32 handled_key;
+ if (contains(prog_build.handledKeys, v)) {
+ handled_key = prog_build.handledKeys.at(v);
+ } else {
+ handled_key = verify_u32(prog_build.handledKeys.size());
+ prog_build.handledKeys.emplace(v, handled_key);
+ }
+
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrCheckNotHandled>(handled_key, end_inst);
+ program.add_before_end(move(ri));
+}
+
+static
+void makeRoleCheckBounds(const RoseBuildImpl &build, RoseVertex v,
+ const RoseEdge &e, RoseProgram &program) {
+ const RoseGraph &g = build.g;
+ const RoseVertex u = source(e, g);
+
+ // We know that we can trust the anchored table (DFA) to always deliver us
+ // literals at the correct offset.
+ if (build.isAnchored(v)) {
+ DEBUG_PRINTF("literal in anchored table, skipping bounds check\n");
+ return;
+ }
+
+ // Use the minimum literal length.
+ u32 lit_length = g[v].eod_accept ? 0 : verify_u32(build.minLiteralLen(v));
+
+ u64a min_bound = g[e].minBound + lit_length;
+ u64a max_bound = g[e].maxBound == ROSE_BOUND_INF
+ ? ROSE_BOUND_INF
+ : g[e].maxBound + lit_length;
+
+ if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
+ assert(g[u].fixedOffset());
+ // Make offsets absolute.
+ min_bound += g[u].max_offset;
+ if (max_bound != ROSE_BOUND_INF) {
+ max_bound += g[u].max_offset;
+ }
+ }
+
+ assert(max_bound <= ROSE_BOUND_INF);
+ assert(min_bound <= max_bound);
+
+ // CHECK_BOUNDS instruction uses 64-bit bounds, so we can use MAX_OFFSET
+ // (max value of a u64a) to represent ROSE_BOUND_INF.
+ if (max_bound == ROSE_BOUND_INF) {
+ max_bound = MAX_OFFSET;
+ }
+
+ // This instruction should be doing _something_ -- bounds should be tighter
+ // than just {length, inf}.
+ assert(min_bound > lit_length || max_bound < MAX_OFFSET);
+
+ const auto *end_inst = program.end_instruction();
+ program.add_before_end(
+ std::make_unique<RoseInstrCheckBounds>(min_bound, max_bound, end_inst));
+}
+
+static
+void makeRoleGroups(const RoseGraph &g, ProgramBuild &prog_build,
+ RoseVertex v, RoseProgram &program) {
+ rose_group groups = g[v].groups;
+ if (!groups) {
+ return;
+ }
+
+ // The set of "already on" groups as we process this vertex is the
+ // intersection of the groups set by our predecessors.
+ assert(in_degree(v, g) > 0);
+ rose_group already_on = ~rose_group{0};
+ for (const auto &u : inv_adjacent_vertices_range(v, g)) {
+ already_on &= prog_build.vertex_group_map.at(u);
+ }
+
+ DEBUG_PRINTF("already_on=0x%llx\n", already_on);
+ DEBUG_PRINTF("squashable=0x%llx\n", prog_build.squashable_groups);
+ DEBUG_PRINTF("groups=0x%llx\n", groups);
+
+ already_on &= ~prog_build.squashable_groups;
+ DEBUG_PRINTF("squashed already_on=0x%llx\n", already_on);
+
+ // We don't *have* to mask off the groups that we know are already on, but
+ // this will make bugs more apparent.
+ groups &= ~already_on;
+
+ if (!groups) {
+ DEBUG_PRINTF("no new groups to set, skipping\n");
+ return;
+ }
+
program.add_before_end(std::make_unique<RoseInstrSetGroups>(groups));
-}
-
-static
-bool checkReachMask(const CharReach &cr, u8 &andmask, u8 &cmpmask) {
- size_t reach_size = cr.count();
- assert(reach_size > 0);
- // check whether entry_size is some power of 2.
- if ((reach_size - 1) & reach_size) {
- return false;
- }
- make_and_cmp_mask(cr, &andmask, &cmpmask);
- if ((1 << popcount32((u8)(~andmask))) ^ reach_size) {
- return false;
- }
- return true;
-}
-
-static
-bool checkReachWithFlip(const CharReach &cr, u8 &andmask,
- u8 &cmpmask, u8 &flip) {
- if (checkReachMask(cr, andmask, cmpmask)) {
- flip = 0;
- return true;
- }
- if (checkReachMask(~cr, andmask, cmpmask)) {
- flip = 1;
- return true;
- }
- return false;
-}
-
-static
-bool makeRoleByte(const vector<LookEntry> &look, RoseProgram &program) {
- if (look.size() == 1) {
- const auto &entry = look[0];
- u8 andmask_u8, cmpmask_u8;
- u8 flip;
- if (!checkReachWithFlip(entry.reach, andmask_u8, cmpmask_u8, flip)) {
- return false;
- }
- s32 checkbyte_offset = verify_s32(entry.offset);
- DEBUG_PRINTF("CHECK BYTE offset=%d\n", checkbyte_offset);
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrCheckByte>(andmask_u8, cmpmask_u8, flip,
- checkbyte_offset, end_inst);
- program.add_before_end(move(ri));
- return true;
- }
- return false;
-}
-
-static
-bool makeRoleMask(const vector<LookEntry> &look, RoseProgram &program) {
- if (look.back().offset < look.front().offset + 8) {
- s32 base_offset = verify_s32(look.front().offset);
- u64a and_mask = 0;
- u64a cmp_mask = 0;
- u64a neg_mask = 0;
- for (const auto &entry : look) {
- u8 andmask_u8, cmpmask_u8, flip;
- if (!checkReachWithFlip(entry.reach, andmask_u8,
- cmpmask_u8, flip)) {
- return false;
- }
- DEBUG_PRINTF("entry offset %d\n", entry.offset);
- u32 shift = (entry.offset - base_offset) << 3;
- and_mask |= (u64a)andmask_u8 << shift;
- cmp_mask |= (u64a)cmpmask_u8 << shift;
- if (flip) {
- neg_mask |= 0xffLLU << shift;
- }
- }
- DEBUG_PRINTF("CHECK MASK and_mask=%llx cmp_mask=%llx\n",
- and_mask, cmp_mask);
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrCheckMask>(and_mask, cmp_mask, neg_mask,
- base_offset, end_inst);
- program.add_before_end(move(ri));
- return true;
- }
- return false;
-}
-
-static UNUSED
-string convertMaskstoString(u8 *p, int byte_len) {
- string s;
- for (int i = 0; i < byte_len; i++) {
- u8 hi = *p >> 4;
- u8 lo = *p & 0xf;
- s += (char)(hi + (hi < 10 ? 48 : 87));
- s += (char)(lo + (lo < 10 ? 48 : 87));
- p++;
- }
- return s;
-}
-
-static
-bool makeRoleMask32(const vector<LookEntry> &look,
- RoseProgram &program) {
- if (look.back().offset >= look.front().offset + 32) {
- return false;
- }
- s32 base_offset = verify_s32(look.front().offset);
- array<u8, 32> and_mask, cmp_mask;
- and_mask.fill(0);
- cmp_mask.fill(0);
- u32 neg_mask = 0;
- for (const auto &entry : look) {
- u8 andmask_u8, cmpmask_u8, flip;
- if (!checkReachWithFlip(entry.reach, andmask_u8,
- cmpmask_u8, flip)) {
- return false;
- }
- u32 shift = entry.offset - base_offset;
- assert(shift < 32);
- and_mask[shift] = andmask_u8;
- cmp_mask[shift] = cmpmask_u8;
- if (flip) {
- neg_mask |= 1 << shift;
- }
- }
-
- DEBUG_PRINTF("and_mask %s\n",
- convertMaskstoString(and_mask.data(), 32).c_str());
- DEBUG_PRINTF("cmp_mask %s\n",
- convertMaskstoString(cmp_mask.data(), 32).c_str());
- DEBUG_PRINTF("neg_mask %08x\n", neg_mask);
- DEBUG_PRINTF("base_offset %d\n", base_offset);
-
- const auto *end_inst = program.end_instruction();
- auto ri = std::make_unique<RoseInstrCheckMask32>(and_mask, cmp_mask, neg_mask,
- base_offset, end_inst);
- program.add_before_end(move(ri));
- return true;
-}
-
+}
+
+static
+bool checkReachMask(const CharReach &cr, u8 &andmask, u8 &cmpmask) {
+ size_t reach_size = cr.count();
+ assert(reach_size > 0);
+ // check whether entry_size is some power of 2.
+ if ((reach_size - 1) & reach_size) {
+ return false;
+ }
+ make_and_cmp_mask(cr, &andmask, &cmpmask);
+ if ((1 << popcount32((u8)(~andmask))) ^ reach_size) {
+ return false;
+ }
+ return true;
+}
+
+static
+bool checkReachWithFlip(const CharReach &cr, u8 &andmask,
+ u8 &cmpmask, u8 &flip) {
+ if (checkReachMask(cr, andmask, cmpmask)) {
+ flip = 0;
+ return true;
+ }
+ if (checkReachMask(~cr, andmask, cmpmask)) {
+ flip = 1;
+ return true;
+ }
+ return false;
+}
+
+static
+bool makeRoleByte(const vector<LookEntry> &look, RoseProgram &program) {
+ if (look.size() == 1) {
+ const auto &entry = look[0];
+ u8 andmask_u8, cmpmask_u8;
+ u8 flip;
+ if (!checkReachWithFlip(entry.reach, andmask_u8, cmpmask_u8, flip)) {
+ return false;
+ }
+ s32 checkbyte_offset = verify_s32(entry.offset);
+ DEBUG_PRINTF("CHECK BYTE offset=%d\n", checkbyte_offset);
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrCheckByte>(andmask_u8, cmpmask_u8, flip,
+ checkbyte_offset, end_inst);
+ program.add_before_end(move(ri));
+ return true;
+ }
+ return false;
+}
+
+static
+bool makeRoleMask(const vector<LookEntry> &look, RoseProgram &program) {
+ if (look.back().offset < look.front().offset + 8) {
+ s32 base_offset = verify_s32(look.front().offset);
+ u64a and_mask = 0;
+ u64a cmp_mask = 0;
+ u64a neg_mask = 0;
+ for (const auto &entry : look) {
+ u8 andmask_u8, cmpmask_u8, flip;
+ if (!checkReachWithFlip(entry.reach, andmask_u8,
+ cmpmask_u8, flip)) {
+ return false;
+ }
+ DEBUG_PRINTF("entry offset %d\n", entry.offset);
+ u32 shift = (entry.offset - base_offset) << 3;
+ and_mask |= (u64a)andmask_u8 << shift;
+ cmp_mask |= (u64a)cmpmask_u8 << shift;
+ if (flip) {
+ neg_mask |= 0xffLLU << shift;
+ }
+ }
+ DEBUG_PRINTF("CHECK MASK and_mask=%llx cmp_mask=%llx\n",
+ and_mask, cmp_mask);
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrCheckMask>(and_mask, cmp_mask, neg_mask,
+ base_offset, end_inst);
+ program.add_before_end(move(ri));
+ return true;
+ }
+ return false;
+}
+
+static UNUSED
+string convertMaskstoString(u8 *p, int byte_len) {
+ string s;
+ for (int i = 0; i < byte_len; i++) {
+ u8 hi = *p >> 4;
+ u8 lo = *p & 0xf;
+ s += (char)(hi + (hi < 10 ? 48 : 87));
+ s += (char)(lo + (lo < 10 ? 48 : 87));
+ p++;
+ }
+ return s;
+}
+
+static
+bool makeRoleMask32(const vector<LookEntry> &look,
+ RoseProgram &program) {
+ if (look.back().offset >= look.front().offset + 32) {
+ return false;
+ }
+ s32 base_offset = verify_s32(look.front().offset);
+ array<u8, 32> and_mask, cmp_mask;
+ and_mask.fill(0);
+ cmp_mask.fill(0);
+ u32 neg_mask = 0;
+ for (const auto &entry : look) {
+ u8 andmask_u8, cmpmask_u8, flip;
+ if (!checkReachWithFlip(entry.reach, andmask_u8,
+ cmpmask_u8, flip)) {
+ return false;
+ }
+ u32 shift = entry.offset - base_offset;
+ assert(shift < 32);
+ and_mask[shift] = andmask_u8;
+ cmp_mask[shift] = cmpmask_u8;
+ if (flip) {
+ neg_mask |= 1 << shift;
+ }
+ }
+
+ DEBUG_PRINTF("and_mask %s\n",
+ convertMaskstoString(and_mask.data(), 32).c_str());
+ DEBUG_PRINTF("cmp_mask %s\n",
+ convertMaskstoString(cmp_mask.data(), 32).c_str());
+ DEBUG_PRINTF("neg_mask %08x\n", neg_mask);
+ DEBUG_PRINTF("base_offset %d\n", base_offset);
+
+ const auto *end_inst = program.end_instruction();
+ auto ri = std::make_unique<RoseInstrCheckMask32>(and_mask, cmp_mask, neg_mask,
+ base_offset, end_inst);
+ program.add_before_end(move(ri));
+ return true;
+}
+
static
bool makeRoleMask64(const vector<LookEntry> &look,
RoseProgram &program, const target_t &target) {
@@ -1104,202 +1104,202 @@ bool makeRoleMask64(const vector<LookEntry> &look,
return true;
}
-// Sorting by the size of every bucket.
-// Used in map<u32, vector<s8>, cmpNibble>.
-struct cmpNibble {
- bool operator()(const u32 data1, const u32 data2) const{
- u32 size1 = popcount32(data1 >> 16) * popcount32(data1 << 16);
- u32 size2 = popcount32(data2 >> 16) * popcount32(data2 << 16);
- return std::tie(size1, data1) < std::tie(size2, data2);
- }
-};
-
-// Insert all pairs of bucket and offset into buckets.
-static really_inline
-void getAllBuckets(const vector<LookEntry> &look,
- map<u32, vector<s8>, cmpNibble> &buckets, u64a &neg_mask) {
- s32 base_offset = verify_s32(look.front().offset);
- for (const auto &entry : look) {
- CharReach cr = entry.reach;
- // Flip heavy character classes to save buckets.
- if (cr.count() > 128 ) {
- cr.flip();
- } else {
- neg_mask ^= 1ULL << (entry.offset - base_offset);
- }
-
- map <u16, u16> lo2hi;
- // We treat Ascii Table as a 16x16 grid.
- // Push every row in cr into lo2hi and mark the row number.
- for (size_t i = cr.find_first(); i != CharReach::npos;) {
- u8 it_hi = i >> 4;
- u16 low_encode = 0;
- while (i != CharReach::npos && (i >> 4) == it_hi) {
- low_encode |= 1 << (i & 0xf);
- i = cr.find_next(i);
- }
- lo2hi[low_encode] |= 1 << it_hi;
- }
- for (const auto &it : lo2hi) {
- u32 hi_lo = (it.second << 16) | it.first;
- buckets[hi_lo].push_back(entry.offset);
- }
- }
-}
-
-// Once we have a new bucket, we'll try to combine it with all old buckets.
-static really_inline
-void nibUpdate(map<u32, u16> &nib, u32 hi_lo) {
- u16 hi = hi_lo >> 16;
- u16 lo = hi_lo & 0xffff;
- for (const auto pairs : nib) {
- u32 old = pairs.first;
- if ((old >> 16) == hi || (old & 0xffff) == lo) {
- if (!nib[old | hi_lo]) {
- nib[old | hi_lo] = nib[old] | nib[hi_lo];
- }
- }
- }
-}
-
-static really_inline
-void nibMaskUpdate(array<u8, 32> &mask, u32 data, u8 bit_index) {
- for (u8 index = 0; data > 0; data >>= 1, index++) {
- if (data & 1) {
- // 0 ~ 7 bucket in first 16 bytes,
- // 8 ~ 15 bucket in second 16 bytes.
- if (bit_index >= 8) {
- mask[index + 16] |= 1 << (bit_index - 8);
- } else {
- mask[index] |= 1 << bit_index;
- }
- }
- }
-}
-
-static
-bool getShuftiMasks(const vector<LookEntry> &look, array<u8, 32> &hi_mask,
- array<u8, 32> &lo_mask, u8 *bucket_select_hi,
- u8 *bucket_select_lo, u64a &neg_mask,
- u8 &bit_idx, size_t len) {
- map<u32, u16> nib; // map every bucket to its bucket number.
- map<u32, vector<s8>, cmpNibble> bucket2offsets;
- s32 base_offset = look.front().offset;
-
- bit_idx = 0;
- neg_mask = ~0ULL;
-
- getAllBuckets(look, bucket2offsets, neg_mask);
-
- for (const auto &it : bucket2offsets) {
- u32 hi_lo = it.first;
- // New bucket.
- if (!nib[hi_lo]) {
- if ((bit_idx >= 8 && len == 64) || bit_idx >= 16) {
- return false;
- }
- nib[hi_lo] = 1 << bit_idx;
-
- nibUpdate(nib, hi_lo);
- nibMaskUpdate(hi_mask, hi_lo >> 16, bit_idx);
- nibMaskUpdate(lo_mask, hi_lo & 0xffff, bit_idx);
- bit_idx++;
- }
-
- DEBUG_PRINTF("hi_lo %x bucket %x\n", hi_lo, nib[hi_lo]);
-
- // Update bucket_select_mask.
- u8 nib_hi = nib[hi_lo] >> 8;
- u8 nib_lo = nib[hi_lo] & 0xff;
- for (const auto offset : it.second) {
- bucket_select_hi[offset - base_offset] |= nib_hi;
- bucket_select_lo[offset - base_offset] |= nib_lo;
- }
- }
- return true;
-}
-
-static
-unique_ptr<RoseInstruction>
-makeCheckShufti16x8(u32 offset_range, u8 bucket_idx,
- const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
- const array<u8, 32> &bucket_select_mask,
- u32 neg_mask, s32 base_offset,
- const RoseInstruction *end_inst) {
- if (offset_range > 16 || bucket_idx > 8) {
- return nullptr;
- }
- array<u8, 32> nib_mask;
- array<u8, 16> bucket_select_mask_16;
- copy(lo_mask.begin(), lo_mask.begin() + 16, nib_mask.begin());
- copy(hi_mask.begin(), hi_mask.begin() + 16, nib_mask.begin() + 16);
- copy(bucket_select_mask.begin(), bucket_select_mask.begin() + 16,
- bucket_select_mask_16.begin());
- return std::make_unique<RoseInstrCheckShufti16x8>
- (nib_mask, bucket_select_mask_16,
- neg_mask & 0xffff, base_offset, end_inst);
-}
-
-static
-unique_ptr<RoseInstruction>
-makeCheckShufti32x8(u32 offset_range, u8 bucket_idx,
- const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
- const array<u8, 32> &bucket_select_mask,
- u32 neg_mask, s32 base_offset,
- const RoseInstruction *end_inst) {
- if (offset_range > 32 || bucket_idx > 8) {
- return nullptr;
- }
-
- array<u8, 16> hi_mask_16;
- array<u8, 16> lo_mask_16;
- copy(hi_mask.begin(), hi_mask.begin() + 16, hi_mask_16.begin());
- copy(lo_mask.begin(), lo_mask.begin() + 16, lo_mask_16.begin());
- return std::make_unique<RoseInstrCheckShufti32x8>
- (hi_mask_16, lo_mask_16, bucket_select_mask,
- neg_mask, base_offset, end_inst);
-}
-
-static
-unique_ptr<RoseInstruction>
-makeCheckShufti16x16(u32 offset_range, u8 bucket_idx,
- const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
- const array<u8, 32> &bucket_select_mask_lo,
- const array<u8, 32> &bucket_select_mask_hi,
- u32 neg_mask, s32 base_offset,
- const RoseInstruction *end_inst) {
- if (offset_range > 16 || bucket_idx > 16) {
- return nullptr;
- }
-
- array<u8, 32> bucket_select_mask_32;
- copy(bucket_select_mask_lo.begin(), bucket_select_mask_lo.begin() + 16,
- bucket_select_mask_32.begin());
- copy(bucket_select_mask_hi.begin(), bucket_select_mask_hi.begin() + 16,
- bucket_select_mask_32.begin() + 16);
- return std::make_unique<RoseInstrCheckShufti16x16>
- (hi_mask, lo_mask, bucket_select_mask_32,
- neg_mask & 0xffff, base_offset, end_inst);
-}
-
-static
-unique_ptr<RoseInstruction>
-makeCheckShufti32x16(u32 offset_range, u8 bucket_idx,
- const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
- const array<u8, 32> &bucket_select_mask_lo,
- const array<u8, 32> &bucket_select_mask_hi,
- u32 neg_mask, s32 base_offset,
- const RoseInstruction *end_inst) {
- if (offset_range > 32 || bucket_idx > 16) {
- return nullptr;
- }
-
- return std::make_unique<RoseInstrCheckShufti32x16>
- (hi_mask, lo_mask, bucket_select_mask_hi,
- bucket_select_mask_lo, neg_mask, base_offset, end_inst);
-}
-
-static
+// Sorting by the size of every bucket.
+// Used in map<u32, vector<s8>, cmpNibble>.
+struct cmpNibble {
+ bool operator()(const u32 data1, const u32 data2) const{
+ u32 size1 = popcount32(data1 >> 16) * popcount32(data1 << 16);
+ u32 size2 = popcount32(data2 >> 16) * popcount32(data2 << 16);
+ return std::tie(size1, data1) < std::tie(size2, data2);
+ }
+};
+
+// Insert all pairs of bucket and offset into buckets.
+static really_inline
+void getAllBuckets(const vector<LookEntry> &look,
+ map<u32, vector<s8>, cmpNibble> &buckets, u64a &neg_mask) {
+ s32 base_offset = verify_s32(look.front().offset);
+ for (const auto &entry : look) {
+ CharReach cr = entry.reach;
+ // Flip heavy character classes to save buckets.
+ if (cr.count() > 128 ) {
+ cr.flip();
+ } else {
+ neg_mask ^= 1ULL << (entry.offset - base_offset);
+ }
+
+ map <u16, u16> lo2hi;
+ // We treat Ascii Table as a 16x16 grid.
+ // Push every row in cr into lo2hi and mark the row number.
+ for (size_t i = cr.find_first(); i != CharReach::npos;) {
+ u8 it_hi = i >> 4;
+ u16 low_encode = 0;
+ while (i != CharReach::npos && (i >> 4) == it_hi) {
+ low_encode |= 1 << (i & 0xf);
+ i = cr.find_next(i);
+ }
+ lo2hi[low_encode] |= 1 << it_hi;
+ }
+ for (const auto &it : lo2hi) {
+ u32 hi_lo = (it.second << 16) | it.first;
+ buckets[hi_lo].push_back(entry.offset);
+ }
+ }
+}
+
+// Once we have a new bucket, we'll try to combine it with all old buckets.
+static really_inline
+void nibUpdate(map<u32, u16> &nib, u32 hi_lo) {
+ u16 hi = hi_lo >> 16;
+ u16 lo = hi_lo & 0xffff;
+ for (const auto pairs : nib) {
+ u32 old = pairs.first;
+ if ((old >> 16) == hi || (old & 0xffff) == lo) {
+ if (!nib[old | hi_lo]) {
+ nib[old | hi_lo] = nib[old] | nib[hi_lo];
+ }
+ }
+ }
+}
+
+static really_inline
+void nibMaskUpdate(array<u8, 32> &mask, u32 data, u8 bit_index) {
+ for (u8 index = 0; data > 0; data >>= 1, index++) {
+ if (data & 1) {
+ // 0 ~ 7 bucket in first 16 bytes,
+ // 8 ~ 15 bucket in second 16 bytes.
+ if (bit_index >= 8) {
+ mask[index + 16] |= 1 << (bit_index - 8);
+ } else {
+ mask[index] |= 1 << bit_index;
+ }
+ }
+ }
+}
+
+static
+bool getShuftiMasks(const vector<LookEntry> &look, array<u8, 32> &hi_mask,
+ array<u8, 32> &lo_mask, u8 *bucket_select_hi,
+ u8 *bucket_select_lo, u64a &neg_mask,
+ u8 &bit_idx, size_t len) {
+ map<u32, u16> nib; // map every bucket to its bucket number.
+ map<u32, vector<s8>, cmpNibble> bucket2offsets;
+ s32 base_offset = look.front().offset;
+
+ bit_idx = 0;
+ neg_mask = ~0ULL;
+
+ getAllBuckets(look, bucket2offsets, neg_mask);
+
+ for (const auto &it : bucket2offsets) {
+ u32 hi_lo = it.first;
+ // New bucket.
+ if (!nib[hi_lo]) {
+ if ((bit_idx >= 8 && len == 64) || bit_idx >= 16) {
+ return false;
+ }
+ nib[hi_lo] = 1 << bit_idx;
+
+ nibUpdate(nib, hi_lo);
+ nibMaskUpdate(hi_mask, hi_lo >> 16, bit_idx);
+ nibMaskUpdate(lo_mask, hi_lo & 0xffff, bit_idx);
+ bit_idx++;
+ }
+
+ DEBUG_PRINTF("hi_lo %x bucket %x\n", hi_lo, nib[hi_lo]);
+
+ // Update bucket_select_mask.
+ u8 nib_hi = nib[hi_lo] >> 8;
+ u8 nib_lo = nib[hi_lo] & 0xff;
+ for (const auto offset : it.second) {
+ bucket_select_hi[offset - base_offset] |= nib_hi;
+ bucket_select_lo[offset - base_offset] |= nib_lo;
+ }
+ }
+ return true;
+}
+
+static
+unique_ptr<RoseInstruction>
+makeCheckShufti16x8(u32 offset_range, u8 bucket_idx,
+ const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
+ const array<u8, 32> &bucket_select_mask,
+ u32 neg_mask, s32 base_offset,
+ const RoseInstruction *end_inst) {
+ if (offset_range > 16 || bucket_idx > 8) {
+ return nullptr;
+ }
+ array<u8, 32> nib_mask;
+ array<u8, 16> bucket_select_mask_16;
+ copy(lo_mask.begin(), lo_mask.begin() + 16, nib_mask.begin());
+ copy(hi_mask.begin(), hi_mask.begin() + 16, nib_mask.begin() + 16);
+ copy(bucket_select_mask.begin(), bucket_select_mask.begin() + 16,
+ bucket_select_mask_16.begin());
+ return std::make_unique<RoseInstrCheckShufti16x8>
+ (nib_mask, bucket_select_mask_16,
+ neg_mask & 0xffff, base_offset, end_inst);
+}
+
+static
+unique_ptr<RoseInstruction>
+makeCheckShufti32x8(u32 offset_range, u8 bucket_idx,
+ const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
+ const array<u8, 32> &bucket_select_mask,
+ u32 neg_mask, s32 base_offset,
+ const RoseInstruction *end_inst) {
+ if (offset_range > 32 || bucket_idx > 8) {
+ return nullptr;
+ }
+
+ array<u8, 16> hi_mask_16;
+ array<u8, 16> lo_mask_16;
+ copy(hi_mask.begin(), hi_mask.begin() + 16, hi_mask_16.begin());
+ copy(lo_mask.begin(), lo_mask.begin() + 16, lo_mask_16.begin());
+ return std::make_unique<RoseInstrCheckShufti32x8>
+ (hi_mask_16, lo_mask_16, bucket_select_mask,
+ neg_mask, base_offset, end_inst);
+}
+
+static
+unique_ptr<RoseInstruction>
+makeCheckShufti16x16(u32 offset_range, u8 bucket_idx,
+ const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
+ const array<u8, 32> &bucket_select_mask_lo,
+ const array<u8, 32> &bucket_select_mask_hi,
+ u32 neg_mask, s32 base_offset,
+ const RoseInstruction *end_inst) {
+ if (offset_range > 16 || bucket_idx > 16) {
+ return nullptr;
+ }
+
+ array<u8, 32> bucket_select_mask_32;
+ copy(bucket_select_mask_lo.begin(), bucket_select_mask_lo.begin() + 16,
+ bucket_select_mask_32.begin());
+ copy(bucket_select_mask_hi.begin(), bucket_select_mask_hi.begin() + 16,
+ bucket_select_mask_32.begin() + 16);
+ return std::make_unique<RoseInstrCheckShufti16x16>
+ (hi_mask, lo_mask, bucket_select_mask_32,
+ neg_mask & 0xffff, base_offset, end_inst);
+}
+
+static
+unique_ptr<RoseInstruction>
+makeCheckShufti32x16(u32 offset_range, u8 bucket_idx,
+ const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
+ const array<u8, 32> &bucket_select_mask_lo,
+ const array<u8, 32> &bucket_select_mask_hi,
+ u32 neg_mask, s32 base_offset,
+ const RoseInstruction *end_inst) {
+ if (offset_range > 32 || bucket_idx > 16) {
+ return nullptr;
+ }
+
+ return std::make_unique<RoseInstrCheckShufti32x16>
+ (hi_mask, lo_mask, bucket_select_mask_hi,
+ bucket_select_mask_lo, neg_mask, base_offset, end_inst);
+}
+
+static
unique_ptr<RoseInstruction>
makeCheckShufti64x8(u32 offset_range, u8 bucket_idx,
const array<u8, 32> &hi_mask, const array<u8, 32> &lo_mask,
@@ -1309,7 +1309,7 @@ makeCheckShufti64x8(u32 offset_range, u8 bucket_idx,
if (offset_range > 64 || bucket_idx > 8) {
return nullptr;
}
-
+
array<u8, 64> hi_mask_64;
array<u8, 64> lo_mask_64;
copy(hi_mask.begin(), hi_mask.begin() + 16, hi_mask_64.begin());
@@ -1375,26 +1375,26 @@ bool makeRoleShufti(const vector<LookEntry> &look, RoseProgram &program,
} else {
offset_limit = 32;
}
- s32 base_offset = verify_s32(look.front().offset);
+ s32 base_offset = verify_s32(look.front().offset);
if (look.back().offset >= base_offset + offset_limit) {
- return false;
- }
-
- u8 bucket_idx = 0; // number of buckets
- u64a neg_mask_64;
- array<u8, 32> hi_mask;
- array<u8, 32> lo_mask;
+ return false;
+ }
+
+ u8 bucket_idx = 0; // number of buckets
+ u64a neg_mask_64;
+ array<u8, 32> hi_mask;
+ array<u8, 32> lo_mask;
array<u8, 64> bucket_select_hi_64; // for AVX512
array<u8, 64> bucket_select_lo_64; // for AVX512
- array<u8, 32> bucket_select_hi;
- array<u8, 32> bucket_select_lo;
- hi_mask.fill(0);
- lo_mask.fill(0);
+ array<u8, 32> bucket_select_hi;
+ array<u8, 32> bucket_select_lo;
+ hi_mask.fill(0);
+ lo_mask.fill(0);
bucket_select_hi_64.fill(0);
bucket_select_lo_64.fill(0);
- bucket_select_hi.fill(0); // will not be used in 16x8 and 32x8.
- bucket_select_lo.fill(0);
-
+ bucket_select_hi.fill(0); // will not be used in 16x8 and 32x8.
+ bucket_select_lo.fill(0);
+
if (target.has_avx512()) {
if (!getShuftiMasks(look, hi_mask, lo_mask, bucket_select_hi_64.data(),
bucket_select_lo_64.data(), neg_mask_64, bucket_idx,
@@ -1416,30 +1416,30 @@ bool makeRoleShufti(const vector<LookEntry> &look, RoseProgram &program,
32)) {
return false;
}
- }
-
- u32 neg_mask = (u32)neg_mask_64;
-
- DEBUG_PRINTF("hi_mask %s\n",
- convertMaskstoString(hi_mask.data(), 32).c_str());
- DEBUG_PRINTF("lo_mask %s\n",
- convertMaskstoString(lo_mask.data(), 32).c_str());
- DEBUG_PRINTF("bucket_select_hi %s\n",
- convertMaskstoString(bucket_select_hi.data(), 32).c_str());
- DEBUG_PRINTF("bucket_select_lo %s\n",
- convertMaskstoString(bucket_select_lo.data(), 32).c_str());
-
- const auto *end_inst = program.end_instruction();
- s32 offset_range = look.back().offset - base_offset + 1;
-
- auto ri = makeCheckShufti16x8(offset_range, bucket_idx, hi_mask, lo_mask,
- bucket_select_lo, neg_mask, base_offset,
- end_inst);
- if (!ri) {
- ri = makeCheckShufti32x8(offset_range, bucket_idx, hi_mask, lo_mask,
- bucket_select_lo, neg_mask, base_offset,
- end_inst);
- }
+ }
+
+ u32 neg_mask = (u32)neg_mask_64;
+
+ DEBUG_PRINTF("hi_mask %s\n",
+ convertMaskstoString(hi_mask.data(), 32).c_str());
+ DEBUG_PRINTF("lo_mask %s\n",
+ convertMaskstoString(lo_mask.data(), 32).c_str());
+ DEBUG_PRINTF("bucket_select_hi %s\n",
+ convertMaskstoString(bucket_select_hi.data(), 32).c_str());
+ DEBUG_PRINTF("bucket_select_lo %s\n",
+ convertMaskstoString(bucket_select_lo.data(), 32).c_str());
+
+ const auto *end_inst = program.end_instruction();
+ s32 offset_range = look.back().offset - base_offset + 1;
+
+ auto ri = makeCheckShufti16x8(offset_range, bucket_idx, hi_mask, lo_mask,
+ bucket_select_lo, neg_mask, base_offset,
+ end_inst);
+ if (!ri) {
+ ri = makeCheckShufti32x8(offset_range, bucket_idx, hi_mask, lo_mask,
+ bucket_select_lo, neg_mask, base_offset,
+ end_inst);
+ }
if (target.has_avx512()) {
if (!ri) {
ri = makeCheckShufti64x8(offset_range, bucket_idx, hi_mask, lo_mask,
@@ -1447,16 +1447,16 @@ bool makeRoleShufti(const vector<LookEntry> &look, RoseProgram &program,
base_offset, end_inst);
}
}
- if (!ri) {
- ri = makeCheckShufti16x16(offset_range, bucket_idx, hi_mask, lo_mask,
- bucket_select_lo, bucket_select_hi,
- neg_mask, base_offset, end_inst);
- }
- if (!ri) {
- ri = makeCheckShufti32x16(offset_range, bucket_idx, hi_mask, lo_mask,
- bucket_select_lo, bucket_select_hi,
- neg_mask, base_offset, end_inst);
- }
+ if (!ri) {
+ ri = makeCheckShufti16x16(offset_range, bucket_idx, hi_mask, lo_mask,
+ bucket_select_lo, bucket_select_hi,
+ neg_mask, base_offset, end_inst);
+ }
+ if (!ri) {
+ ri = makeCheckShufti32x16(offset_range, bucket_idx, hi_mask, lo_mask,
+ bucket_select_lo, bucket_select_hi,
+ neg_mask, base_offset, end_inst);
+ }
if (target.has_avx512()) {
if (!ri) {
ri = makeCheckShufti64x16(offset_range, bucket_idx, hi_mask, lo_mask,
@@ -1464,1137 +1464,1137 @@ bool makeRoleShufti(const vector<LookEntry> &look, RoseProgram &program,
neg_mask_64, base_offset, end_inst);
}
}
- assert(ri);
- program.add_before_end(move(ri));
-
- return true;
-}
-
-/**
- * Builds a lookaround instruction, or an appropriate specialization if one is
- * available.
- */
-static
-void makeLookaroundInstruction(const vector<LookEntry> &look,
+ assert(ri);
+ program.add_before_end(move(ri));
+
+ return true;
+}
+
+/**
+ * Builds a lookaround instruction, or an appropriate specialization if one is
+ * available.
+ */
+static
+void makeLookaroundInstruction(const vector<LookEntry> &look,
RoseProgram &program, const target_t &target) {
- assert(!look.empty());
-
- if (makeRoleByte(look, program)) {
- return;
- }
-
- if (look.size() == 1) {
- s8 offset = look.begin()->offset;
- const CharReach &reach = look.begin()->reach;
- auto ri = std::make_unique<RoseInstrCheckSingleLookaround>(offset, reach,
- program.end_instruction());
- program.add_before_end(move(ri));
- return;
- }
-
- if (makeRoleMask(look, program)) {
- return;
- }
-
- if (makeRoleMask32(look, program)) {
- return;
- }
-
+ assert(!look.empty());
+
+ if (makeRoleByte(look, program)) {
+ return;
+ }
+
+ if (look.size() == 1) {
+ s8 offset = look.begin()->offset;
+ const CharReach &reach = look.begin()->reach;
+ auto ri = std::make_unique<RoseInstrCheckSingleLookaround>(offset, reach,
+ program.end_instruction());
+ program.add_before_end(move(ri));
+ return;
+ }
+
+ if (makeRoleMask(look, program)) {
+ return;
+ }
+
+ if (makeRoleMask32(look, program)) {
+ return;
+ }
+
if (makeRoleMask64(look, program, target)) {
- return;
- }
-
+ return;
+ }
+
if (makeRoleShufti(look, program, target)) {
return;
}
- auto ri = std::make_unique<RoseInstrCheckLookaround>(look,
- program.end_instruction());
- program.add_before_end(move(ri));
-}
-
-static
-void makeCheckLitMaskInstruction(const RoseBuildImpl &build, u32 lit_id,
- RoseProgram &program) {
- const auto &info = build.literal_info.at(lit_id);
- if (!info.requires_benefits) {
- return;
- }
-
- vector<LookEntry> look;
-
- const auto &lit = build.literals.at(lit_id);
- const ue2_literal &s = lit.s;
- const auto &msk = lit.msk;
-
- DEBUG_PRINTF("building mask for lit %u: %s\n", lit_id,
- dumpString(s).c_str());
-
- assert(s.length() <= MAX_MASK2_WIDTH);
-
- // Note: the literal matcher will confirm the HWLM mask in lit.msk, so we
- // do not include those entries in the lookaround.
- auto it = s.begin();
- for (s32 i = 0 - s.length(), i_end = 0 - msk.size(); i < i_end; ++i, ++it) {
- if (!it->nocase) {
- look.emplace_back(verify_s8(i), *it);
- }
- }
-
- if (look.empty()) {
- return; // all caseful chars handled by HWLM mask.
- }
-
+ auto ri = std::make_unique<RoseInstrCheckLookaround>(look,
+ program.end_instruction());
+ program.add_before_end(move(ri));
+}
+
+static
+void makeCheckLitMaskInstruction(const RoseBuildImpl &build, u32 lit_id,
+ RoseProgram &program) {
+ const auto &info = build.literal_info.at(lit_id);
+ if (!info.requires_benefits) {
+ return;
+ }
+
+ vector<LookEntry> look;
+
+ const auto &lit = build.literals.at(lit_id);
+ const ue2_literal &s = lit.s;
+ const auto &msk = lit.msk;
+
+ DEBUG_PRINTF("building mask for lit %u: %s\n", lit_id,
+ dumpString(s).c_str());
+
+ assert(s.length() <= MAX_MASK2_WIDTH);
+
+ // Note: the literal matcher will confirm the HWLM mask in lit.msk, so we
+ // do not include those entries in the lookaround.
+ auto it = s.begin();
+ for (s32 i = 0 - s.length(), i_end = 0 - msk.size(); i < i_end; ++i, ++it) {
+ if (!it->nocase) {
+ look.emplace_back(verify_s8(i), *it);
+ }
+ }
+
+ if (look.empty()) {
+ return; // all caseful chars handled by HWLM mask.
+ }
+
makeLookaroundInstruction(look, program, build.cc.target_info);
-}
-
-static
-void makeCheckLitEarlyInstruction(const RoseBuildImpl &build, u32 lit_id,
- const vector<RoseEdge> &lit_edges,
- u32 floatingMinLiteralMatchOffset,
- RoseProgram &prog) {
- if (lit_edges.empty()) {
- return;
- }
-
- if (floatingMinLiteralMatchOffset == 0) {
- return;
- }
-
- RoseVertex v = target(lit_edges.front(), build.g);
- if (!build.isFloating(v)) {
- return;
- }
-
- const auto &lit = build.literals.at(lit_id);
- size_t min_len = lit.elength();
- u32 min_offset = findMinOffset(build, lit_id);
- DEBUG_PRINTF("has min_len=%zu, min_offset=%u, global min is %u\n", min_len,
- min_offset, floatingMinLiteralMatchOffset);
-
- // If we can't match before the min offset, we don't need the check.
- if (min_len >= floatingMinLiteralMatchOffset) {
- DEBUG_PRINTF("no need for check, min is %u\n",
- floatingMinLiteralMatchOffset);
- return;
- }
-
- assert(min_offset >= floatingMinLiteralMatchOffset);
- assert(min_offset < UINT32_MAX);
-
- DEBUG_PRINTF("adding lit early check, min_offset=%u\n", min_offset);
- const auto *end = prog.end_instruction();
+}
+
+static
+void makeCheckLitEarlyInstruction(const RoseBuildImpl &build, u32 lit_id,
+ const vector<RoseEdge> &lit_edges,
+ u32 floatingMinLiteralMatchOffset,
+ RoseProgram &prog) {
+ if (lit_edges.empty()) {
+ return;
+ }
+
+ if (floatingMinLiteralMatchOffset == 0) {
+ return;
+ }
+
+ RoseVertex v = target(lit_edges.front(), build.g);
+ if (!build.isFloating(v)) {
+ return;
+ }
+
+ const auto &lit = build.literals.at(lit_id);
+ size_t min_len = lit.elength();
+ u32 min_offset = findMinOffset(build, lit_id);
+ DEBUG_PRINTF("has min_len=%zu, min_offset=%u, global min is %u\n", min_len,
+ min_offset, floatingMinLiteralMatchOffset);
+
+ // If we can't match before the min offset, we don't need the check.
+ if (min_len >= floatingMinLiteralMatchOffset) {
+ DEBUG_PRINTF("no need for check, min is %u\n",
+ floatingMinLiteralMatchOffset);
+ return;
+ }
+
+ assert(min_offset >= floatingMinLiteralMatchOffset);
+ assert(min_offset < UINT32_MAX);
+
+ DEBUG_PRINTF("adding lit early check, min_offset=%u\n", min_offset);
+ const auto *end = prog.end_instruction();
prog.add_before_end(std::make_unique<RoseInstrCheckLitEarly>(min_offset, end));
-}
-
-static
-void makeGroupCheckInstruction(const RoseBuildImpl &build, u32 lit_id,
- RoseProgram &prog) {
- const auto &info = build.literal_info.at(lit_id);
-
- if (!info.group_mask) {
- return;
- }
+}
+
+static
+void makeGroupCheckInstruction(const RoseBuildImpl &build, u32 lit_id,
+ RoseProgram &prog) {
+ const auto &info = build.literal_info.at(lit_id);
+
+ if (!info.group_mask) {
+ return;
+ }
prog.add_before_end(std::make_unique<RoseInstrCheckGroups>(info.group_mask));
-}
-
-static
-bool hasDelayedLiteral(const RoseBuildImpl &build,
- const vector<RoseEdge> &lit_edges) {
- auto is_delayed = [&build](u32 lit_id) { return build.isDelayed(lit_id); };
- for (const auto &e : lit_edges) {
- auto v = target(e, build.g);
- const auto &lits = build.g[v].literals;
- if (any_of(begin(lits), end(lits), is_delayed)) {
- return true;
- }
- }
- return false;
-}
-
-static
-RoseProgram makeLitInitialProgram(const RoseBuildImpl &build,
- ProgramBuild &prog_build, u32 lit_id,
- const vector<RoseEdge> &lit_edges,
- bool is_anchored_replay_program) {
- RoseProgram program;
-
- // Check long literal info.
- if (!build.isDelayed(lit_id)) {
- makeCheckLiteralInstruction(build.literals.at(lit_id),
- prog_build.longLitLengthThreshold,
- program, build.cc);
- }
-
- // Check lit mask.
- makeCheckLitMaskInstruction(build, lit_id, program);
-
- // Check literal groups. This is an optimisation that we only perform for
- // delayed literals, as their groups may be switched off; ordinarily, we
- // can trust the HWLM matcher.
- if (hasDelayedLiteral(build, lit_edges)) {
- makeGroupCheckInstruction(build, lit_id, program);
- }
-
- // Add instructions for pushing delayed matches, if there are any.
- makePushDelayedInstructions(build.literals, prog_build,
- build.literal_info.at(lit_id).delayed_ids,
- program);
-
- // Add pre-check for early literals in the floating table.
- makeCheckLitEarlyInstruction(build, lit_id, lit_edges,
- prog_build.floatingMinLiteralMatchOffset,
- program);
-
- /* Check if we are able to deliever matches from the anchored table now */
- if (!is_anchored_replay_program) {
- makeAnchoredLiteralDelay(build, prog_build, lit_id, program);
- }
-
- return program;
-}
-
-static
-bool makeRoleMultipathShufti(const vector<vector<LookEntry>> &multi_look,
- RoseProgram &program) {
- if (multi_look.empty()) {
- return false;
- }
-
- // find the base offset
- assert(!multi_look[0].empty());
- s32 base_offset = multi_look[0].front().offset;
- s32 last_start = base_offset;
- s32 end_offset = multi_look[0].back().offset;
- size_t multi_len = 0;
-
- for (const auto &look : multi_look) {
- assert(look.size() > 0);
- multi_len += look.size();
-
- LIMIT_TO_AT_MOST(&base_offset, look.front().offset);
- ENSURE_AT_LEAST(&last_start, look.front().offset);
- ENSURE_AT_LEAST(&end_offset, look.back().offset);
- }
-
- assert(last_start < 0);
-
- if (end_offset - base_offset >= MULTIPATH_MAX_LEN) {
- return false;
- }
-
- if (multi_len <= 16) {
- multi_len = 16;
- } else if (multi_len <= 32) {
- multi_len = 32;
- } else if (multi_len <= 64) {
- multi_len = 64;
- } else {
- DEBUG_PRINTF("too long for multi-path\n");
- return false;
- }
-
- vector<LookEntry> linear_look;
- array<u8, 64> data_select_mask;
- data_select_mask.fill(0);
- u64a hi_bits_mask = 0;
- u64a lo_bits_mask = 0;
-
- for (const auto &look : multi_look) {
- assert(linear_look.size() < 64);
- lo_bits_mask |= 1LLU << linear_look.size();
- for (const auto &entry : look) {
- assert(entry.offset - base_offset < MULTIPATH_MAX_LEN);
- data_select_mask[linear_look.size()] =
- verify_u8(entry.offset - base_offset);
- linear_look.emplace_back(verify_s8(linear_look.size()), entry.reach);
- }
- hi_bits_mask |= 1LLU << (linear_look.size() - 1);
- }
-
- u8 bit_index = 0; // number of buckets
- u64a neg_mask;
- array<u8, 32> hi_mask;
- array<u8, 32> lo_mask;
- array<u8, 64> bucket_select_hi;
- array<u8, 64> bucket_select_lo;
- hi_mask.fill(0);
- lo_mask.fill(0);
- bucket_select_hi.fill(0);
- bucket_select_lo.fill(0);
-
- if (!getShuftiMasks(linear_look, hi_mask, lo_mask, bucket_select_hi.data(),
- bucket_select_lo.data(), neg_mask, bit_index,
- multi_len)) {
- return false;
- }
-
- DEBUG_PRINTF("hi_mask %s\n",
- convertMaskstoString(hi_mask.data(), 16).c_str());
- DEBUG_PRINTF("lo_mask %s\n",
- convertMaskstoString(lo_mask.data(), 16).c_str());
- DEBUG_PRINTF("bucket_select_hi %s\n",
- convertMaskstoString(bucket_select_hi.data(), 64).c_str());
- DEBUG_PRINTF("bucket_select_lo %s\n",
- convertMaskstoString(bucket_select_lo.data(), 64).c_str());
- DEBUG_PRINTF("data_select_mask %s\n",
- convertMaskstoString(data_select_mask.data(), 64).c_str());
- DEBUG_PRINTF("hi_bits_mask %llx\n", hi_bits_mask);
- DEBUG_PRINTF("lo_bits_mask %llx\n", lo_bits_mask);
- DEBUG_PRINTF("neg_mask %llx\n", neg_mask);
- DEBUG_PRINTF("base_offset %d\n", base_offset);
- DEBUG_PRINTF("last_start %d\n", last_start);
-
- // Since we don't have 16x16 now, just call 32x16 instead.
- if (bit_index > 8) {
- assert(multi_len <= 32);
- multi_len = 32;
- }
-
- const auto *end_inst = program.end_instruction();
- assert(multi_len == 16 || multi_len == 32 || multi_len == 64);
- if (multi_len == 16) {
- neg_mask &= 0xffff;
- assert(!(hi_bits_mask & ~0xffffULL));
- assert(!(lo_bits_mask & ~0xffffULL));
- assert(bit_index <=8);
- array<u8, 32> nib_mask;
- copy(begin(lo_mask), begin(lo_mask) + 16, nib_mask.begin());
- copy(begin(hi_mask), begin(hi_mask) + 16, nib_mask.begin() + 16);
-
- auto ri = std::make_unique<RoseInstrCheckMultipathShufti16x8>
- (nib_mask, bucket_select_lo, data_select_mask, hi_bits_mask,
- lo_bits_mask, neg_mask, base_offset, last_start, end_inst);
- program.add_before_end(move(ri));
- } else if (multi_len == 32) {
- neg_mask &= 0xffffffff;
- assert(!(hi_bits_mask & ~0xffffffffULL));
- assert(!(lo_bits_mask & ~0xffffffffULL));
- if (bit_index <= 8) {
- auto ri = std::make_unique<RoseInstrCheckMultipathShufti32x8>
- (hi_mask, lo_mask, bucket_select_lo, data_select_mask,
- hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
- last_start, end_inst);
- program.add_before_end(move(ri));
- } else {
- auto ri = std::make_unique<RoseInstrCheckMultipathShufti32x16>
- (hi_mask, lo_mask, bucket_select_hi, bucket_select_lo,
- data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
- base_offset, last_start, end_inst);
- program.add_before_end(move(ri));
- }
- } else {
- auto ri = std::make_unique<RoseInstrCheckMultipathShufti64>
- (hi_mask, lo_mask, bucket_select_lo, data_select_mask,
- hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
- last_start, end_inst);
- program.add_before_end(move(ri));
- }
- return true;
-}
-
-static
-void makeRoleMultipathLookaround(const vector<vector<LookEntry>> &multi_look,
- RoseProgram &program) {
- assert(!multi_look.empty());
- assert(multi_look.size() <= MAX_LOOKAROUND_PATHS);
- vector<vector<LookEntry>> ordered_look;
- set<s32> look_offset;
-
- assert(!multi_look[0].empty());
- s32 last_start = multi_look[0][0].offset;
-
- // build offset table.
- for (const auto &look : multi_look) {
- assert(look.size() > 0);
- last_start = max(last_start, (s32)look.begin()->offset);
-
- for (const auto &t : look) {
- look_offset.insert(t.offset);
- }
- }
-
- array<u8, MULTIPATH_MAX_LEN> start_mask;
- if (multi_look.size() < MAX_LOOKAROUND_PATHS) {
- start_mask.fill((1 << multi_look.size()) - 1);
- } else {
- start_mask.fill(0xff);
- }
-
- u32 path_idx = 0;
- for (const auto &look : multi_look) {
- for (const auto &t : look) {
- assert(t.offset >= (int)*look_offset.begin());
- size_t update_offset = t.offset - *look_offset.begin() + 1;
- if (update_offset < start_mask.size()) {
- start_mask[update_offset] &= ~(1 << path_idx);
- }
- }
- path_idx++;
- }
-
- for (u32 i = 1; i < MULTIPATH_MAX_LEN; i++) {
- start_mask[i] &= start_mask[i - 1];
- DEBUG_PRINTF("start_mask[%u] = %x\n", i, start_mask[i]);
- }
-
- assert(look_offset.size() <= MULTIPATH_MAX_LEN);
-
- assert(last_start < 0);
-
- for (const auto &offset : look_offset) {
- vector<LookEntry> multi_entry;
- multi_entry.resize(MAX_LOOKAROUND_PATHS);
-
- for (size_t i = 0; i < multi_look.size(); i++) {
- for (const auto &t : multi_look[i]) {
- if (t.offset == offset) {
- multi_entry[i] = t;
- }
- }
- }
- ordered_look.emplace_back(multi_entry);
- }
-
- auto ri = std::make_unique<RoseInstrMultipathLookaround>(move(ordered_look),
- last_start, start_mask,
- program.end_instruction());
- program.add_before_end(move(ri));
-}
-
-static
-void makeRoleLookaround(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- RoseVertex v, RoseProgram &program) {
- if (!build.cc.grey.roseLookaroundMasks) {
- return;
- }
-
- vector<vector<LookEntry>> looks;
-
- // Lookaround from leftfix (mandatory).
- if (contains(leftfix_info, v) && leftfix_info.at(v).has_lookaround) {
- DEBUG_PRINTF("using leftfix lookaround\n");
- looks = leftfix_info.at(v).lookaround;
- }
-
- // We may be able to find more lookaround info (advisory) and merge it
- // in.
- if (looks.size() <= 1) {
- vector<LookEntry> look;
- vector<LookEntry> look_more;
- if (!looks.empty()) {
- look = move(looks.front());
- }
- findLookaroundMasks(build, v, look_more);
- mergeLookaround(look, look_more);
- if (!look.empty()) {
+}
+
+static
+bool hasDelayedLiteral(const RoseBuildImpl &build,
+ const vector<RoseEdge> &lit_edges) {
+ auto is_delayed = [&build](u32 lit_id) { return build.isDelayed(lit_id); };
+ for (const auto &e : lit_edges) {
+ auto v = target(e, build.g);
+ const auto &lits = build.g[v].literals;
+ if (any_of(begin(lits), end(lits), is_delayed)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static
+RoseProgram makeLitInitialProgram(const RoseBuildImpl &build,
+ ProgramBuild &prog_build, u32 lit_id,
+ const vector<RoseEdge> &lit_edges,
+ bool is_anchored_replay_program) {
+ RoseProgram program;
+
+ // Check long literal info.
+ if (!build.isDelayed(lit_id)) {
+ makeCheckLiteralInstruction(build.literals.at(lit_id),
+ prog_build.longLitLengthThreshold,
+ program, build.cc);
+ }
+
+ // Check lit mask.
+ makeCheckLitMaskInstruction(build, lit_id, program);
+
+ // Check literal groups. This is an optimisation that we only perform for
+ // delayed literals, as their groups may be switched off; ordinarily, we
+ // can trust the HWLM matcher.
+ if (hasDelayedLiteral(build, lit_edges)) {
+ makeGroupCheckInstruction(build, lit_id, program);
+ }
+
+ // Add instructions for pushing delayed matches, if there are any.
+ makePushDelayedInstructions(build.literals, prog_build,
+ build.literal_info.at(lit_id).delayed_ids,
+ program);
+
+ // Add pre-check for early literals in the floating table.
+ makeCheckLitEarlyInstruction(build, lit_id, lit_edges,
+ prog_build.floatingMinLiteralMatchOffset,
+ program);
+
+ /* Check if we are able to deliever matches from the anchored table now */
+ if (!is_anchored_replay_program) {
+ makeAnchoredLiteralDelay(build, prog_build, lit_id, program);
+ }
+
+ return program;
+}
+
+static
+bool makeRoleMultipathShufti(const vector<vector<LookEntry>> &multi_look,
+ RoseProgram &program) {
+ if (multi_look.empty()) {
+ return false;
+ }
+
+ // find the base offset
+ assert(!multi_look[0].empty());
+ s32 base_offset = multi_look[0].front().offset;
+ s32 last_start = base_offset;
+ s32 end_offset = multi_look[0].back().offset;
+ size_t multi_len = 0;
+
+ for (const auto &look : multi_look) {
+ assert(look.size() > 0);
+ multi_len += look.size();
+
+ LIMIT_TO_AT_MOST(&base_offset, look.front().offset);
+ ENSURE_AT_LEAST(&last_start, look.front().offset);
+ ENSURE_AT_LEAST(&end_offset, look.back().offset);
+ }
+
+ assert(last_start < 0);
+
+ if (end_offset - base_offset >= MULTIPATH_MAX_LEN) {
+ return false;
+ }
+
+ if (multi_len <= 16) {
+ multi_len = 16;
+ } else if (multi_len <= 32) {
+ multi_len = 32;
+ } else if (multi_len <= 64) {
+ multi_len = 64;
+ } else {
+ DEBUG_PRINTF("too long for multi-path\n");
+ return false;
+ }
+
+ vector<LookEntry> linear_look;
+ array<u8, 64> data_select_mask;
+ data_select_mask.fill(0);
+ u64a hi_bits_mask = 0;
+ u64a lo_bits_mask = 0;
+
+ for (const auto &look : multi_look) {
+ assert(linear_look.size() < 64);
+ lo_bits_mask |= 1LLU << linear_look.size();
+ for (const auto &entry : look) {
+ assert(entry.offset - base_offset < MULTIPATH_MAX_LEN);
+ data_select_mask[linear_look.size()] =
+ verify_u8(entry.offset - base_offset);
+ linear_look.emplace_back(verify_s8(linear_look.size()), entry.reach);
+ }
+ hi_bits_mask |= 1LLU << (linear_look.size() - 1);
+ }
+
+ u8 bit_index = 0; // number of buckets
+ u64a neg_mask;
+ array<u8, 32> hi_mask;
+ array<u8, 32> lo_mask;
+ array<u8, 64> bucket_select_hi;
+ array<u8, 64> bucket_select_lo;
+ hi_mask.fill(0);
+ lo_mask.fill(0);
+ bucket_select_hi.fill(0);
+ bucket_select_lo.fill(0);
+
+ if (!getShuftiMasks(linear_look, hi_mask, lo_mask, bucket_select_hi.data(),
+ bucket_select_lo.data(), neg_mask, bit_index,
+ multi_len)) {
+ return false;
+ }
+
+ DEBUG_PRINTF("hi_mask %s\n",
+ convertMaskstoString(hi_mask.data(), 16).c_str());
+ DEBUG_PRINTF("lo_mask %s\n",
+ convertMaskstoString(lo_mask.data(), 16).c_str());
+ DEBUG_PRINTF("bucket_select_hi %s\n",
+ convertMaskstoString(bucket_select_hi.data(), 64).c_str());
+ DEBUG_PRINTF("bucket_select_lo %s\n",
+ convertMaskstoString(bucket_select_lo.data(), 64).c_str());
+ DEBUG_PRINTF("data_select_mask %s\n",
+ convertMaskstoString(data_select_mask.data(), 64).c_str());
+ DEBUG_PRINTF("hi_bits_mask %llx\n", hi_bits_mask);
+ DEBUG_PRINTF("lo_bits_mask %llx\n", lo_bits_mask);
+ DEBUG_PRINTF("neg_mask %llx\n", neg_mask);
+ DEBUG_PRINTF("base_offset %d\n", base_offset);
+ DEBUG_PRINTF("last_start %d\n", last_start);
+
+ // Since we don't have 16x16 now, just call 32x16 instead.
+ if (bit_index > 8) {
+ assert(multi_len <= 32);
+ multi_len = 32;
+ }
+
+ const auto *end_inst = program.end_instruction();
+ assert(multi_len == 16 || multi_len == 32 || multi_len == 64);
+ if (multi_len == 16) {
+ neg_mask &= 0xffff;
+ assert(!(hi_bits_mask & ~0xffffULL));
+ assert(!(lo_bits_mask & ~0xffffULL));
+ assert(bit_index <=8);
+ array<u8, 32> nib_mask;
+ copy(begin(lo_mask), begin(lo_mask) + 16, nib_mask.begin());
+ copy(begin(hi_mask), begin(hi_mask) + 16, nib_mask.begin() + 16);
+
+ auto ri = std::make_unique<RoseInstrCheckMultipathShufti16x8>
+ (nib_mask, bucket_select_lo, data_select_mask, hi_bits_mask,
+ lo_bits_mask, neg_mask, base_offset, last_start, end_inst);
+ program.add_before_end(move(ri));
+ } else if (multi_len == 32) {
+ neg_mask &= 0xffffffff;
+ assert(!(hi_bits_mask & ~0xffffffffULL));
+ assert(!(lo_bits_mask & ~0xffffffffULL));
+ if (bit_index <= 8) {
+ auto ri = std::make_unique<RoseInstrCheckMultipathShufti32x8>
+ (hi_mask, lo_mask, bucket_select_lo, data_select_mask,
+ hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
+ last_start, end_inst);
+ program.add_before_end(move(ri));
+ } else {
+ auto ri = std::make_unique<RoseInstrCheckMultipathShufti32x16>
+ (hi_mask, lo_mask, bucket_select_hi, bucket_select_lo,
+ data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
+ base_offset, last_start, end_inst);
+ program.add_before_end(move(ri));
+ }
+ } else {
+ auto ri = std::make_unique<RoseInstrCheckMultipathShufti64>
+ (hi_mask, lo_mask, bucket_select_lo, data_select_mask,
+ hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
+ last_start, end_inst);
+ program.add_before_end(move(ri));
+ }
+ return true;
+}
+
+static
+void makeRoleMultipathLookaround(const vector<vector<LookEntry>> &multi_look,
+ RoseProgram &program) {
+ assert(!multi_look.empty());
+ assert(multi_look.size() <= MAX_LOOKAROUND_PATHS);
+ vector<vector<LookEntry>> ordered_look;
+ set<s32> look_offset;
+
+ assert(!multi_look[0].empty());
+ s32 last_start = multi_look[0][0].offset;
+
+ // build offset table.
+ for (const auto &look : multi_look) {
+ assert(look.size() > 0);
+ last_start = max(last_start, (s32)look.begin()->offset);
+
+ for (const auto &t : look) {
+ look_offset.insert(t.offset);
+ }
+ }
+
+ array<u8, MULTIPATH_MAX_LEN> start_mask;
+ if (multi_look.size() < MAX_LOOKAROUND_PATHS) {
+ start_mask.fill((1 << multi_look.size()) - 1);
+ } else {
+ start_mask.fill(0xff);
+ }
+
+ u32 path_idx = 0;
+ for (const auto &look : multi_look) {
+ for (const auto &t : look) {
+ assert(t.offset >= (int)*look_offset.begin());
+ size_t update_offset = t.offset - *look_offset.begin() + 1;
+ if (update_offset < start_mask.size()) {
+ start_mask[update_offset] &= ~(1 << path_idx);
+ }
+ }
+ path_idx++;
+ }
+
+ for (u32 i = 1; i < MULTIPATH_MAX_LEN; i++) {
+ start_mask[i] &= start_mask[i - 1];
+ DEBUG_PRINTF("start_mask[%u] = %x\n", i, start_mask[i]);
+ }
+
+ assert(look_offset.size() <= MULTIPATH_MAX_LEN);
+
+ assert(last_start < 0);
+
+ for (const auto &offset : look_offset) {
+ vector<LookEntry> multi_entry;
+ multi_entry.resize(MAX_LOOKAROUND_PATHS);
+
+ for (size_t i = 0; i < multi_look.size(); i++) {
+ for (const auto &t : multi_look[i]) {
+ if (t.offset == offset) {
+ multi_entry[i] = t;
+ }
+ }
+ }
+ ordered_look.emplace_back(multi_entry);
+ }
+
+ auto ri = std::make_unique<RoseInstrMultipathLookaround>(move(ordered_look),
+ last_start, start_mask,
+ program.end_instruction());
+ program.add_before_end(move(ri));
+}
+
+static
+void makeRoleLookaround(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ RoseVertex v, RoseProgram &program) {
+ if (!build.cc.grey.roseLookaroundMasks) {
+ return;
+ }
+
+ vector<vector<LookEntry>> looks;
+
+ // Lookaround from leftfix (mandatory).
+ if (contains(leftfix_info, v) && leftfix_info.at(v).has_lookaround) {
+ DEBUG_PRINTF("using leftfix lookaround\n");
+ looks = leftfix_info.at(v).lookaround;
+ }
+
+ // We may be able to find more lookaround info (advisory) and merge it
+ // in.
+ if (looks.size() <= 1) {
+ vector<LookEntry> look;
+ vector<LookEntry> look_more;
+ if (!looks.empty()) {
+ look = move(looks.front());
+ }
+ findLookaroundMasks(build, v, look_more);
+ mergeLookaround(look, look_more);
+ if (!look.empty()) {
makeLookaroundInstruction(look, program, build.cc.target_info);
- }
- return;
- }
-
- if (!makeRoleMultipathShufti(looks, program)) {
- assert(looks.size() <= 8);
- makeRoleMultipathLookaround(looks, program);
- }
-}
-
-static
-void makeRoleSuffix(const RoseBuildImpl &build,
- const map<suffix_id, u32> &suffixes,
- const map<u32, engine_info> &engine_info_by_queue,
- RoseVertex v, RoseProgram &prog) {
- const auto &g = build.g;
- if (!g[v].suffix) {
- return;
- }
- assert(contains(suffixes, g[v].suffix));
- u32 queue = suffixes.at(g[v].suffix);
- u32 event;
- assert(contains(engine_info_by_queue, queue));
- const auto eng_info = engine_info_by_queue.at(queue);
- if (isContainerType(eng_info.type)) {
- auto tamaProto = g[v].suffix.tamarama.get();
- assert(tamaProto);
- event = (u32)MQE_TOP_FIRST +
- tamaProto->top_remap.at(make_pair(g[v].index,
- g[v].suffix.top));
- assert(event < MQE_INVALID);
- } else if (isMultiTopType(eng_info.type)) {
- assert(!g[v].suffix.haig);
- event = (u32)MQE_TOP_FIRST + g[v].suffix.top;
- assert(event < MQE_INVALID);
- } else {
- // DFAs/Puffs have no MQE_TOP_N support, so they get a classic TOP
- // event.
- assert(!g[v].suffix.graph || onlyOneTop(*g[v].suffix.graph));
- event = MQE_TOP;
- }
-
+ }
+ return;
+ }
+
+ if (!makeRoleMultipathShufti(looks, program)) {
+ assert(looks.size() <= 8);
+ makeRoleMultipathLookaround(looks, program);
+ }
+}
+
+static
+void makeRoleSuffix(const RoseBuildImpl &build,
+ const map<suffix_id, u32> &suffixes,
+ const map<u32, engine_info> &engine_info_by_queue,
+ RoseVertex v, RoseProgram &prog) {
+ const auto &g = build.g;
+ if (!g[v].suffix) {
+ return;
+ }
+ assert(contains(suffixes, g[v].suffix));
+ u32 queue = suffixes.at(g[v].suffix);
+ u32 event;
+ assert(contains(engine_info_by_queue, queue));
+ const auto eng_info = engine_info_by_queue.at(queue);
+ if (isContainerType(eng_info.type)) {
+ auto tamaProto = g[v].suffix.tamarama.get();
+ assert(tamaProto);
+ event = (u32)MQE_TOP_FIRST +
+ tamaProto->top_remap.at(make_pair(g[v].index,
+ g[v].suffix.top));
+ assert(event < MQE_INVALID);
+ } else if (isMultiTopType(eng_info.type)) {
+ assert(!g[v].suffix.haig);
+ event = (u32)MQE_TOP_FIRST + g[v].suffix.top;
+ assert(event < MQE_INVALID);
+ } else {
+ // DFAs/Puffs have no MQE_TOP_N support, so they get a classic TOP
+ // event.
+ assert(!g[v].suffix.graph || onlyOneTop(*g[v].suffix.graph));
+ event = MQE_TOP;
+ }
+
prog.add_before_end(std::make_unique<RoseInstrTriggerSuffix>(queue, event));
-}
-
-static
-void addInfixTriggerInstructions(vector<TriggerInfo> triggers,
- RoseProgram &prog) {
- // Order, de-dupe and add instructions to the end of program.
- sort_and_unique(triggers, [](const TriggerInfo &a, const TriggerInfo &b) {
- return tie(a.cancel, a.queue, a.event) <
- tie(b.cancel, b.queue, b.event);
- });
- for (const auto &ti : triggers) {
- prog.add_before_end(
- std::make_unique<RoseInstrTriggerInfix>(ti.cancel, ti.queue, ti.event));
- }
-}
-
-static
-void makeRoleInfixTriggers(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- const map<u32, engine_info> &engine_info_by_queue,
- RoseVertex u, RoseProgram &program) {
- const auto &g = build.g;
-
- vector<TriggerInfo> triggers;
-
- for (const auto &e : out_edges_range(u, g)) {
- RoseVertex v = target(e, g);
- if (!g[v].left) {
- continue;
- }
-
- assert(contains(leftfix_info, v));
- const left_build_info &lbi = leftfix_info.at(v);
- if (lbi.has_lookaround) {
- continue;
- }
-
- assert(contains(engine_info_by_queue, lbi.queue));
- const auto &eng_info = engine_info_by_queue.at(lbi.queue);
-
- // DFAs have no TOP_N support, so they get a classic MQE_TOP event.
- u32 top;
- if (isContainerType(eng_info.type)) {
- auto tamaProto = g[v].left.tamarama.get();
- assert(tamaProto);
- top = MQE_TOP_FIRST + tamaProto->top_remap.at(
- make_pair(g[v].index, g[e].rose_top));
- assert(top < MQE_INVALID);
- } else if (!isMultiTopType(eng_info.type)) {
- assert(num_tops(g[v].left) == 1);
- top = MQE_TOP;
- } else {
- top = MQE_TOP_FIRST + g[e].rose_top;
- assert(top < MQE_INVALID);
- }
-
- triggers.emplace_back(g[e].rose_cancel_prev_top, lbi.queue, top);
- }
-
- addInfixTriggerInstructions(move(triggers), program);
-}
-
-
-/**
- * \brief True if the given vertex is a role that can only be switched on at
- * EOD.
- */
-static
-bool onlyAtEod(const RoseBuildImpl &tbi, RoseVertex v) {
- const RoseGraph &g = tbi.g;
-
- // All such roles have only (0,0) edges to vertices with the eod_accept
- // property, and no other effects (suffixes, ordinary reports, etc, etc).
-
- if (isLeafNode(v, g) || !g[v].reports.empty() || g[v].suffix) {
- return false;
- }
-
- for (const auto &e : out_edges_range(v, g)) {
- RoseVertex w = target(e, g);
- if (!g[w].eod_accept) {
- return false;
- }
- assert(!g[w].reports.empty());
- assert(g[w].literals.empty());
-
- if (g[e].minBound || g[e].maxBound) {
- return false;
- }
- }
-
- /* There is no pointing enforcing this check at runtime if
- * this role is only fired by the eod event literal */
- if (tbi.eod_event_literal_id != MO_INVALID_IDX &&
- g[v].literals.size() == 1 &&
- *g[v].literals.begin() == tbi.eod_event_literal_id) {
- return false;
- }
-
- return true;
-}
-
-static
-void addCheckOnlyEodInstruction(RoseProgram &prog) {
- DEBUG_PRINTF("only at eod\n");
- const auto *end_inst = prog.end_instruction();
+}
+
+static
+void addInfixTriggerInstructions(vector<TriggerInfo> triggers,
+ RoseProgram &prog) {
+ // Order, de-dupe and add instructions to the end of program.
+ sort_and_unique(triggers, [](const TriggerInfo &a, const TriggerInfo &b) {
+ return tie(a.cancel, a.queue, a.event) <
+ tie(b.cancel, b.queue, b.event);
+ });
+ for (const auto &ti : triggers) {
+ prog.add_before_end(
+ std::make_unique<RoseInstrTriggerInfix>(ti.cancel, ti.queue, ti.event));
+ }
+}
+
+static
+void makeRoleInfixTriggers(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ const map<u32, engine_info> &engine_info_by_queue,
+ RoseVertex u, RoseProgram &program) {
+ const auto &g = build.g;
+
+ vector<TriggerInfo> triggers;
+
+ for (const auto &e : out_edges_range(u, g)) {
+ RoseVertex v = target(e, g);
+ if (!g[v].left) {
+ continue;
+ }
+
+ assert(contains(leftfix_info, v));
+ const left_build_info &lbi = leftfix_info.at(v);
+ if (lbi.has_lookaround) {
+ continue;
+ }
+
+ assert(contains(engine_info_by_queue, lbi.queue));
+ const auto &eng_info = engine_info_by_queue.at(lbi.queue);
+
+ // DFAs have no TOP_N support, so they get a classic MQE_TOP event.
+ u32 top;
+ if (isContainerType(eng_info.type)) {
+ auto tamaProto = g[v].left.tamarama.get();
+ assert(tamaProto);
+ top = MQE_TOP_FIRST + tamaProto->top_remap.at(
+ make_pair(g[v].index, g[e].rose_top));
+ assert(top < MQE_INVALID);
+ } else if (!isMultiTopType(eng_info.type)) {
+ assert(num_tops(g[v].left) == 1);
+ top = MQE_TOP;
+ } else {
+ top = MQE_TOP_FIRST + g[e].rose_top;
+ assert(top < MQE_INVALID);
+ }
+
+ triggers.emplace_back(g[e].rose_cancel_prev_top, lbi.queue, top);
+ }
+
+ addInfixTriggerInstructions(move(triggers), program);
+}
+
+
+/**
+ * \brief True if the given vertex is a role that can only be switched on at
+ * EOD.
+ */
+static
+bool onlyAtEod(const RoseBuildImpl &tbi, RoseVertex v) {
+ const RoseGraph &g = tbi.g;
+
+ // All such roles have only (0,0) edges to vertices with the eod_accept
+ // property, and no other effects (suffixes, ordinary reports, etc, etc).
+
+ if (isLeafNode(v, g) || !g[v].reports.empty() || g[v].suffix) {
+ return false;
+ }
+
+ for (const auto &e : out_edges_range(v, g)) {
+ RoseVertex w = target(e, g);
+ if (!g[w].eod_accept) {
+ return false;
+ }
+ assert(!g[w].reports.empty());
+ assert(g[w].literals.empty());
+
+ if (g[e].minBound || g[e].maxBound) {
+ return false;
+ }
+ }
+
+ /* There is no pointing enforcing this check at runtime if
+ * this role is only fired by the eod event literal */
+ if (tbi.eod_event_literal_id != MO_INVALID_IDX &&
+ g[v].literals.size() == 1 &&
+ *g[v].literals.begin() == tbi.eod_event_literal_id) {
+ return false;
+ }
+
+ return true;
+}
+
+static
+void addCheckOnlyEodInstruction(RoseProgram &prog) {
+ DEBUG_PRINTF("only at eod\n");
+ const auto *end_inst = prog.end_instruction();
prog.add_before_end(std::make_unique<RoseInstrCheckOnlyEod>(end_inst));
-}
-
-static
-void makeRoleEagerEodReports(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- bool needs_catchup, RoseVertex v,
- RoseProgram &program) {
- RoseProgram eod_program;
-
- for (const auto &e : out_edges_range(v, build.g)) {
- if (canEagerlyReportAtEod(build, e)) {
- RoseProgram block;
- makeRoleReports(build, leftfix_info, needs_catchup,
- target(e, build.g), block);
- eod_program.add_block(move(block));
- }
- }
-
- if (eod_program.empty()) {
- return;
- }
-
- if (!onlyAtEod(build, v)) {
- // The rest of our program wasn't EOD anchored, so we need to guard
- // these reports with a check.
- addCheckOnlyEodInstruction(program);
- }
-
- program.add_before_end(move(eod_program));
-}
-
+}
+
+static
+void makeRoleEagerEodReports(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ bool needs_catchup, RoseVertex v,
+ RoseProgram &program) {
+ RoseProgram eod_program;
+
+ for (const auto &e : out_edges_range(v, build.g)) {
+ if (canEagerlyReportAtEod(build, e)) {
+ RoseProgram block;
+ makeRoleReports(build, leftfix_info, needs_catchup,
+ target(e, build.g), block);
+ eod_program.add_block(move(block));
+ }
+ }
+
+ if (eod_program.empty()) {
+ return;
+ }
+
+ if (!onlyAtEod(build, v)) {
+ // The rest of our program wasn't EOD anchored, so we need to guard
+ // these reports with a check.
+ addCheckOnlyEodInstruction(program);
+ }
+
+ program.add_before_end(move(eod_program));
+}
+
/** Makes a program for a role/vertex given a specific pred/in_edge. */
-static
-RoseProgram makeRoleProgram(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- const map<suffix_id, u32> &suffixes,
- const map<u32, engine_info> &engine_info_by_queue,
- const unordered_map<RoseVertex, u32> &roleStateIndices,
- ProgramBuild &prog_build, const RoseEdge &e) {
- const RoseGraph &g = build.g;
- auto v = target(e, g);
-
- RoseProgram program;
-
- // First, add program instructions that enforce preconditions without
- // effects.
-
- if (onlyAtEod(build, v)) {
- addCheckOnlyEodInstruction(program);
- }
-
- if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
- makeRoleCheckBounds(build, v, e, program);
- }
-
- // This role program may be triggered by different predecessors, with
- // different offset bounds. We must ensure we put this check/set operation
- // after the bounds check to deal with this case.
- if (in_degree(v, g) > 1) {
- assert(!build.isRootSuccessor(v));
- makeRoleCheckNotHandled(prog_build, v, program);
- }
-
- makeRoleLookaround(build, leftfix_info, v, program);
- makeRoleCheckLeftfix(build, leftfix_info, v, program);
-
- // Next, we can add program instructions that have effects. This must be
- // done as a series of blocks, as some of them (like reports) are
- // escapable.
-
- RoseProgram effects_block;
-
- RoseProgram reports_block;
- makeRoleReports(build, leftfix_info, prog_build.needs_catchup, v,
- reports_block);
- effects_block.add_block(move(reports_block));
-
- RoseProgram infix_block;
- makeRoleInfixTriggers(build, leftfix_info, engine_info_by_queue, v,
- infix_block);
- effects_block.add_block(move(infix_block));
-
- // Note: SET_GROUPS instruction must be after infix triggers, as an infix
- // going dead may switch off groups.
- RoseProgram groups_block;
- makeRoleGroups(build.g, prog_build, v, groups_block);
- effects_block.add_block(move(groups_block));
-
- RoseProgram suffix_block;
- makeRoleSuffix(build, suffixes, engine_info_by_queue, v, suffix_block);
- effects_block.add_block(move(suffix_block));
-
- RoseProgram state_block;
- makeRoleSetState(roleStateIndices, v, state_block);
- effects_block.add_block(move(state_block));
-
- // Note: EOD eager reports may generate a CHECK_ONLY_EOD instruction (if
- // the program doesn't have one already).
- RoseProgram eod_block;
- makeRoleEagerEodReports(build, leftfix_info, prog_build.needs_catchup, v,
- eod_block);
- effects_block.add_block(move(eod_block));
-
- /* a 'ghost role' may do nothing if we know that its groups are already set
- * - in this case we can avoid producing a program at all. */
- if (effects_block.empty()) {
- return {};
- }
-
- program.add_before_end(move(effects_block));
- return program;
-}
-
-static
-void makeGroupSquashInstruction(const RoseBuildImpl &build, u32 lit_id,
- RoseProgram &prog) {
- const auto &info = build.literal_info.at(lit_id);
- if (!info.squash_group) {
- return;
- }
-
- DEBUG_PRINTF("squashes 0x%llx\n", info.group_mask);
- assert(info.group_mask);
- /* Note: group_mask is negated. */
+static
+RoseProgram makeRoleProgram(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ const map<suffix_id, u32> &suffixes,
+ const map<u32, engine_info> &engine_info_by_queue,
+ const unordered_map<RoseVertex, u32> &roleStateIndices,
+ ProgramBuild &prog_build, const RoseEdge &e) {
+ const RoseGraph &g = build.g;
+ auto v = target(e, g);
+
+ RoseProgram program;
+
+ // First, add program instructions that enforce preconditions without
+ // effects.
+
+ if (onlyAtEod(build, v)) {
+ addCheckOnlyEodInstruction(program);
+ }
+
+ if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
+ makeRoleCheckBounds(build, v, e, program);
+ }
+
+ // This role program may be triggered by different predecessors, with
+ // different offset bounds. We must ensure we put this check/set operation
+ // after the bounds check to deal with this case.
+ if (in_degree(v, g) > 1) {
+ assert(!build.isRootSuccessor(v));
+ makeRoleCheckNotHandled(prog_build, v, program);
+ }
+
+ makeRoleLookaround(build, leftfix_info, v, program);
+ makeRoleCheckLeftfix(build, leftfix_info, v, program);
+
+ // Next, we can add program instructions that have effects. This must be
+ // done as a series of blocks, as some of them (like reports) are
+ // escapable.
+
+ RoseProgram effects_block;
+
+ RoseProgram reports_block;
+ makeRoleReports(build, leftfix_info, prog_build.needs_catchup, v,
+ reports_block);
+ effects_block.add_block(move(reports_block));
+
+ RoseProgram infix_block;
+ makeRoleInfixTriggers(build, leftfix_info, engine_info_by_queue, v,
+ infix_block);
+ effects_block.add_block(move(infix_block));
+
+ // Note: SET_GROUPS instruction must be after infix triggers, as an infix
+ // going dead may switch off groups.
+ RoseProgram groups_block;
+ makeRoleGroups(build.g, prog_build, v, groups_block);
+ effects_block.add_block(move(groups_block));
+
+ RoseProgram suffix_block;
+ makeRoleSuffix(build, suffixes, engine_info_by_queue, v, suffix_block);
+ effects_block.add_block(move(suffix_block));
+
+ RoseProgram state_block;
+ makeRoleSetState(roleStateIndices, v, state_block);
+ effects_block.add_block(move(state_block));
+
+ // Note: EOD eager reports may generate a CHECK_ONLY_EOD instruction (if
+ // the program doesn't have one already).
+ RoseProgram eod_block;
+ makeRoleEagerEodReports(build, leftfix_info, prog_build.needs_catchup, v,
+ eod_block);
+ effects_block.add_block(move(eod_block));
+
+ /* a 'ghost role' may do nothing if we know that its groups are already set
+ * - in this case we can avoid producing a program at all. */
+ if (effects_block.empty()) {
+ return {};
+ }
+
+ program.add_before_end(move(effects_block));
+ return program;
+}
+
+static
+void makeGroupSquashInstruction(const RoseBuildImpl &build, u32 lit_id,
+ RoseProgram &prog) {
+ const auto &info = build.literal_info.at(lit_id);
+ if (!info.squash_group) {
+ return;
+ }
+
+ DEBUG_PRINTF("squashes 0x%llx\n", info.group_mask);
+ assert(info.group_mask);
+ /* Note: group_mask is negated. */
prog.add_before_end(std::make_unique<RoseInstrSquashGroups>(~info.group_mask));
-}
-
-namespace {
-struct ProgKey {
- ProgKey(const RoseProgram &p) : prog(&p) {}
-
- bool operator==(const ProgKey &b) const {
- return RoseProgramEquivalence()(*prog, *b.prog);
- }
-
- size_t hash() const {
- return RoseProgramHash()(*prog);
- }
-private:
- const RoseProgram *prog;
-};
-}
-
-RoseProgram assembleProgramBlocks(vector<RoseProgram> &&blocks_in) {
- DEBUG_PRINTF("%zu blocks before dedupe\n", blocks_in.size());
-
- vector<RoseProgram> blocks;
- blocks.reserve(blocks_in.size()); /* to ensure stable reference for seen */
-
- ue2_unordered_set<ProgKey> seen;
- for (auto &block : blocks_in) {
- if (contains(seen, block)) {
- continue;
- }
-
- blocks.push_back(move(block));
- seen.emplace(blocks.back());
- }
-
- DEBUG_PRINTF("%zu blocks after dedupe\n", blocks.size());
-
- RoseProgram prog;
- for (auto &block : blocks) {
- /* If we have multiple blocks from different literals and any of them
- * squash groups, we will have to add a CLEAR_WORK_DONE instruction to
- * each literal program block to clear the work_done flags so that it's
- * only set if a state has been. */
- if (!prog.empty() && reads_work_done_flag(block)) {
- RoseProgram clear_block;
+}
+
+namespace {
+struct ProgKey {
+ ProgKey(const RoseProgram &p) : prog(&p) {}
+
+ bool operator==(const ProgKey &b) const {
+ return RoseProgramEquivalence()(*prog, *b.prog);
+ }
+
+ size_t hash() const {
+ return RoseProgramHash()(*prog);
+ }
+private:
+ const RoseProgram *prog;
+};
+}
+
+RoseProgram assembleProgramBlocks(vector<RoseProgram> &&blocks_in) {
+ DEBUG_PRINTF("%zu blocks before dedupe\n", blocks_in.size());
+
+ vector<RoseProgram> blocks;
+ blocks.reserve(blocks_in.size()); /* to ensure stable reference for seen */
+
+ ue2_unordered_set<ProgKey> seen;
+ for (auto &block : blocks_in) {
+ if (contains(seen, block)) {
+ continue;
+ }
+
+ blocks.push_back(move(block));
+ seen.emplace(blocks.back());
+ }
+
+ DEBUG_PRINTF("%zu blocks after dedupe\n", blocks.size());
+
+ RoseProgram prog;
+ for (auto &block : blocks) {
+ /* If we have multiple blocks from different literals and any of them
+ * squash groups, we will have to add a CLEAR_WORK_DONE instruction to
+ * each literal program block to clear the work_done flags so that it's
+ * only set if a state has been. */
+ if (!prog.empty() && reads_work_done_flag(block)) {
+ RoseProgram clear_block;
clear_block.add_before_end(std::make_unique<RoseInstrClearWorkDone>());
- prog.add_block(move(clear_block));
- }
-
- prog.add_block(move(block));
- }
-
- return prog;
-}
-
-RoseProgram makeLiteralProgram(const RoseBuildImpl &build,
- const map<RoseVertex, left_build_info> &leftfix_info,
- const map<suffix_id, u32> &suffixes,
- const map<u32, engine_info> &engine_info_by_queue,
- const unordered_map<RoseVertex, u32> &roleStateIndices,
- ProgramBuild &prog_build, u32 lit_id,
- const vector<RoseEdge> &lit_edges,
- bool is_anchored_replay_program) {
- const auto &g = build.g;
-
- DEBUG_PRINTF("lit id=%u, %zu lit edges\n", lit_id, lit_edges.size());
-
- // Construct initial program up front, as its early checks must be able
- // to jump to end and terminate processing for this literal.
- auto lit_program = makeLitInitialProgram(build, prog_build, lit_id,
- lit_edges,
- is_anchored_replay_program);
-
- RoseProgram role_programs;
-
- // Predecessor state id -> program block.
- map<u32, RoseProgram> pred_blocks;
-
- // Construct sparse iter sub-programs.
- for (const auto &e : lit_edges) {
- const auto &u = source(e, g);
- if (build.isAnyStart(u)) {
- continue; // Root roles are not handled with sparse iterator.
- }
- DEBUG_PRINTF("sparse iter edge (%zu,%zu)\n", g[u].index,
- g[target(e, g)].index);
- assert(contains(roleStateIndices, u));
- u32 pred_state = roleStateIndices.at(u);
- auto role_prog = makeRoleProgram(build, leftfix_info, suffixes,
- engine_info_by_queue, roleStateIndices,
- prog_build, e);
- if (!role_prog.empty()) {
- pred_blocks[pred_state].add_block(move(role_prog));
- }
- }
-
- // Add blocks to deal with non-root edges (triggered by sparse iterator or
- // mmbit_isset checks).
- addPredBlocks(pred_blocks, roleStateIndices.size(), role_programs);
-
- // Add blocks to handle root roles.
- for (const auto &e : lit_edges) {
- const auto &u = source(e, g);
- if (!build.isAnyStart(u)) {
- continue;
- }
- DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].index,
- g[target(e, g)].index);
- auto role_prog = makeRoleProgram(build, leftfix_info, suffixes,
- engine_info_by_queue, roleStateIndices,
- prog_build, e);
- role_programs.add_block(move(role_prog));
- }
-
- if (lit_id == build.eod_event_literal_id) {
+ prog.add_block(move(clear_block));
+ }
+
+ prog.add_block(move(block));
+ }
+
+ return prog;
+}
+
+RoseProgram makeLiteralProgram(const RoseBuildImpl &build,
+ const map<RoseVertex, left_build_info> &leftfix_info,
+ const map<suffix_id, u32> &suffixes,
+ const map<u32, engine_info> &engine_info_by_queue,
+ const unordered_map<RoseVertex, u32> &roleStateIndices,
+ ProgramBuild &prog_build, u32 lit_id,
+ const vector<RoseEdge> &lit_edges,
+ bool is_anchored_replay_program) {
+ const auto &g = build.g;
+
+ DEBUG_PRINTF("lit id=%u, %zu lit edges\n", lit_id, lit_edges.size());
+
+ // Construct initial program up front, as its early checks must be able
+ // to jump to end and terminate processing for this literal.
+ auto lit_program = makeLitInitialProgram(build, prog_build, lit_id,
+ lit_edges,
+ is_anchored_replay_program);
+
+ RoseProgram role_programs;
+
+ // Predecessor state id -> program block.
+ map<u32, RoseProgram> pred_blocks;
+
+ // Construct sparse iter sub-programs.
+ for (const auto &e : lit_edges) {
+ const auto &u = source(e, g);
+ if (build.isAnyStart(u)) {
+ continue; // Root roles are not handled with sparse iterator.
+ }
+ DEBUG_PRINTF("sparse iter edge (%zu,%zu)\n", g[u].index,
+ g[target(e, g)].index);
+ assert(contains(roleStateIndices, u));
+ u32 pred_state = roleStateIndices.at(u);
+ auto role_prog = makeRoleProgram(build, leftfix_info, suffixes,
+ engine_info_by_queue, roleStateIndices,
+ prog_build, e);
+ if (!role_prog.empty()) {
+ pred_blocks[pred_state].add_block(move(role_prog));
+ }
+ }
+
+ // Add blocks to deal with non-root edges (triggered by sparse iterator or
+ // mmbit_isset checks).
+ addPredBlocks(pred_blocks, roleStateIndices.size(), role_programs);
+
+ // Add blocks to handle root roles.
+ for (const auto &e : lit_edges) {
+ const auto &u = source(e, g);
+ if (!build.isAnyStart(u)) {
+ continue;
+ }
+ DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].index,
+ g[target(e, g)].index);
+ auto role_prog = makeRoleProgram(build, leftfix_info, suffixes,
+ engine_info_by_queue, roleStateIndices,
+ prog_build, e);
+ role_programs.add_block(move(role_prog));
+ }
+
+ if (lit_id == build.eod_event_literal_id) {
/* Note: does not require the lit initial program */
- assert(build.eod_event_literal_id != MO_INVALID_IDX);
- return role_programs;
- }
-
- /* Instructions to run even if a role program bails out */
- RoseProgram unconditional_block;
-
- // Literal may squash groups.
- makeGroupSquashInstruction(build, lit_id, unconditional_block);
-
- role_programs.add_block(move(unconditional_block));
- lit_program.add_before_end(move(role_programs));
-
- return lit_program;
-}
-
-RoseProgram makeDelayRebuildProgram(const RoseBuildImpl &build,
- ProgramBuild &prog_build,
- const vector<u32> &lit_ids) {
- assert(!lit_ids.empty());
- assert(build.cc.streaming);
-
- vector<RoseProgram> blocks;
-
- for (const auto &lit_id : lit_ids) {
- DEBUG_PRINTF("lit_id=%u\n", lit_id);
- const auto &info = build.literal_info.at(lit_id);
- if (info.delayed_ids.empty()) {
- continue; // No delayed IDs, no work to do.
- }
-
- RoseProgram prog;
- if (!build.isDelayed(lit_id)) {
- makeCheckLiteralInstruction(build.literals.at(lit_id),
- prog_build.longLitLengthThreshold, prog,
- build.cc);
- }
-
- makeCheckLitMaskInstruction(build, lit_id, prog);
- makePushDelayedInstructions(build.literals, prog_build,
- build.literal_info.at(lit_id).delayed_ids,
- prog);
- blocks.push_back(move(prog));
- }
-
- return assembleProgramBlocks(move(blocks));
-}
-
-RoseProgram makeEodAnchorProgram(const RoseBuildImpl &build,
- ProgramBuild &prog_build, const RoseEdge &e,
- const bool multiple_preds) {
- const RoseGraph &g = build.g;
- const RoseVertex v = target(e, g);
-
- RoseProgram program;
-
- if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
- makeRoleCheckBounds(build, v, e, program);
- }
-
- if (multiple_preds) {
- // Only necessary when there is more than one pred.
- makeRoleCheckNotHandled(prog_build, v, program);
- }
-
- makeCatchup(build.rm, prog_build.needs_catchup, g[v].reports, program);
-
- const bool has_som = false;
- RoseProgram report_block;
- for (const auto &id : g[v].reports) {
- makeReport(build, id, has_som, report_block);
- }
- program.add_before_end(move(report_block));
-
- return program;
-}
-
-static
-void makeCatchupMpv(const ReportManager &rm, bool needs_mpv_catchup,
- ReportID id, RoseProgram &program) {
- if (!needs_mpv_catchup) {
- return;
- }
-
- const Report &report = rm.getReport(id);
- if (report.type == INTERNAL_ROSE_CHAIN) {
- return;
- }
-
+ assert(build.eod_event_literal_id != MO_INVALID_IDX);
+ return role_programs;
+ }
+
+ /* Instructions to run even if a role program bails out */
+ RoseProgram unconditional_block;
+
+ // Literal may squash groups.
+ makeGroupSquashInstruction(build, lit_id, unconditional_block);
+
+ role_programs.add_block(move(unconditional_block));
+ lit_program.add_before_end(move(role_programs));
+
+ return lit_program;
+}
+
+RoseProgram makeDelayRebuildProgram(const RoseBuildImpl &build,
+ ProgramBuild &prog_build,
+ const vector<u32> &lit_ids) {
+ assert(!lit_ids.empty());
+ assert(build.cc.streaming);
+
+ vector<RoseProgram> blocks;
+
+ for (const auto &lit_id : lit_ids) {
+ DEBUG_PRINTF("lit_id=%u\n", lit_id);
+ const auto &info = build.literal_info.at(lit_id);
+ if (info.delayed_ids.empty()) {
+ continue; // No delayed IDs, no work to do.
+ }
+
+ RoseProgram prog;
+ if (!build.isDelayed(lit_id)) {
+ makeCheckLiteralInstruction(build.literals.at(lit_id),
+ prog_build.longLitLengthThreshold, prog,
+ build.cc);
+ }
+
+ makeCheckLitMaskInstruction(build, lit_id, prog);
+ makePushDelayedInstructions(build.literals, prog_build,
+ build.literal_info.at(lit_id).delayed_ids,
+ prog);
+ blocks.push_back(move(prog));
+ }
+
+ return assembleProgramBlocks(move(blocks));
+}
+
+RoseProgram makeEodAnchorProgram(const RoseBuildImpl &build,
+ ProgramBuild &prog_build, const RoseEdge &e,
+ const bool multiple_preds) {
+ const RoseGraph &g = build.g;
+ const RoseVertex v = target(e, g);
+
+ RoseProgram program;
+
+ if (g[e].history == ROSE_ROLE_HISTORY_ANCH) {
+ makeRoleCheckBounds(build, v, e, program);
+ }
+
+ if (multiple_preds) {
+ // Only necessary when there is more than one pred.
+ makeRoleCheckNotHandled(prog_build, v, program);
+ }
+
+ makeCatchup(build.rm, prog_build.needs_catchup, g[v].reports, program);
+
+ const bool has_som = false;
+ RoseProgram report_block;
+ for (const auto &id : g[v].reports) {
+ makeReport(build, id, has_som, report_block);
+ }
+ program.add_before_end(move(report_block));
+
+ return program;
+}
+
+static
+void makeCatchupMpv(const ReportManager &rm, bool needs_mpv_catchup,
+ ReportID id, RoseProgram &program) {
+ if (!needs_mpv_catchup) {
+ return;
+ }
+
+ const Report &report = rm.getReport(id);
+ if (report.type == INTERNAL_ROSE_CHAIN) {
+ return;
+ }
+
program.add_before_end(std::make_unique<RoseInstrCatchUpMpv>());
-}
-
-RoseProgram makeReportProgram(const RoseBuildImpl &build,
- bool needs_mpv_catchup, ReportID id) {
- RoseProgram prog;
-
- makeCatchupMpv(build.rm, needs_mpv_catchup, id, prog);
-
- const bool has_som = false;
- makeReport(build, id, has_som, prog);
-
- return prog;
-}
-
-RoseProgram makeBoundaryProgram(const RoseBuildImpl &build,
- const set<ReportID> &reports) {
- // Note: no CATCHUP instruction is necessary in the boundary case, as we
- // should always be caught up (and may not even have the resources in
- // scratch to support it).
-
- const bool has_som = false;
- RoseProgram prog;
- for (const auto &id : reports) {
- makeReport(build, id, has_som, prog);
- }
-
- return prog;
-}
-
-void addIncludedJumpProgram(RoseProgram &program, u32 child_offset,
- u8 squash) {
- RoseProgram block;
+}
+
+RoseProgram makeReportProgram(const RoseBuildImpl &build,
+ bool needs_mpv_catchup, ReportID id) {
+ RoseProgram prog;
+
+ makeCatchupMpv(build.rm, needs_mpv_catchup, id, prog);
+
+ const bool has_som = false;
+ makeReport(build, id, has_som, prog);
+
+ return prog;
+}
+
+RoseProgram makeBoundaryProgram(const RoseBuildImpl &build,
+ const set<ReportID> &reports) {
+ // Note: no CATCHUP instruction is necessary in the boundary case, as we
+ // should always be caught up (and may not even have the resources in
+ // scratch to support it).
+
+ const bool has_som = false;
+ RoseProgram prog;
+ for (const auto &id : reports) {
+ makeReport(build, id, has_som, prog);
+ }
+
+ return prog;
+}
+
+void addIncludedJumpProgram(RoseProgram &program, u32 child_offset,
+ u8 squash) {
+ RoseProgram block;
block.add_before_end(std::make_unique<RoseInstrIncludedJump>(child_offset,
- squash));
- program.add_block(move(block));
-}
-
-static
-void addPredBlockSingle(u32 pred_state, RoseProgram &pred_block,
- RoseProgram &program) {
- // Prepend an instruction to check the pred state is on.
- const auto *end_inst = pred_block.end_instruction();
- pred_block.insert(begin(pred_block),
- std::make_unique<RoseInstrCheckState>(pred_state, end_inst));
- program.add_block(move(pred_block));
-}
-
-static
-void addPredBlocksAny(map<u32, RoseProgram> &pred_blocks, u32 num_states,
- RoseProgram &program) {
- RoseProgram sparse_program;
-
- vector<u32> keys;
- for (const u32 &key : pred_blocks | map_keys) {
- keys.push_back(key);
- }
-
- const RoseInstruction *end_inst = sparse_program.end_instruction();
- auto ri = std::make_unique<RoseInstrSparseIterAny>(num_states, keys, end_inst);
- sparse_program.add_before_end(move(ri));
-
- RoseProgram &block = pred_blocks.begin()->second;
-
- /* we no longer need the check handled instruction as all the pred-role
- * blocks are being collapsed together */
- stripCheckHandledInstruction(block);
-
- sparse_program.add_before_end(move(block));
- program.add_block(move(sparse_program));
-}
-
-static
-void addPredBlocksMulti(map<u32, RoseProgram> &pred_blocks,
- u32 num_states, RoseProgram &program) {
- assert(!pred_blocks.empty());
-
- RoseProgram sparse_program;
- const RoseInstruction *end_inst = sparse_program.end_instruction();
- vector<pair<u32, const RoseInstruction *>> jump_table;
-
- // BEGIN instruction.
- auto ri_begin = std::make_unique<RoseInstrSparseIterBegin>(num_states, end_inst);
- RoseInstrSparseIterBegin *begin_inst = ri_begin.get();
- sparse_program.add_before_end(move(ri_begin));
-
- // NEXT instructions, one per pred program.
- u32 prev_key = pred_blocks.begin()->first;
- for (auto it = next(begin(pred_blocks)); it != end(pred_blocks); ++it) {
- auto ri = std::make_unique<RoseInstrSparseIterNext>(prev_key, begin_inst,
- end_inst);
- sparse_program.add_before_end(move(ri));
- prev_key = it->first;
- }
-
- // Splice in each pred program after its BEGIN/NEXT.
- auto out_it = begin(sparse_program);
- for (auto &m : pred_blocks) {
- u32 key = m.first;
- RoseProgram &flat_prog = m.second;
- assert(!flat_prog.empty());
- const size_t block_len = flat_prog.size() - 1; // without INSTR_END.
-
- assert(dynamic_cast<const RoseInstrSparseIterBegin *>(out_it->get()) ||
- dynamic_cast<const RoseInstrSparseIterNext *>(out_it->get()));
- out_it = sparse_program.insert(++out_it, move(flat_prog));
-
- // Jump table target for this key is the beginning of the block we just
- // spliced in.
- jump_table.emplace_back(key, out_it->get());
-
- assert(distance(begin(sparse_program), out_it) + block_len <=
- sparse_program.size());
- advance(out_it, block_len);
- }
-
- // Write the jump table back into the SPARSE_ITER_BEGIN instruction.
- begin_inst->jump_table = move(jump_table);
-
- program.add_block(move(sparse_program));
-}
-
-void addPredBlocks(map<u32, RoseProgram> &pred_blocks, u32 num_states,
- RoseProgram &program) {
- // Trim empty blocks, if any exist.
- for (auto it = pred_blocks.begin(); it != pred_blocks.end();) {
- if (it->second.empty()) {
- it = pred_blocks.erase(it);
- } else {
- ++it;
- }
- }
-
- const size_t num_preds = pred_blocks.size();
- if (num_preds == 0) {
- return;
- }
-
- if (num_preds == 1) {
- const auto head = pred_blocks.begin();
- addPredBlockSingle(head->first, head->second, program);
- return;
- }
-
- // First, see if all our blocks are equivalent, in which case we can
- // collapse them down into one.
- const auto &blocks = pred_blocks | map_values;
- if (all_of(begin(blocks), end(blocks), [&](const RoseProgram &block) {
- return RoseProgramEquivalence()(*begin(blocks), block);
- })) {
- DEBUG_PRINTF("all blocks equiv\n");
- addPredBlocksAny(pred_blocks, num_states, program);
- return;
- }
-
- addPredBlocksMulti(pred_blocks, num_states, program);
-}
-
-void applyFinalSpecialisation(RoseProgram &program) {
- assert(!program.empty());
- assert(program.back().code() == ROSE_INSTR_END);
- if (program.size() < 2) {
- return;
- }
-
- /* Replace the second-to-last instruction (before END) with a one-shot
- * specialisation if available. */
- auto it = next(program.rbegin());
- if (auto *ri = dynamic_cast<const RoseInstrReport *>(it->get())) {
- DEBUG_PRINTF("replacing REPORT with FINAL_REPORT\n");
- program.replace(it, std::make_unique<RoseInstrFinalReport>(
- ri->onmatch, ri->offset_adjust));
- }
-}
-
-void recordLongLiterals(vector<ue2_case_string> &longLiterals,
- const RoseProgram &program) {
- for (const auto &ri : program) {
- if (const auto *ri_check =
- dynamic_cast<const RoseInstrCheckLongLit *>(ri.get())) {
- DEBUG_PRINTF("found CHECK_LONG_LIT for string '%s'\n",
- escapeString(ri_check->literal).c_str());
- longLiterals.emplace_back(ri_check->literal, false);
- continue;
- }
- if (const auto *ri_check =
- dynamic_cast<const RoseInstrCheckLongLitNocase *>(ri.get())) {
- DEBUG_PRINTF("found CHECK_LONG_LIT_NOCASE for string '%s'\n",
- escapeString(ri_check->literal).c_str());
- longLiterals.emplace_back(ri_check->literal, true);
- }
- }
-}
-
-void recordResources(RoseResources &resources, const RoseProgram &program) {
- for (const auto &ri : program) {
- switch (ri->code()) {
- case ROSE_INSTR_TRIGGER_SUFFIX:
- resources.has_suffixes = true;
- break;
- case ROSE_INSTR_TRIGGER_INFIX:
- case ROSE_INSTR_CHECK_INFIX:
- case ROSE_INSTR_CHECK_PREFIX:
- case ROSE_INSTR_SOM_LEFTFIX:
- resources.has_leftfixes = true;
- break;
- case ROSE_INSTR_SET_STATE:
- case ROSE_INSTR_CHECK_STATE:
- case ROSE_INSTR_SPARSE_ITER_BEGIN:
- case ROSE_INSTR_SPARSE_ITER_NEXT:
- resources.has_states = true;
- break;
- case ROSE_INSTR_CHECK_GROUPS:
- resources.checks_groups = true;
- break;
- case ROSE_INSTR_PUSH_DELAYED:
- resources.has_lit_delay = true;
- break;
- case ROSE_INSTR_CHECK_LONG_LIT:
- case ROSE_INSTR_CHECK_LONG_LIT_NOCASE:
- resources.has_lit_check = true;
- break;
- default:
- break;
- }
- }
-}
-
-} // namespace ue2
+ squash));
+ program.add_block(move(block));
+}
+
+static
+void addPredBlockSingle(u32 pred_state, RoseProgram &pred_block,
+ RoseProgram &program) {
+ // Prepend an instruction to check the pred state is on.
+ const auto *end_inst = pred_block.end_instruction();
+ pred_block.insert(begin(pred_block),
+ std::make_unique<RoseInstrCheckState>(pred_state, end_inst));
+ program.add_block(move(pred_block));
+}
+
+static
+void addPredBlocksAny(map<u32, RoseProgram> &pred_blocks, u32 num_states,
+ RoseProgram &program) {
+ RoseProgram sparse_program;
+
+ vector<u32> keys;
+ for (const u32 &key : pred_blocks | map_keys) {
+ keys.push_back(key);
+ }
+
+ const RoseInstruction *end_inst = sparse_program.end_instruction();
+ auto ri = std::make_unique<RoseInstrSparseIterAny>(num_states, keys, end_inst);
+ sparse_program.add_before_end(move(ri));
+
+ RoseProgram &block = pred_blocks.begin()->second;
+
+ /* we no longer need the check handled instruction as all the pred-role
+ * blocks are being collapsed together */
+ stripCheckHandledInstruction(block);
+
+ sparse_program.add_before_end(move(block));
+ program.add_block(move(sparse_program));
+}
+
+static
+void addPredBlocksMulti(map<u32, RoseProgram> &pred_blocks,
+ u32 num_states, RoseProgram &program) {
+ assert(!pred_blocks.empty());
+
+ RoseProgram sparse_program;
+ const RoseInstruction *end_inst = sparse_program.end_instruction();
+ vector<pair<u32, const RoseInstruction *>> jump_table;
+
+ // BEGIN instruction.
+ auto ri_begin = std::make_unique<RoseInstrSparseIterBegin>(num_states, end_inst);
+ RoseInstrSparseIterBegin *begin_inst = ri_begin.get();
+ sparse_program.add_before_end(move(ri_begin));
+
+ // NEXT instructions, one per pred program.
+ u32 prev_key = pred_blocks.begin()->first;
+ for (auto it = next(begin(pred_blocks)); it != end(pred_blocks); ++it) {
+ auto ri = std::make_unique<RoseInstrSparseIterNext>(prev_key, begin_inst,
+ end_inst);
+ sparse_program.add_before_end(move(ri));
+ prev_key = it->first;
+ }
+
+ // Splice in each pred program after its BEGIN/NEXT.
+ auto out_it = begin(sparse_program);
+ for (auto &m : pred_blocks) {
+ u32 key = m.first;
+ RoseProgram &flat_prog = m.second;
+ assert(!flat_prog.empty());
+ const size_t block_len = flat_prog.size() - 1; // without INSTR_END.
+
+ assert(dynamic_cast<const RoseInstrSparseIterBegin *>(out_it->get()) ||
+ dynamic_cast<const RoseInstrSparseIterNext *>(out_it->get()));
+ out_it = sparse_program.insert(++out_it, move(flat_prog));
+
+ // Jump table target for this key is the beginning of the block we just
+ // spliced in.
+ jump_table.emplace_back(key, out_it->get());
+
+ assert(distance(begin(sparse_program), out_it) + block_len <=
+ sparse_program.size());
+ advance(out_it, block_len);
+ }
+
+ // Write the jump table back into the SPARSE_ITER_BEGIN instruction.
+ begin_inst->jump_table = move(jump_table);
+
+ program.add_block(move(sparse_program));
+}
+
+void addPredBlocks(map<u32, RoseProgram> &pred_blocks, u32 num_states,
+ RoseProgram &program) {
+ // Trim empty blocks, if any exist.
+ for (auto it = pred_blocks.begin(); it != pred_blocks.end();) {
+ if (it->second.empty()) {
+ it = pred_blocks.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ const size_t num_preds = pred_blocks.size();
+ if (num_preds == 0) {
+ return;
+ }
+
+ if (num_preds == 1) {
+ const auto head = pred_blocks.begin();
+ addPredBlockSingle(head->first, head->second, program);
+ return;
+ }
+
+ // First, see if all our blocks are equivalent, in which case we can
+ // collapse them down into one.
+ const auto &blocks = pred_blocks | map_values;
+ if (all_of(begin(blocks), end(blocks), [&](const RoseProgram &block) {
+ return RoseProgramEquivalence()(*begin(blocks), block);
+ })) {
+ DEBUG_PRINTF("all blocks equiv\n");
+ addPredBlocksAny(pred_blocks, num_states, program);
+ return;
+ }
+
+ addPredBlocksMulti(pred_blocks, num_states, program);
+}
+
+void applyFinalSpecialisation(RoseProgram &program) {
+ assert(!program.empty());
+ assert(program.back().code() == ROSE_INSTR_END);
+ if (program.size() < 2) {
+ return;
+ }
+
+ /* Replace the second-to-last instruction (before END) with a one-shot
+ * specialisation if available. */
+ auto it = next(program.rbegin());
+ if (auto *ri = dynamic_cast<const RoseInstrReport *>(it->get())) {
+ DEBUG_PRINTF("replacing REPORT with FINAL_REPORT\n");
+ program.replace(it, std::make_unique<RoseInstrFinalReport>(
+ ri->onmatch, ri->offset_adjust));
+ }
+}
+
+void recordLongLiterals(vector<ue2_case_string> &longLiterals,
+ const RoseProgram &program) {
+ for (const auto &ri : program) {
+ if (const auto *ri_check =
+ dynamic_cast<const RoseInstrCheckLongLit *>(ri.get())) {
+ DEBUG_PRINTF("found CHECK_LONG_LIT for string '%s'\n",
+ escapeString(ri_check->literal).c_str());
+ longLiterals.emplace_back(ri_check->literal, false);
+ continue;
+ }
+ if (const auto *ri_check =
+ dynamic_cast<const RoseInstrCheckLongLitNocase *>(ri.get())) {
+ DEBUG_PRINTF("found CHECK_LONG_LIT_NOCASE for string '%s'\n",
+ escapeString(ri_check->literal).c_str());
+ longLiterals.emplace_back(ri_check->literal, true);
+ }
+ }
+}
+
+void recordResources(RoseResources &resources, const RoseProgram &program) {
+ for (const auto &ri : program) {
+ switch (ri->code()) {
+ case ROSE_INSTR_TRIGGER_SUFFIX:
+ resources.has_suffixes = true;
+ break;
+ case ROSE_INSTR_TRIGGER_INFIX:
+ case ROSE_INSTR_CHECK_INFIX:
+ case ROSE_INSTR_CHECK_PREFIX:
+ case ROSE_INSTR_SOM_LEFTFIX:
+ resources.has_leftfixes = true;
+ break;
+ case ROSE_INSTR_SET_STATE:
+ case ROSE_INSTR_CHECK_STATE:
+ case ROSE_INSTR_SPARSE_ITER_BEGIN:
+ case ROSE_INSTR_SPARSE_ITER_NEXT:
+ resources.has_states = true;
+ break;
+ case ROSE_INSTR_CHECK_GROUPS:
+ resources.checks_groups = true;
+ break;
+ case ROSE_INSTR_PUSH_DELAYED:
+ resources.has_lit_delay = true;
+ break;
+ case ROSE_INSTR_CHECK_LONG_LIT:
+ case ROSE_INSTR_CHECK_LONG_LIT_NOCASE:
+ resources.has_lit_check = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_program.h b/contrib/libs/hyperscan/src/rose/rose_build_program.h
index eb4adae29f6..7d781f3191e 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_program.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_program.h
@@ -1,290 +1,290 @@
-/*
+/*
* Copyright (c) 2016-2019, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_PROGRAM_H
-#define ROSE_BUILD_PROGRAM_H
-
-#include "rose_build_impl.h"
-#include "rose_program.h"
-#include "util/bytecode_ptr.h"
-#include "util/hash.h"
-#include "util/make_unique.h"
-
-#include <unordered_map>
-#include <vector>
-
-#include <boost/range/adaptor/map.hpp>
-
-namespace ue2 {
-
-struct LookEntry;
-class RoseEngineBlob;
-class RoseInstruction;
-struct RoseResources;
-
-/**
- * \brief Container for a list of program instructions.
- */
-class RoseProgram {
-private:
- std::vector<std::unique_ptr<RoseInstruction>> prog;
-
-public:
- RoseProgram();
- ~RoseProgram();
- RoseProgram(const RoseProgram &) = delete;
- RoseProgram(RoseProgram &&);
- RoseProgram &operator=(const RoseProgram &) = delete;
- RoseProgram &operator=(RoseProgram &&);
-
- bool empty() const;
-
- size_t size() const { return prog.size(); }
-
- const RoseInstruction &back() const { return *prog.back(); }
- const RoseInstruction &front() const { return *prog.front(); }
-
- using iterator = decltype(prog)::iterator;
- iterator begin() { return prog.begin(); }
- iterator end() { return prog.end(); }
-
- using const_iterator = decltype(prog)::const_iterator;
- const_iterator begin() const { return prog.begin(); }
- const_iterator end() const { return prog.end(); }
-
- using reverse_iterator = decltype(prog)::reverse_iterator;
- reverse_iterator rbegin() { return prog.rbegin(); }
- reverse_iterator rend() { return prog.rend(); }
-
- using const_reverse_iterator = decltype(prog)::const_reverse_iterator;
- const_reverse_iterator rbegin() const { return prog.rbegin(); }
- const_reverse_iterator rend() const { return prog.rend(); }
-
- /** \brief Retrieve a pointer to the terminating ROSE_INSTR_END. */
- const RoseInstruction *end_instruction() const;
-
- static void update_targets(iterator it, iterator it_end,
- const RoseInstruction *old_target,
- const RoseInstruction *new_target);
-
- iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri);
-
- iterator insert(iterator it, RoseProgram &&block);
-
- /* Note: takes iterator rather than const_iterator to support toolchains
- * with pre-C++11 standard libraries (i.e., gcc-4.8). */
- iterator erase(iterator first, iterator last);
-
- /**
- * \brief Adds this instruction to the program just before the terminating
- * ROSE_INSTR_END.
- */
- void add_before_end(std::unique_ptr<RoseInstruction> ri);
-
- /**
- * \brief Adds this block to the program just before the terminating
- * ROSE_INSTR_END.
- *
- * Any existing instruction that was jumping to end continues to do so.
- */
- void add_before_end(RoseProgram &&block);
- /**
- * \brief Append this program block, replacing our current ROSE_INSTR_END.
- *
- * Any existing instruction that was jumping to end, now leads to the newly
- * added block.
- */
- void add_block(RoseProgram &&block);
-
- /**
- * \brief Replace the instruction pointed to by the given iterator.
- */
- template<class Iter>
- void replace(Iter it, std::unique_ptr<RoseInstruction> ri) {
- assert(!prog.empty());
-
- const RoseInstruction *old_ptr = it->get();
- *it = move(ri);
- update_targets(prog.begin(), prog.end(), old_ptr, it->get());
- }
-};
-
-bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
- const RoseProgram &program);
-
-class RoseProgramHash {
-public:
- size_t operator()(const RoseProgram &program) const;
-};
-
-class RoseProgramEquivalence {
-public:
- bool operator()(const RoseProgram &prog1, const RoseProgram &prog2) const;
-};
-
-/** \brief Data only used during construction of various programs (literal,
- * anchored, delay, etc). */
-struct ProgramBuild : noncopyable {
- explicit ProgramBuild(u32 fMinLitOffset, size_t longLitThresh,
- bool catchup)
- : floatingMinLiteralMatchOffset(fMinLitOffset),
- longLitLengthThreshold(longLitThresh), needs_catchup(catchup) {
- }
-
- /** \brief Minimum offset of a match from the floating table. */
- const u32 floatingMinLiteralMatchOffset;
-
- /** \brief Long literal length threshold, used in streaming mode. */
- const size_t longLitLengthThreshold;
-
- /** \brief True if reports need CATCH_UP instructions to catch up suffixes,
- * outfixes etc. */
- const bool needs_catchup;
-
- /** \brief Mapping from vertex to key, for vertices with a
- * CHECK_NOT_HANDLED instruction. */
- std::unordered_map<RoseVertex, u32> handledKeys;
-
- /** \brief Mapping from Rose literal ID to anchored program index. */
- std::map<u32, u32> anchored_programs;
-
- /** \brief Mapping from Rose literal ID to delayed program index. */
- std::map<u32, u32> delay_programs;
-
- /** \brief Mapping from every vertex to the groups that must be on for that
- * vertex to be reached. */
- std::unordered_map<RoseVertex, rose_group> vertex_group_map;
-
- /** \brief Global bitmap of groups that can be squashed. */
- rose_group squashable_groups = 0;
-};
-
-void addEnginesEodProgram(u32 eodNfaIterOffset, RoseProgram &program);
-void addSuffixesEodProgram(RoseProgram &program);
-void addMatcherEodProgram(RoseProgram &program);
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_PROGRAM_H
+#define ROSE_BUILD_PROGRAM_H
+
+#include "rose_build_impl.h"
+#include "rose_program.h"
+#include "util/bytecode_ptr.h"
+#include "util/hash.h"
+#include "util/make_unique.h"
+
+#include <unordered_map>
+#include <vector>
+
+#include <boost/range/adaptor/map.hpp>
+
+namespace ue2 {
+
+struct LookEntry;
+class RoseEngineBlob;
+class RoseInstruction;
+struct RoseResources;
+
+/**
+ * \brief Container for a list of program instructions.
+ */
+class RoseProgram {
+private:
+ std::vector<std::unique_ptr<RoseInstruction>> prog;
+
+public:
+ RoseProgram();
+ ~RoseProgram();
+ RoseProgram(const RoseProgram &) = delete;
+ RoseProgram(RoseProgram &&);
+ RoseProgram &operator=(const RoseProgram &) = delete;
+ RoseProgram &operator=(RoseProgram &&);
+
+ bool empty() const;
+
+ size_t size() const { return prog.size(); }
+
+ const RoseInstruction &back() const { return *prog.back(); }
+ const RoseInstruction &front() const { return *prog.front(); }
+
+ using iterator = decltype(prog)::iterator;
+ iterator begin() { return prog.begin(); }
+ iterator end() { return prog.end(); }
+
+ using const_iterator = decltype(prog)::const_iterator;
+ const_iterator begin() const { return prog.begin(); }
+ const_iterator end() const { return prog.end(); }
+
+ using reverse_iterator = decltype(prog)::reverse_iterator;
+ reverse_iterator rbegin() { return prog.rbegin(); }
+ reverse_iterator rend() { return prog.rend(); }
+
+ using const_reverse_iterator = decltype(prog)::const_reverse_iterator;
+ const_reverse_iterator rbegin() const { return prog.rbegin(); }
+ const_reverse_iterator rend() const { return prog.rend(); }
+
+ /** \brief Retrieve a pointer to the terminating ROSE_INSTR_END. */
+ const RoseInstruction *end_instruction() const;
+
+ static void update_targets(iterator it, iterator it_end,
+ const RoseInstruction *old_target,
+ const RoseInstruction *new_target);
+
+ iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri);
+
+ iterator insert(iterator it, RoseProgram &&block);
+
+ /* Note: takes iterator rather than const_iterator to support toolchains
+ * with pre-C++11 standard libraries (i.e., gcc-4.8). */
+ iterator erase(iterator first, iterator last);
+
+ /**
+ * \brief Adds this instruction to the program just before the terminating
+ * ROSE_INSTR_END.
+ */
+ void add_before_end(std::unique_ptr<RoseInstruction> ri);
+
+ /**
+ * \brief Adds this block to the program just before the terminating
+ * ROSE_INSTR_END.
+ *
+ * Any existing instruction that was jumping to end continues to do so.
+ */
+ void add_before_end(RoseProgram &&block);
+ /**
+ * \brief Append this program block, replacing our current ROSE_INSTR_END.
+ *
+ * Any existing instruction that was jumping to end, now leads to the newly
+ * added block.
+ */
+ void add_block(RoseProgram &&block);
+
+ /**
+ * \brief Replace the instruction pointed to by the given iterator.
+ */
+ template<class Iter>
+ void replace(Iter it, std::unique_ptr<RoseInstruction> ri) {
+ assert(!prog.empty());
+
+ const RoseInstruction *old_ptr = it->get();
+ *it = move(ri);
+ update_targets(prog.begin(), prog.end(), old_ptr, it->get());
+ }
+};
+
+bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
+ const RoseProgram &program);
+
+class RoseProgramHash {
+public:
+ size_t operator()(const RoseProgram &program) const;
+};
+
+class RoseProgramEquivalence {
+public:
+ bool operator()(const RoseProgram &prog1, const RoseProgram &prog2) const;
+};
+
+/** \brief Data only used during construction of various programs (literal,
+ * anchored, delay, etc). */
+struct ProgramBuild : noncopyable {
+ explicit ProgramBuild(u32 fMinLitOffset, size_t longLitThresh,
+ bool catchup)
+ : floatingMinLiteralMatchOffset(fMinLitOffset),
+ longLitLengthThreshold(longLitThresh), needs_catchup(catchup) {
+ }
+
+ /** \brief Minimum offset of a match from the floating table. */
+ const u32 floatingMinLiteralMatchOffset;
+
+ /** \brief Long literal length threshold, used in streaming mode. */
+ const size_t longLitLengthThreshold;
+
+ /** \brief True if reports need CATCH_UP instructions to catch up suffixes,
+ * outfixes etc. */
+ const bool needs_catchup;
+
+ /** \brief Mapping from vertex to key, for vertices with a
+ * CHECK_NOT_HANDLED instruction. */
+ std::unordered_map<RoseVertex, u32> handledKeys;
+
+ /** \brief Mapping from Rose literal ID to anchored program index. */
+ std::map<u32, u32> anchored_programs;
+
+ /** \brief Mapping from Rose literal ID to delayed program index. */
+ std::map<u32, u32> delay_programs;
+
+ /** \brief Mapping from every vertex to the groups that must be on for that
+ * vertex to be reached. */
+ std::unordered_map<RoseVertex, rose_group> vertex_group_map;
+
+ /** \brief Global bitmap of groups that can be squashed. */
+ rose_group squashable_groups = 0;
+};
+
+void addEnginesEodProgram(u32 eodNfaIterOffset, RoseProgram &program);
+void addSuffixesEodProgram(RoseProgram &program);
+void addMatcherEodProgram(RoseProgram &program);
void addFlushCombinationProgram(RoseProgram &program);
void addLastFlushCombinationProgram(RoseProgram &program);
-
-static constexpr u32 INVALID_QUEUE = ~0U;
-
-struct left_build_info {
- // Constructor for an engine implementation.
- left_build_info(u32 q, u32 l, u32 t, rose_group sm,
- const std::vector<u8> &stops, u32 max_ql, u8 cm_count,
- const CharReach &cm_cr);
-
- // Constructor for a lookaround implementation.
- explicit left_build_info(const std::vector<std::vector<LookEntry>> &looks);
-
- u32 queue = INVALID_QUEUE; /* uniquely idents the left_build_info */
- u32 lag = 0;
- u32 transient = 0;
- rose_group squash_mask = ~rose_group{0};
- std::vector<u8> stopAlphabet;
- u32 max_queuelen = 0;
- u8 countingMiracleCount = 0;
- CharReach countingMiracleReach;
- u32 countingMiracleOffset = 0; /* populated later when laying out bytecode */
- bool has_lookaround = false;
-
- // alternative implementation to the NFA
- std::vector<std::vector<LookEntry>> lookaround;
-};
-
-/**
- * \brief Provides a brief summary of properties of an NFA that has already been
- * finalised and stored in the blob.
- */
-struct engine_info {
- engine_info(const NFA *nfa, bool trans);
-
- enum NFAEngineType type;
- bool accepts_eod;
- u32 stream_size;
- u32 scratch_size;
- u32 scratch_align;
- bool transient;
-};
-
-/**
- * \brief Consumes list of program blocks corresponding to different literals,
- * checks them for duplicates and then concatenates them into one program.
- *
- * Note: if a block will squash groups, a CLEAR_WORK_DONE instruction is
- * inserted to prevent the work_done flag being contaminated by early blocks.
- */
-RoseProgram assembleProgramBlocks(std::vector<RoseProgram> &&blocks);
-
-RoseProgram makeLiteralProgram(const RoseBuildImpl &build,
- const std::map<RoseVertex, left_build_info> &leftfix_info,
- const std::map<suffix_id, u32> &suffixes,
- const std::map<u32, engine_info> &engine_info_by_queue,
- const std::unordered_map<RoseVertex, u32> &roleStateIndices,
- ProgramBuild &prog_build, u32 lit_id,
- const std::vector<RoseEdge> &lit_edges,
- bool is_anchored_replay_program);
-
-RoseProgram makeDelayRebuildProgram(const RoseBuildImpl &build,
- ProgramBuild &prog_build,
- const std::vector<u32> &lit_ids);
-
-RoseProgram makeEodAnchorProgram(const RoseBuildImpl &build,
- ProgramBuild &prog_build, const RoseEdge &e,
- const bool multiple_preds);
-
-RoseProgram makeReportProgram(const RoseBuildImpl &build,
- bool needs_mpv_catchup, ReportID id);
-
-RoseProgram makeBoundaryProgram(const RoseBuildImpl &build,
- const std::set<ReportID> &reports);
-
-struct TriggerInfo {
- TriggerInfo(bool c, u32 q, u32 e) : cancel(c), queue(q), event(e) {}
- bool cancel;
- u32 queue;
- u32 event;
-
- bool operator==(const TriggerInfo &b) const {
- return cancel == b.cancel && queue == b.queue && event == b.event;
- }
-};
-
-void addPredBlocks(std::map<u32, RoseProgram> &pred_blocks, u32 num_states,
- RoseProgram &program);
-
-void applyFinalSpecialisation(RoseProgram &program);
-
-void recordLongLiterals(std::vector<ue2_case_string> &longLiterals,
- const RoseProgram &program);
-
-void recordResources(RoseResources &resources, const RoseProgram &program);
-
-void addIncludedJumpProgram(RoseProgram &program, u32 child_offset, u8 squash);
-} // namespace ue2
-
-#endif // ROSE_BUILD_PROGRAM_H
+
+static constexpr u32 INVALID_QUEUE = ~0U;
+
+struct left_build_info {
+ // Constructor for an engine implementation.
+ left_build_info(u32 q, u32 l, u32 t, rose_group sm,
+ const std::vector<u8> &stops, u32 max_ql, u8 cm_count,
+ const CharReach &cm_cr);
+
+ // Constructor for a lookaround implementation.
+ explicit left_build_info(const std::vector<std::vector<LookEntry>> &looks);
+
+ u32 queue = INVALID_QUEUE; /* uniquely idents the left_build_info */
+ u32 lag = 0;
+ u32 transient = 0;
+ rose_group squash_mask = ~rose_group{0};
+ std::vector<u8> stopAlphabet;
+ u32 max_queuelen = 0;
+ u8 countingMiracleCount = 0;
+ CharReach countingMiracleReach;
+ u32 countingMiracleOffset = 0; /* populated later when laying out bytecode */
+ bool has_lookaround = false;
+
+ // alternative implementation to the NFA
+ std::vector<std::vector<LookEntry>> lookaround;
+};
+
+/**
+ * \brief Provides a brief summary of properties of an NFA that has already been
+ * finalised and stored in the blob.
+ */
+struct engine_info {
+ engine_info(const NFA *nfa, bool trans);
+
+ enum NFAEngineType type;
+ bool accepts_eod;
+ u32 stream_size;
+ u32 scratch_size;
+ u32 scratch_align;
+ bool transient;
+};
+
+/**
+ * \brief Consumes list of program blocks corresponding to different literals,
+ * checks them for duplicates and then concatenates them into one program.
+ *
+ * Note: if a block will squash groups, a CLEAR_WORK_DONE instruction is
+ * inserted to prevent the work_done flag being contaminated by early blocks.
+ */
+RoseProgram assembleProgramBlocks(std::vector<RoseProgram> &&blocks);
+
+RoseProgram makeLiteralProgram(const RoseBuildImpl &build,
+ const std::map<RoseVertex, left_build_info> &leftfix_info,
+ const std::map<suffix_id, u32> &suffixes,
+ const std::map<u32, engine_info> &engine_info_by_queue,
+ const std::unordered_map<RoseVertex, u32> &roleStateIndices,
+ ProgramBuild &prog_build, u32 lit_id,
+ const std::vector<RoseEdge> &lit_edges,
+ bool is_anchored_replay_program);
+
+RoseProgram makeDelayRebuildProgram(const RoseBuildImpl &build,
+ ProgramBuild &prog_build,
+ const std::vector<u32> &lit_ids);
+
+RoseProgram makeEodAnchorProgram(const RoseBuildImpl &build,
+ ProgramBuild &prog_build, const RoseEdge &e,
+ const bool multiple_preds);
+
+RoseProgram makeReportProgram(const RoseBuildImpl &build,
+ bool needs_mpv_catchup, ReportID id);
+
+RoseProgram makeBoundaryProgram(const RoseBuildImpl &build,
+ const std::set<ReportID> &reports);
+
+struct TriggerInfo {
+ TriggerInfo(bool c, u32 q, u32 e) : cancel(c), queue(q), event(e) {}
+ bool cancel;
+ u32 queue;
+ u32 event;
+
+ bool operator==(const TriggerInfo &b) const {
+ return cancel == b.cancel && queue == b.queue && event == b.event;
+ }
+};
+
+void addPredBlocks(std::map<u32, RoseProgram> &pred_blocks, u32 num_states,
+ RoseProgram &program);
+
+void applyFinalSpecialisation(RoseProgram &program);
+
+void recordLongLiterals(std::vector<ue2_case_string> &longLiterals,
+ const RoseProgram &program);
+
+void recordResources(RoseResources &resources, const RoseProgram &program);
+
+void addIncludedJumpProgram(RoseProgram &program, u32 child_offset, u8 squash);
+} // namespace ue2
+
+#endif // ROSE_BUILD_PROGRAM_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_resources.h b/contrib/libs/hyperscan/src/rose/rose_build_resources.h
index 0488a8b3ba6..4fa102f3ee7 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_resources.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_resources.h
@@ -1,59 +1,59 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ROSE_BUILD_RESOURCES_H
-#define ROSE_BUILD_RESOURCES_H
-
-namespace ue2 {
-
-/**
- * \brief Structure tracking which resources are used by this Rose instance at
- * runtime.
- *
- * We use this to control how much initialisation we need to do at the
- * beginning of a stream/block at runtime.
- */
-struct RoseResources {
- bool has_outfixes = false;
- bool has_suffixes = false;
- bool has_leftfixes = false;
- bool has_literals = false;
- bool has_states = false;
- bool checks_groups = false;
- bool has_lit_delay = false;
- bool has_lit_check = false; // long literal support
- bool has_anchored = false;
- bool has_anchored_multiple = false; /* multiple anchored dfas */
- bool has_anchored_large = false; /* mcclellan 16 anchored dfa */
- bool has_floating = false;
- bool has_eod = false;
-};
-
-}
-
-#endif
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ROSE_BUILD_RESOURCES_H
+#define ROSE_BUILD_RESOURCES_H
+
+namespace ue2 {
+
+/**
+ * \brief Structure tracking which resources are used by this Rose instance at
+ * runtime.
+ *
+ * We use this to control how much initialisation we need to do at the
+ * beginning of a stream/block at runtime.
+ */
+struct RoseResources {
+ bool has_outfixes = false;
+ bool has_suffixes = false;
+ bool has_leftfixes = false;
+ bool has_literals = false;
+ bool has_states = false;
+ bool checks_groups = false;
+ bool has_lit_delay = false;
+ bool has_lit_check = false; // long literal support
+ bool has_anchored = false;
+ bool has_anchored_multiple = false; /* multiple anchored dfas */
+ bool has_anchored_large = false; /* mcclellan 16 anchored dfa */
+ bool has_floating = false;
+ bool has_eod = false;
+};
+
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.cpp b/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.cpp
index 475f3f49c0d..359550e1189 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,10 +45,10 @@
#include "util/bitutils.h"
#include "util/compile_context.h"
#include "util/container.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph.h"
#include "util/graph_range.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include "util/order_check.h"
#include <algorithm>
@@ -62,8 +62,8 @@ using boost::adaptors::map_values;
namespace ue2 {
-static constexpr size_t MERGE_GROUP_SIZE_MAX = 200;
-
+static constexpr size_t MERGE_GROUP_SIZE_MAX = 200;
+
namespace {
// Used for checking edge sets (both in- and out-) against each other.
struct EdgeAndVertex {
@@ -113,14 +113,14 @@ struct AliasInEdge : EdgeAndVertex {
class CandidateSet {
public:
- using key_type = RoseVertex;
- using iterator = set<RoseVertex>::iterator;
- using const_iterator = set<RoseVertex>::const_iterator;
+ using key_type = RoseVertex;
+ using iterator = set<RoseVertex>::iterator;
+ using const_iterator = set<RoseVertex>::const_iterator;
iterator begin() { return main_cont.begin(); }
iterator end() { return main_cont.end(); }
- const_iterator begin() const { return main_cont.begin(); }
- const_iterator end() const { return main_cont.end(); }
+ const_iterator begin() const { return main_cont.begin(); }
+ const_iterator end() const { return main_cont.end(); }
bool contains(RoseVertex a) const {
return hash_cont.find(a) != hash_cont.end();
@@ -154,36 +154,36 @@ public:
private:
/* if a vertex is worth storing, it is worth storing twice */
- set<RoseVertex> main_cont; /* deterministic iterator */
- unordered_set<RoseVertex> hash_cont; /* member checks */
+ set<RoseVertex> main_cont; /* deterministic iterator */
+ unordered_set<RoseVertex> hash_cont; /* member checks */
};
-struct RoseAliasingInfo {
- RoseAliasingInfo(const RoseBuildImpl &build) {
- const auto &g = build.g;
+struct RoseAliasingInfo {
+ RoseAliasingInfo(const RoseBuildImpl &build) {
+ const auto &g = build.g;
- // Populate reverse leftfix map.
- for (auto v : vertices_range(g)) {
- if (g[v].left) {
- rev_leftfix[g[v].left].insert(v);
- }
- }
+ // Populate reverse leftfix map.
+ for (auto v : vertices_range(g)) {
+ if (g[v].left) {
+ rev_leftfix[g[v].left].insert(v);
+ }
+ }
- // Populate reverse ghost vertex map.
- for (const auto &m : build.ghost) {
- rev_ghost[m.second].insert(m.first);
+ // Populate reverse ghost vertex map.
+ for (const auto &m : build.ghost) {
+ rev_ghost[m.second].insert(m.first);
}
}
- /** \brief Mapping from leftfix to vertices. */
- unordered_map<left_id, set<RoseVertex>> rev_leftfix;
-
- /** \brief Mapping from undelayed ghost to delayed vertices. */
- unordered_map<RoseVertex, set<RoseVertex>> rev_ghost;
-};
-
-} // namespace
-
+ /** \brief Mapping from leftfix to vertices. */
+ unordered_map<left_id, set<RoseVertex>> rev_leftfix;
+
+ /** \brief Mapping from undelayed ghost to delayed vertices. */
+ unordered_map<RoseVertex, set<RoseVertex>> rev_ghost;
+};
+
+} // namespace
+
// Check successor set: must lead to the same vertices via edges with the
// same properties.
static
@@ -259,8 +259,8 @@ bool samePredecessors(RoseVertex a, RoseVertex b, const RoseGraph &g) {
}
for (const auto &e_a : in_edges_range(a, g)) {
- RoseEdge e = edge(source(e_a, g), b, g);
- if (!e || g[e].rose_top != g[e_a].rose_top) {
+ RoseEdge e = edge(source(e_a, g), b, g);
+ if (!e || g[e].rose_top != g[e_a].rose_top) {
DEBUG_PRINTF("bad tops\n");
return false;
}
@@ -271,10 +271,10 @@ bool samePredecessors(RoseVertex a, RoseVertex b, const RoseGraph &g) {
}
static
-bool hasCommonSuccWithBadBounds(RoseVertex a, RoseVertex b,
- const RoseGraph &g) {
+bool hasCommonSuccWithBadBounds(RoseVertex a, RoseVertex b,
+ const RoseGraph &g) {
for (const auto &e_a : out_edges_range(a, g)) {
- if (RoseEdge e = edge(b, target(e_a, g), g)) {
+ if (RoseEdge e = edge(b, target(e_a, g), g)) {
if (g[e_a].maxBound < g[e].minBound
|| g[e].maxBound < g[e_a].minBound) {
return true;
@@ -290,10 +290,10 @@ bool hasCommonSuccWithBadBounds(RoseVertex a, RoseVertex b,
}
static
-bool hasCommonPredWithBadBounds(RoseVertex a, RoseVertex b,
- const RoseGraph &g) {
+bool hasCommonPredWithBadBounds(RoseVertex a, RoseVertex b,
+ const RoseGraph &g) {
for (const auto &e_a : in_edges_range(a, g)) {
- if (RoseEdge e = edge(source(e_a, g), b, g)) {
+ if (RoseEdge e = edge(source(e_a, g), b, g)) {
if (g[e_a].maxBound < g[e].minBound
|| g[e].maxBound < g[e_a].minBound) {
return true;
@@ -314,24 +314,24 @@ bool hasCommonPredWithBadBounds(RoseVertex a, RoseVertex b,
}
static
-bool canMergeLiterals(RoseVertex a, RoseVertex b, const RoseBuildImpl &build) {
- const auto &lits_a = build.g[a].literals;
- const auto &lits_b = build.g[b].literals;
+bool canMergeLiterals(RoseVertex a, RoseVertex b, const RoseBuildImpl &build) {
+ const auto &lits_a = build.g[a].literals;
+ const auto &lits_b = build.g[b].literals;
assert(!lits_a.empty() && !lits_b.empty());
// If both vertices have only pseudo-dotstar in-edges, we can merge
// literals of different lengths and can avoid the check below.
- if (build.hasOnlyPseudoStarInEdges(a) &&
- build.hasOnlyPseudoStarInEdges(b)) {
+ if (build.hasOnlyPseudoStarInEdges(a) &&
+ build.hasOnlyPseudoStarInEdges(b)) {
DEBUG_PRINTF("both have pseudo-dotstar in-edges\n");
return true;
}
// Otherwise, all the literals involved must have the same length.
for (u32 a_id : lits_a) {
- const rose_literal_id &la = build.literals.at(a_id);
+ const rose_literal_id &la = build.literals.at(a_id);
for (u32 b_id : lits_b) {
- const rose_literal_id &lb = build.literals.at(b_id);
+ const rose_literal_id &lb = build.literals.at(b_id);
if (la.elength() != lb.elength()) {
DEBUG_PRINTF("bad merge %zu!=%zu '%s', '%s'\n", la.elength(),
@@ -345,56 +345,56 @@ bool canMergeLiterals(RoseVertex a, RoseVertex b, const RoseBuildImpl &build) {
}
static
-bool isAliasingCandidate(RoseVertex v, const RoseBuildImpl &build) {
- const RoseVertexProps &props = build.g[v];
+bool isAliasingCandidate(RoseVertex v, const RoseBuildImpl &build) {
+ const RoseVertexProps &props = build.g[v];
// Must have literals.
if (props.literals.empty()) {
return false;
}
- assert(*props.literals.begin() != MO_INVALID_IDX);
- return true;
-}
-
-static
-bool sameGhostProperties(const RoseBuildImpl &build,
- const RoseAliasingInfo &rai, RoseVertex a,
- RoseVertex b) {
- // If these are ghost mapping keys, then they must map to the same vertex.
- if (contains(build.ghost, a) || contains(build.ghost, b)) {
- DEBUG_PRINTF("checking ghost key compat\n");
- if (!contains(build.ghost, a) || !contains(build.ghost, b)) {
- DEBUG_PRINTF("missing ghost mapping\n");
- return false;
- }
- if (build.ghost.at(a) != build.ghost.at(b)) {
- DEBUG_PRINTF("diff ghost mapping\n");
- return false;
- }
- DEBUG_PRINTF("ghost mappings ok\n");
- return true;
- }
-
- // If they are ghost vertices, then they must have the same literals.
- if (contains(rai.rev_ghost, a) || contains(rai.rev_ghost, b)) {
- if (!contains(rai.rev_ghost, a) || !contains(rai.rev_ghost, b)) {
- DEBUG_PRINTF("missing ghost reverse mapping\n");
- return false;
- }
- return build.g[a].literals == build.g[b].literals;
- }
+ assert(*props.literals.begin() != MO_INVALID_IDX);
+ return true;
+}
+
+static
+bool sameGhostProperties(const RoseBuildImpl &build,
+ const RoseAliasingInfo &rai, RoseVertex a,
+ RoseVertex b) {
+ // If these are ghost mapping keys, then they must map to the same vertex.
+ if (contains(build.ghost, a) || contains(build.ghost, b)) {
+ DEBUG_PRINTF("checking ghost key compat\n");
+ if (!contains(build.ghost, a) || !contains(build.ghost, b)) {
+ DEBUG_PRINTF("missing ghost mapping\n");
+ return false;
+ }
+ if (build.ghost.at(a) != build.ghost.at(b)) {
+ DEBUG_PRINTF("diff ghost mapping\n");
+ return false;
+ }
+ DEBUG_PRINTF("ghost mappings ok\n");
+ return true;
+ }
+
+ // If they are ghost vertices, then they must have the same literals.
+ if (contains(rai.rev_ghost, a) || contains(rai.rev_ghost, b)) {
+ if (!contains(rai.rev_ghost, a) || !contains(rai.rev_ghost, b)) {
+ DEBUG_PRINTF("missing ghost reverse mapping\n");
+ return false;
+ }
+ return build.g[a].literals == build.g[b].literals;
+ }
return true;
}
static
-bool sameRoleProperties(const RoseBuildImpl &build, const RoseAliasingInfo &rai,
- RoseVertex a, RoseVertex b) {
+bool sameRoleProperties(const RoseBuildImpl &build, const RoseAliasingInfo &rai,
+ RoseVertex a, RoseVertex b) {
const RoseGraph &g = build.g;
const RoseVertexProps &aprops = g[a], &bprops = g[b];
- if (aprops.eod_accept != bprops.eod_accept) {
+ if (aprops.eod_accept != bprops.eod_accept) {
return false;
}
@@ -415,17 +415,17 @@ bool sameRoleProperties(const RoseBuildImpl &build, const RoseAliasingInfo &rai,
return false;
}
- if (!sameGhostProperties(build, rai, a, b)) {
- return false;
- }
-
+ if (!sameGhostProperties(build, rai, a, b)) {
+ return false;
+ }
+
/* "roses are mergeable" check are handled elsewhere */
return true;
}
-/* Checks compatibility of role properties if we require that two roles are
- * right equiv. */
+/* Checks compatibility of role properties if we require that two roles are
+ * right equiv. */
static
bool sameRightRoleProperties(const RoseBuildImpl &build, RoseVertex a,
RoseVertex b) {
@@ -462,11 +462,11 @@ void mergeEdgeAdd(RoseVertex u, RoseVertex v, const RoseEdge &from_edge,
const RoseEdgeProps &from_props = g[from_edge];
if (!to_edge) {
- DEBUG_PRINTF("adding edge [%zu,%zu]\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("adding edge [%zu,%zu]\n", g[u].index, g[v].index);
add_edge(u, v, from_props, g);
} else {
// union of the two edges.
- DEBUG_PRINTF("updating edge [%zu,%zu]\n", g[u].index, g[v].index);
+ DEBUG_PRINTF("updating edge [%zu,%zu]\n", g[u].index, g[v].index);
RoseEdgeProps &to_props = g[*to_edge];
to_props.minBound = min(to_props.minBound, from_props.minBound);
to_props.maxBound = max(to_props.maxBound, from_props.maxBound);
@@ -484,7 +484,7 @@ void mergeEdges(RoseVertex a, RoseVertex b, RoseGraph &g) {
// Cache b's in-edges so we can look them up by source quickly.
for (const auto &e : in_edges_range(b, g)) {
RoseVertex u = source(e, g);
- b_edges.emplace(u, e);
+ b_edges.emplace(u, e);
}
// Add a's in-edges to b, merging them in where b already has the new edge.
@@ -503,7 +503,7 @@ void mergeEdges(RoseVertex a, RoseVertex b, RoseGraph &g) {
b_edges.clear();
for (const auto &e : out_edges_range(b, g)) {
RoseVertex v = target(e, g);
- b_edges.emplace(v, e);
+ b_edges.emplace(v, e);
}
// Add a's out-edges to b, merging them in where b already has the new edge.
@@ -523,11 +523,11 @@ void mergeEdges(RoseVertex a, RoseVertex b, RoseGraph &g) {
}
static
-void mergeLiteralSets(RoseVertex a, RoseVertex b, RoseBuildImpl &build) {
- RoseGraph &g = build.g;
+void mergeLiteralSets(RoseVertex a, RoseVertex b, RoseBuildImpl &build) {
+ RoseGraph &g = build.g;
const auto &a_literals = g[a].literals;
for (u32 lit_id : a_literals) {
- auto &lit_vertices = build.literal_info[lit_id].vertices;
+ auto &lit_vertices = build.literal_info[lit_id].vertices;
lit_vertices.erase(a);
lit_vertices.insert(b);
}
@@ -536,131 +536,131 @@ void mergeLiteralSets(RoseVertex a, RoseVertex b, RoseBuildImpl &build) {
}
static
-void updateAliasingInfo(RoseBuildImpl &build, RoseAliasingInfo &rai,
- RoseVertex a, RoseVertex b) {
- if (build.g[a].left) {
- const left_id left(build.g[a].left);
- assert(contains(rai.rev_leftfix[left], a));
- rai.rev_leftfix[left].erase(a);
- }
- if (contains(build.ghost, a)) {
- auto ghost = build.ghost.at(a);
- assert(contains(build.ghost, b) && ghost == build.ghost.at(b));
- build.ghost.erase(a);
- rai.rev_ghost[ghost].erase(a);
- }
-
- if (contains(rai.rev_ghost, a)) {
- for (const auto &v : rai.rev_ghost[a]) {
- build.ghost[v] = b;
- rai.rev_ghost[b].insert(v);
- }
- rai.rev_ghost.erase(a);
- }
-}
-
-/** \brief Common role merge code used by variants below. */
-static
-void mergeCommon(RoseBuildImpl &build, RoseAliasingInfo &rai, RoseVertex a,
- RoseVertex b) {
- RoseGraph &g = build.g;
-
+void updateAliasingInfo(RoseBuildImpl &build, RoseAliasingInfo &rai,
+ RoseVertex a, RoseVertex b) {
+ if (build.g[a].left) {
+ const left_id left(build.g[a].left);
+ assert(contains(rai.rev_leftfix[left], a));
+ rai.rev_leftfix[left].erase(a);
+ }
+ if (contains(build.ghost, a)) {
+ auto ghost = build.ghost.at(a);
+ assert(contains(build.ghost, b) && ghost == build.ghost.at(b));
+ build.ghost.erase(a);
+ rai.rev_ghost[ghost].erase(a);
+ }
+
+ if (contains(rai.rev_ghost, a)) {
+ for (const auto &v : rai.rev_ghost[a]) {
+ build.ghost[v] = b;
+ rai.rev_ghost[b].insert(v);
+ }
+ rai.rev_ghost.erase(a);
+ }
+}
+
+/** \brief Common role merge code used by variants below. */
+static
+void mergeCommon(RoseBuildImpl &build, RoseAliasingInfo &rai, RoseVertex a,
+ RoseVertex b) {
+ RoseGraph &g = build.g;
+
assert(g[a].eod_accept == g[b].eod_accept);
assert(g[a].left == g[b].left);
- assert(!g[a].suffix || g[a].suffix == g[b].suffix);
+ assert(!g[a].suffix || g[a].suffix == g[b].suffix);
// In some situations (ghost roles etc), we can have different groups.
assert(!g[a].groups && !g[b].groups); /* current structure means groups
* haven't been assigned yet */
g[b].groups |= g[a].groups;
- mergeLiteralSets(a, b, build);
- updateAliasingInfo(build, rai, a, b);
-
- // Our min and max_offsets should be sane.
- assert(g[b].min_offset <= g[b].max_offset);
-
- // Safety check: we should not have created through a merge a vertex that
- // has an out-edge with ANCH history but is not fixed-offset.
- assert(!hasAnchHistorySucc(g, b) || g[b].fixedOffset());
-}
-
-/** \brief Merge role 'a' into 'b', left merge path. */
-static
-void mergeVerticesLeft(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
- DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
-
- insert(&g[b].reports, g[a].reports);
-
- // Since it is a left merge (identical LHS) we should pick the tighter
- // bound.
- g[b].min_offset = max(g[a].min_offset, g[b].min_offset);
- g[b].max_offset = min(g[a].max_offset, g[b].max_offset);
-
+ mergeLiteralSets(a, b, build);
+ updateAliasingInfo(build, rai, a, b);
+
+ // Our min and max_offsets should be sane.
+ assert(g[b].min_offset <= g[b].max_offset);
+
+ // Safety check: we should not have created through a merge a vertex that
+ // has an out-edge with ANCH history but is not fixed-offset.
+ assert(!hasAnchHistorySucc(g, b) || g[b].fixedOffset());
+}
+
+/** \brief Merge role 'a' into 'b', left merge path. */
+static
+void mergeVerticesLeft(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
+ DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
+
+ insert(&g[b].reports, g[a].reports);
+
+ // Since it is a left merge (identical LHS) we should pick the tighter
+ // bound.
+ g[b].min_offset = max(g[a].min_offset, g[b].min_offset);
+ g[b].max_offset = min(g[a].max_offset, g[b].max_offset);
+
if (!g[b].suffix) {
g[b].suffix = g[a].suffix;
}
mergeEdges(a, b, g);
- mergeCommon(build, rai, a, b);
+ mergeCommon(build, rai, a, b);
+}
+
+/** \brief Merge role 'a' into 'b', right merge path. */
+static
+void mergeVerticesRight(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
+ DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
+
+ insert(&g[b].reports, g[a].reports);
+ g[b].min_offset = min(g[a].min_offset, g[b].min_offset);
+ g[b].max_offset = max(g[a].max_offset, g[b].max_offset);
+
+ mergeEdges(a, b, g);
+ mergeCommon(build, rai, a, b);
}
-/** \brief Merge role 'a' into 'b', right merge path. */
-static
-void mergeVerticesRight(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
- DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
-
- insert(&g[b].reports, g[a].reports);
- g[b].min_offset = min(g[a].min_offset, g[b].min_offset);
- g[b].max_offset = max(g[a].max_offset, g[b].max_offset);
-
- mergeEdges(a, b, g);
- mergeCommon(build, rai, a, b);
-}
-
/**
* Faster version of \ref mergeVertices for diamond merges, for which we know
* that the in- and out-edge sets, reports and suffixes are identical.
*/
static
-void mergeVerticesDiamond(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
- DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
+void mergeVerticesDiamond(RoseVertex a, RoseVertex b, RoseBuildImpl &build,
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
+ DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index);
- // For a diamond merge, most properties are already the same (with the
- // notable exception of the literal set).
+ // For a diamond merge, most properties are already the same (with the
+ // notable exception of the literal set).
assert(g[a].reports == g[b].reports);
assert(g[a].suffix == g[b].suffix);
g[b].min_offset = min(g[a].min_offset, g[b].min_offset);
g[b].max_offset = max(g[a].max_offset, g[b].max_offset);
- mergeCommon(build, rai, a, b);
+ mergeCommon(build, rai, a, b);
}
static never_inline
-void findCandidates(const RoseBuildImpl &build, CandidateSet *candidates) {
- for (auto v : vertices_range(build.g)) {
- if (isAliasingCandidate(v, build)) {
- DEBUG_PRINTF("candidate %zu\n", build.g[v].index);
- DEBUG_PRINTF("lits: %u\n", *build.g[v].literals.begin());
+void findCandidates(const RoseBuildImpl &build, CandidateSet *candidates) {
+ for (auto v : vertices_range(build.g)) {
+ if (isAliasingCandidate(v, build)) {
+ DEBUG_PRINTF("candidate %zu\n", build.g[v].index);
+ DEBUG_PRINTF("lits: %u\n", *build.g[v].literals.begin());
candidates->insert(v);
}
}
- assert(candidates->size() <= num_vertices(build.g));
+ assert(candidates->size() <= num_vertices(build.g));
DEBUG_PRINTF("found %zu/%zu candidates\n", candidates->size(),
- num_vertices(build.g));
+ num_vertices(build.g));
}
static
RoseVertex pickPred(const RoseVertex v, const RoseGraph &g,
- const RoseBuildImpl &build) {
+ const RoseBuildImpl &build) {
RoseGraph::in_edge_iterator ei, ee;
tie(ei, ee) = in_edges(v, g);
if (ei == ee) {
@@ -671,7 +671,7 @@ RoseVertex pickPred(const RoseVertex v, const RoseGraph &g,
// Avoid roots if we have other options, since it doesn't matter to the
// merge pass which predecessor we pick.
RoseVertex u = source(*ei, g);
- while (build.isAnyStart(u) && ++ei != ee) {
+ while (build.isAnyStart(u) && ++ei != ee) {
u = source(*ei, g);
}
return u;
@@ -700,7 +700,7 @@ bool hasCommonPredWithDiffRoses(RoseVertex a, RoseVertex b,
const bool equal_roses = hasEqualLeftfixes(a, b, g);
for (const auto &e_a : in_edges_range(a, g)) {
- if (RoseEdge e = edge(source(e_a, g), b, g)) {
+ if (RoseEdge e = edge(source(e_a, g), b, g)) {
DEBUG_PRINTF("common pred, e_r=%d r_t %u,%u\n",
(int)equal_roses, g[e].rose_top, g[e_a].rose_top);
if (!equal_roses) {
@@ -718,13 +718,13 @@ bool hasCommonPredWithDiffRoses(RoseVertex a, RoseVertex b,
}
static
-void pruneReportIfUnused(const RoseBuildImpl &build, shared_ptr<NGHolder> h,
+void pruneReportIfUnused(const RoseBuildImpl &build, shared_ptr<NGHolder> h,
const set<RoseVertex> &verts, ReportID report) {
DEBUG_PRINTF("trying to prune %u from %p (v %zu)\n", report, h.get(),
verts.size());
for (RoseVertex v : verts) {
- if (build.g[v].left.graph == h &&
- build.g[v].left.leftfix_report == report) {
+ if (build.g[v].left.graph == h &&
+ build.g[v].left.leftfix_report == report) {
DEBUG_PRINTF("report %u still in use\n", report);
return;
}
@@ -736,12 +736,12 @@ void pruneReportIfUnused(const RoseBuildImpl &build, shared_ptr<NGHolder> h,
// unimplementable.
DEBUG_PRINTF("report %u has been merged away, pruning\n", report);
- assert(h->kind == (build.isRootSuccessor(*verts.begin()) ? NFA_PREFIX
- : NFA_INFIX));
+ assert(h->kind == (build.isRootSuccessor(*verts.begin()) ? NFA_PREFIX
+ : NFA_INFIX));
unique_ptr<NGHolder> h_new = cloneHolder(*h);
pruneReport(*h_new, report);
- if (isImplementableNFA(*h_new, nullptr, build.cc)) {
+ if (isImplementableNFA(*h_new, nullptr, build.cc)) {
clear_graph(*h);
cloneHolder(*h, *h_new);
} else {
@@ -772,13 +772,13 @@ void pruneCastle(CastleProto &castle, ReportID report) {
/** \brief Set all reports to the given one. */
static
void setReports(CastleProto &castle, ReportID report) {
- castle.report_map.clear();
- for (auto &e : castle.repeats) {
- u32 top = e.first;
- auto &repeat = e.second;
+ castle.report_map.clear();
+ for (auto &e : castle.repeats) {
+ u32 top = e.first;
+ auto &repeat = e.second;
repeat.reports.clear();
repeat.reports.insert(report);
- castle.report_map[report].insert(top);
+ castle.report_map[report].insert(top);
}
}
@@ -792,7 +792,7 @@ void updateEdgeTops(RoseGraph &g, RoseVertex v, const map<u32, u32> &top_map) {
static
void pruneUnusedTops(CastleProto &castle, const RoseGraph &g,
const set<RoseVertex> &verts) {
- unordered_set<u32> used_tops;
+ unordered_set<u32> used_tops;
for (auto v : verts) {
assert(g[v].left.castle.get() == &castle);
@@ -817,13 +817,13 @@ void pruneUnusedTops(CastleProto &castle, const RoseGraph &g,
static
void pruneUnusedTops(NGHolder &h, const RoseGraph &g,
const set<RoseVertex> &verts) {
- if (!is_triggered(h)) {
- DEBUG_PRINTF("not triggered, no tops\n");
- return;
- }
- assert(isCorrectlyTopped(h));
- DEBUG_PRINTF("pruning unused tops\n");
- flat_set<u32> used_tops;
+ if (!is_triggered(h)) {
+ DEBUG_PRINTF("not triggered, no tops\n");
+ return;
+ }
+ assert(isCorrectlyTopped(h));
+ DEBUG_PRINTF("pruning unused tops\n");
+ flat_set<u32> used_tops;
for (auto v : verts) {
assert(g[v].left.graph.get() == &h);
@@ -839,13 +839,13 @@ void pruneUnusedTops(NGHolder &h, const RoseGraph &g,
if (v == h.startDs) {
continue; // stylised edge, leave it alone.
}
- flat_set<u32> pruned_tops;
- auto pt_inserter = inserter(pruned_tops, pruned_tops.end());
- set_intersection(h[e].tops.begin(), h[e].tops.end(),
- used_tops.begin(), used_tops.end(), pt_inserter);
- h[e].tops = std::move(pruned_tops);
- if (h[e].tops.empty()) {
- DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index);
+ flat_set<u32> pruned_tops;
+ auto pt_inserter = inserter(pruned_tops, pruned_tops.end());
+ set_intersection(h[e].tops.begin(), h[e].tops.end(),
+ used_tops.begin(), used_tops.end(), pt_inserter);
+ h[e].tops = std::move(pruned_tops);
+ if (h[e].tops.empty()) {
+ DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index);
dead.push_back(e);
}
}
@@ -860,9 +860,9 @@ void pruneUnusedTops(NGHolder &h, const RoseGraph &g,
}
static
-bool mergeSameCastle(RoseBuildImpl &build, RoseVertex a, RoseVertex b,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
+bool mergeSameCastle(RoseBuildImpl &build, RoseVertex a, RoseVertex b,
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
LeftEngInfo &a_left = g[a].left;
LeftEngInfo &b_left = g[b].left;
CastleProto &castle = *a_left.castle;
@@ -885,7 +885,7 @@ bool mergeSameCastle(RoseBuildImpl &build, RoseVertex a, RoseVertex b,
return false;
}
- const ReportID new_report = build.getNewNfaReport();
+ const ReportID new_report = build.getNewNfaReport();
map<u32, u32> a_top_map, b_top_map;
for (const auto &c : castle.repeats) {
@@ -907,9 +907,9 @@ bool mergeSameCastle(RoseBuildImpl &build, RoseVertex a, RoseVertex b,
}
}
- assert(contains(rai.rev_leftfix[b_left], b));
- rai.rev_leftfix[b_left].erase(b);
- rai.rev_leftfix[a_left].insert(b);
+ assert(contains(rai.rev_leftfix[b_left], b));
+ rai.rev_leftfix[b_left].erase(b);
+ rai.rev_leftfix[a_left].insert(b);
a_left.leftfix_report = new_report;
b_left.leftfix_report = new_report;
@@ -918,15 +918,15 @@ bool mergeSameCastle(RoseBuildImpl &build, RoseVertex a, RoseVertex b,
updateEdgeTops(g, a, a_top_map);
updateEdgeTops(g, b, b_top_map);
- pruneUnusedTops(castle, g, rai.rev_leftfix[a_left]);
+ pruneUnusedTops(castle, g, rai.rev_leftfix[a_left]);
return true;
}
static
-bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
+bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
RoseVertex b, bool trivialCasesOnly,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
LeftEngInfo &a_left = g[a].left;
LeftEngInfo &b_left = g[b].left;
left_id a_left_id(a_left);
@@ -944,28 +944,28 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
if (&a_castle == &b_castle) {
DEBUG_PRINTF("castles are the same\n");
- return mergeSameCastle(build, a, b, rai);
+ return mergeSameCastle(build, a, b, rai);
}
if (is_equal(a_castle, a_left.leftfix_report, b_castle,
b_left.leftfix_report)) {
DEBUG_PRINTF("castles are equiv with respect to reports\n");
- if (rai.rev_leftfix[a_left_id].size() == 1) {
+ if (rai.rev_leftfix[a_left_id].size() == 1) {
/* nobody else is using a_castle */
- rai.rev_leftfix[b_left_id].erase(b);
- rai.rev_leftfix[a_left_id].insert(b);
- pruneUnusedTops(b_castle, g, rai.rev_leftfix[b_left_id]);
+ rai.rev_leftfix[b_left_id].erase(b);
+ rai.rev_leftfix[a_left_id].insert(b);
+ pruneUnusedTops(b_castle, g, rai.rev_leftfix[b_left_id]);
b_left.castle = a_left.castle;
b_left.leftfix_report = a_left.leftfix_report;
DEBUG_PRINTF("OK -> only user of a_castle\n");
return true;
}
- if (rai.rev_leftfix[b_left_id].size() == 1) {
+ if (rai.rev_leftfix[b_left_id].size() == 1) {
/* nobody else is using b_castle */
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].insert(a);
- pruneUnusedTops(a_castle, g, rai.rev_leftfix[a_left_id]);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].insert(a);
+ pruneUnusedTops(a_castle, g, rai.rev_leftfix[a_left_id]);
a_left.castle = b_left.castle;
a_left.leftfix_report = b_left.leftfix_report;
DEBUG_PRINTF("OK -> only user of b_castle\n");
@@ -974,32 +974,32 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
if (preds_same) {
/* preds are the same anyway in diamond/left merges just need to
- * check that all the literals in rev_leftfix[b_h] can handle a_h */
- for (auto v : rai.rev_leftfix[b_left_id]) {
- if (!mergeableRoseVertices(build, a, v)) {
+ * check that all the literals in rev_leftfix[b_h] can handle a_h */
+ for (auto v : rai.rev_leftfix[b_left_id]) {
+ if (!mergeableRoseVertices(build, a, v)) {
goto literal_mismatch_1;
}
}
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].insert(a);
- pruneUnusedTops(a_castle, g, rai.rev_leftfix[a_left_id]);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].insert(a);
+ pruneUnusedTops(a_castle, g, rai.rev_leftfix[a_left_id]);
a_left.castle = b_left.castle;
a_left.leftfix_report = b_left.leftfix_report;
DEBUG_PRINTF("OK -> same preds ???\n");
return true;
literal_mismatch_1:
/* preds are the same anyway in diamond/left merges just need to
- * check that all the literals in rev_leftfix[a_h] can handle b_h */
- for (auto v : rai.rev_leftfix[a_left_id]) {
- if (!mergeableRoseVertices(build, v, b)) {
+ * check that all the literals in rev_leftfix[a_h] can handle b_h */
+ for (auto v : rai.rev_leftfix[a_left_id]) {
+ if (!mergeableRoseVertices(build, v, b)) {
goto literal_mismatch_2;
}
}
- rai.rev_leftfix[b_left_id].erase(b);
- rai.rev_leftfix[a_left_id].insert(b);
- pruneUnusedTops(b_castle, g, rai.rev_leftfix[b_left_id]);
+ rai.rev_leftfix[b_left_id].erase(b);
+ rai.rev_leftfix[a_left_id].insert(b);
+ pruneUnusedTops(b_castle, g, rai.rev_leftfix[b_left_id]);
b_left.castle = a_left.castle;
b_left.leftfix_report = a_left.leftfix_report;
DEBUG_PRINTF("OK -> same preds ???\n");
@@ -1010,15 +1010,15 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
/* we need to create a new graph as there may be other people
* using b_left and it would be bad if a's preds started triggering it
*/
- ReportID new_report = build.getNewNfaReport();
+ ReportID new_report = build.getNewNfaReport();
shared_ptr<CastleProto> new_castle = make_shared<CastleProto>(a_castle);
pruneCastle(*new_castle, a_left.leftfix_report);
setReports(*new_castle, new_report);
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].erase(b);
- pruneUnusedTops(*a_left.castle, g, rai.rev_leftfix[a_left_id]);
- pruneUnusedTops(*b_left.castle, g, rai.rev_leftfix[b_left_id]);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].erase(b);
+ pruneUnusedTops(*a_left.castle, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*b_left.castle, g, rai.rev_leftfix[b_left_id]);
a_left.leftfix_report = new_report;
b_left.leftfix_report = new_report;
@@ -1026,9 +1026,9 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
b_left.castle = new_castle;
assert(a_left == b_left);
- rai.rev_leftfix[a_left].insert(a);
- rai.rev_leftfix[a_left].insert(b);
- pruneUnusedTops(*new_castle, g, rai.rev_leftfix[a_left]);
+ rai.rev_leftfix[a_left].insert(a);
+ rai.rev_leftfix[a_left].insert(b);
+ pruneUnusedTops(*new_castle, g, rai.rev_leftfix[a_left]);
return true;
}
@@ -1040,27 +1040,27 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
// Only infixes. Prefixes require special care when doing non-trivial
// merges.
- if (!build.isNonRootSuccessor(a) || !build.isNonRootSuccessor(b)) {
+ if (!build.isNonRootSuccessor(a) || !build.isNonRootSuccessor(b)) {
return false;
}
- set<RoseVertex> &b_verts = rai.rev_leftfix[b_left_id];
+ set<RoseVertex> &b_verts = rai.rev_leftfix[b_left_id];
set<RoseVertex> aa;
aa.insert(a);
- if (!mergeableRoseVertices(build, aa, b_verts)) {
+ if (!mergeableRoseVertices(build, aa, b_verts)) {
DEBUG_PRINTF("vertices not mergeable\n");
return false;
}
- if (!build.cc.grey.roseMultiTopRoses || !build.cc.grey.allowCastle) {
+ if (!build.cc.grey.roseMultiTopRoses || !build.cc.grey.allowCastle) {
return false;
}
DEBUG_PRINTF("merging into new castle\n");
// Clone new castle with a's repeats in it, set to a new report.
- ReportID new_report = build.getNewNfaReport();
+ ReportID new_report = build.getNewNfaReport();
shared_ptr<CastleProto> m_castle = make_shared<CastleProto>(a_castle);
pruneCastle(*m_castle, a_left.leftfix_report);
setReports(*m_castle, new_report);
@@ -1079,7 +1079,7 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
// We should be protected from merging common preds with tops leading
// to completely different repeats by earlier checks, but just in
// case...
- if (RoseEdge a_edge = edge(source(e, g), a, g)) {
+ if (RoseEdge a_edge = edge(source(e, g), a, g)) {
u32 a_top = g[a_edge].rose_top;
const PureRepeat &a_pr = m_castle->repeats[a_top]; // new report
if (pr != a_pr) {
@@ -1101,10 +1101,10 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
DEBUG_PRINTF("merged into castle containing %zu repeats\n",
m_castle->repeats.size());
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].erase(b);
- pruneUnusedTops(*a_left.castle, g, rai.rev_leftfix[a_left_id]);
- pruneUnusedTops(*b_left.castle, g, rai.rev_leftfix[b_left_id]);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].erase(b);
+ pruneUnusedTops(*a_left.castle, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*b_left.castle, g, rai.rev_leftfix[b_left_id]);
a_left.castle = m_castle;
a_left.leftfix_report = new_report;
@@ -1112,17 +1112,17 @@ bool attemptRoseCastleMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
b_left.leftfix_report = new_report;
assert(a_left == b_left);
- rai.rev_leftfix[a_left].insert(a);
- rai.rev_leftfix[a_left].insert(b);
- pruneUnusedTops(*m_castle, g, rai.rev_leftfix[a_left]);
+ rai.rev_leftfix[a_left].insert(a);
+ rai.rev_leftfix[a_left].insert(b);
+ pruneUnusedTops(*m_castle, g, rai.rev_leftfix[a_left]);
return true;
}
static
-bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
+bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
RoseVertex b, bool trivialCasesOnly,
- RoseAliasingInfo &rai) {
- RoseGraph &g = build.g;
+ RoseAliasingInfo &rai) {
+ RoseGraph &g = build.g;
LeftEngInfo &a_left = g[a].left;
LeftEngInfo &b_left = g[b].left;
left_id a_left_id(a_left);
@@ -1130,8 +1130,8 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
shared_ptr<NGHolder> a_h = a_left.graph;
shared_ptr<NGHolder> b_h = b_left.graph;
assert(a_h && b_h);
- assert(isImplementableNFA(*a_h, nullptr, build.cc));
- assert(isImplementableNFA(*b_h, nullptr, build.cc));
+ assert(isImplementableNFA(*a_h, nullptr, build.cc));
+ assert(isImplementableNFA(*b_h, nullptr, build.cc));
// If we only differ in reports, this is a very easy merge. Just use b's
// report for both.
@@ -1141,74 +1141,74 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
DEBUG_PRINTF("OK -> same actual holder\n");
ReportID a_oldreport = a_left.leftfix_report;
ReportID b_oldreport = b_left.leftfix_report;
- ReportID new_report = build.getNewNfaReport();
+ ReportID new_report = build.getNewNfaReport();
duplicateReport(*a_h, a_left.leftfix_report, new_report);
duplicateReport(*b_h, b_left.leftfix_report, new_report);
a_left.leftfix_report = new_report;
b_left.leftfix_report = new_report;
- pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id],
- a_oldreport);
- pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id],
- b_oldreport);
- pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
+ pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id],
+ a_oldreport);
+ pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id],
+ b_oldreport);
+ pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
assert(a_left == b_left);
return true;
}
/* if it is the same graph, it is also fairly easy */
if (is_equal(*a_h, a_left.leftfix_report, *b_h, b_left.leftfix_report)) {
- if (rai.rev_leftfix[a_left_id].size() == 1) {
+ if (rai.rev_leftfix[a_left_id].size() == 1) {
/* nobody else is using a_h */
- rai.rev_leftfix[b_left_id].erase(b);
- rai.rev_leftfix[a_left_id].insert(b);
+ rai.rev_leftfix[b_left_id].erase(b);
+ rai.rev_leftfix[a_left_id].insert(b);
b_left.graph = a_h;
b_left.leftfix_report = a_left.leftfix_report;
- pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
+ pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
DEBUG_PRINTF("OK -> only user of a_h\n");
return true;
}
- if (rai.rev_leftfix[b_left_id].size() == 1) {
+ if (rai.rev_leftfix[b_left_id].size() == 1) {
/* nobody else is using b_h */
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].insert(a);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].insert(a);
a_left.graph = b_h;
a_left.leftfix_report = b_left.leftfix_report;
- pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
DEBUG_PRINTF("OK -> only user of b_h\n");
return true;
}
if (preds_same) {
/* preds are the same anyway in diamond/left merges just need to
- * check that all the literals in rev_leftfix[b_h] can handle a_h */
- for (auto v : rai.rev_leftfix[b_left_id]) {
- if (!mergeableRoseVertices(build, a, v)) {
+ * check that all the literals in rev_leftfix[b_h] can handle a_h */
+ for (auto v : rai.rev_leftfix[b_left_id]) {
+ if (!mergeableRoseVertices(build, a, v)) {
goto literal_mismatch_1;
}
}
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].insert(a);
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].insert(a);
a_left.graph = b_h;
a_left.leftfix_report = b_left.leftfix_report;
- pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
DEBUG_PRINTF("OK -> same preds ???\n");
return true;
literal_mismatch_1:
/* preds are the same anyway in diamond/left merges just need to
- * check that all the literals in rev_leftfix[a_h] can handle b_h */
- for (auto v : rai.rev_leftfix[a_left_id]) {
- if (!mergeableRoseVertices(build, v, b)) {
+ * check that all the literals in rev_leftfix[a_h] can handle b_h */
+ for (auto v : rai.rev_leftfix[a_left_id]) {
+ if (!mergeableRoseVertices(build, v, b)) {
goto literal_mismatch_2;
}
}
- rai.rev_leftfix[b_left_id].erase(b);
- rai.rev_leftfix[a_left_id].insert(b);
+ rai.rev_leftfix[b_left_id].erase(b);
+ rai.rev_leftfix[a_left_id].insert(b);
b_left.graph = a_h;
b_left.leftfix_report = a_left.leftfix_report;
- pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
+ pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
DEBUG_PRINTF("OK -> same preds ???\n");
return true;
literal_mismatch_2:;
@@ -1217,29 +1217,29 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
/* we need to create a new graph as there may be other people
* using b_left and it would be bad if a's preds started triggering it
*/
- ReportID new_report = build.getNewNfaReport();
+ ReportID new_report = build.getNewNfaReport();
shared_ptr<NGHolder> new_graph = cloneHolder(*b_h);
duplicateReport(*new_graph, b_left.leftfix_report, new_report);
- pruneAllOtherReports(*new_graph, new_report);
-
- if (!isImplementableNFA(*new_graph, nullptr, build.cc)) {
- DEBUG_PRINTF("new graph not implementable\n");
- return false;
- }
-
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].erase(b);
- pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
- pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
-
+ pruneAllOtherReports(*new_graph, new_report);
+
+ if (!isImplementableNFA(*new_graph, nullptr, build.cc)) {
+ DEBUG_PRINTF("new graph not implementable\n");
+ return false;
+ }
+
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].erase(b);
+ pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
+
a_left.leftfix_report = new_report;
b_left.leftfix_report = new_report;
a_left.graph = new_graph;
b_left.graph = new_graph;
- rai.rev_leftfix[a_left].insert(a);
- rai.rev_leftfix[a_left].insert(b);
- pruneUnusedTops(*new_graph, g, rai.rev_leftfix[a_left]);
+ rai.rev_leftfix[a_left].insert(a);
+ rai.rev_leftfix[a_left].insert(b);
+ pruneUnusedTops(*new_graph, g, rai.rev_leftfix[a_left]);
return true;
}
@@ -1251,23 +1251,23 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
// Only infixes. Prefixes require special care when doing non-trivial
// merges.
- if (!build.isNonRootSuccessor(a) || !build.isNonRootSuccessor(b)) {
+ if (!build.isNonRootSuccessor(a) || !build.isNonRootSuccessor(b)) {
return false;
}
DEBUG_PRINTF("attempting merge of roses on vertices %zu and %zu\n",
- g[a].index, g[b].index);
+ g[a].index, g[b].index);
- set<RoseVertex> &b_verts = rai.rev_leftfix[b_left];
+ set<RoseVertex> &b_verts = rai.rev_leftfix[b_left];
set<RoseVertex> aa;
aa.insert(a);
- if (!mergeableRoseVertices(build, aa, b_verts)) {
+ if (!mergeableRoseVertices(build, aa, b_verts)) {
DEBUG_PRINTF("vertices not mergeable\n");
return false;
}
- if (!build.cc.grey.roseMultiTopRoses) {
+ if (!build.cc.grey.roseMultiTopRoses) {
return false;
}
@@ -1277,10 +1277,10 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
/* We need to allocate a new report id because */
ReportID a_oldreport = a_left.leftfix_report;
ReportID b_oldreport = b_left.leftfix_report;
- ReportID new_report = build.getNewNfaReport();
+ ReportID new_report = build.getNewNfaReport();
duplicateReport(*b_h, b_left.leftfix_report, new_report);
b_left.leftfix_report = new_report;
- pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id], b_oldreport);
+ pruneReportIfUnused(build, b_h, rai.rev_leftfix[b_left_id], b_oldreport);
NGHolder victim;
cloneHolder(victim, *a_h);
@@ -1296,22 +1296,22 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
DEBUG_PRINTF("winner %zu states\n", num_vertices(*b_h));
if (!setDistinctRoseTops(g, victim, *b_h, deque<RoseVertex>(1, a))) {
- assert(roseHasTops(build, a));
- assert(roseHasTops(build, b));
+ assert(roseHasTops(build, a));
+ assert(roseHasTops(build, b));
return false;
}
assert(victim.kind == b_h->kind);
assert(!generates_callbacks(*b_h));
- if (!mergeNfaPair(victim, *b_h, nullptr, build.cc)) {
+ if (!mergeNfaPair(victim, *b_h, nullptr, build.cc)) {
DEBUG_PRINTF("merge failed\n");
// Restore in-edge properties.
for (const auto &e : in_edges_range(a, g)) {
g[e] = a_props[source(e, g)];
}
- assert(roseHasTops(build, a));
- assert(roseHasTops(build, b));
+ assert(roseHasTops(build, a));
+ assert(roseHasTops(build, b));
return false;
}
@@ -1321,22 +1321,22 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
a_left.graph = b_h;
a_left.leftfix_report = new_report;
- assert(contains(rai.rev_leftfix[a_left_id], a));
- assert(contains(rai.rev_leftfix[b_left_id], b));
- rai.rev_leftfix[a_left_id].erase(a);
- rai.rev_leftfix[b_left_id].insert(a);
+ assert(contains(rai.rev_leftfix[a_left_id], a));
+ assert(contains(rai.rev_leftfix[b_left_id], b));
+ rai.rev_leftfix[a_left_id].erase(a);
+ rai.rev_leftfix[b_left_id].insert(a);
- pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
- pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
+ pruneUnusedTops(*a_h, g, rai.rev_leftfix[a_left_id]);
+ pruneUnusedTops(*b_h, g, rai.rev_leftfix[b_left_id]);
// Prune A's report from its old prefix if it was only used by A.
- pruneReportIfUnused(build, a_h, rai.rev_leftfix[a_left_id], a_oldreport);
+ pruneReportIfUnused(build, a_h, rai.rev_leftfix[a_left_id], a_oldreport);
- reduceImplementableGraph(*b_h, SOM_NONE, nullptr, build.cc);
+ reduceImplementableGraph(*b_h, SOM_NONE, nullptr, build.cc);
- assert(roseHasTops(build, a));
- assert(roseHasTops(build, b));
- assert(isImplementableNFA(*b_h, nullptr, build.cc));
+ assert(roseHasTops(build, a));
+ assert(roseHasTops(build, b));
+ assert(isImplementableNFA(*b_h, nullptr, build.cc));
return true;
}
@@ -1344,14 +1344,14 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
// the two LeftEngInfo structures to be the same. Returns false if the merge
// is not possible.
static
-bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
- RoseVertex b, bool trivialCasesOnly,
- RoseAliasingInfo &rai) {
+bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
+ RoseVertex b, bool trivialCasesOnly,
+ RoseAliasingInfo &rai) {
DEBUG_PRINTF("attempting rose merge, vertices a=%zu, b=%zu\n",
- build.g[a].index, build.g[b].index);
+ build.g[a].index, build.g[b].index);
assert(a != b);
- RoseGraph &g = build.g;
+ RoseGraph &g = build.g;
LeftEngInfo &a_left = g[a].left;
LeftEngInfo &b_left = g[b].left;
@@ -1375,8 +1375,8 @@ bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
}
// Only non-transients for the moment.
- if (contains(build.transient, a_left_id) ||
- contains(build.transient, b_left_id)) {
+ if (contains(build.transient, a_left_id) ||
+ contains(build.transient, b_left_id)) {
return false;
}
@@ -1386,117 +1386,117 @@ bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
return false;
}
- assert(roseHasTops(build, a));
- assert(roseHasTops(build, b));
+ assert(roseHasTops(build, a));
+ assert(roseHasTops(build, b));
if (a_left_id.graph() && b_left_id.graph()) {
- return attemptRoseGraphMerge(build, preds_same, a, b, trivialCasesOnly,
- rai);
+ return attemptRoseGraphMerge(build, preds_same, a, b, trivialCasesOnly,
+ rai);
}
if (a_left_id.castle() && b_left_id.castle()) {
- return attemptRoseCastleMerge(build, preds_same, a, b, trivialCasesOnly,
- rai);
+ return attemptRoseCastleMerge(build, preds_same, a, b, trivialCasesOnly,
+ rai);
}
return false;
}
-/**
- * \brief Buckets that only contain one vertex are never going to lead to a
- * merge.
- */
+/**
+ * \brief Buckets that only contain one vertex are never going to lead to a
+ * merge.
+ */
static
-void removeSingletonBuckets(vector<vector<RoseVertex>> &buckets) {
- auto it = remove_if(
- begin(buckets), end(buckets),
- [](const vector<RoseVertex> &bucket) { return bucket.size() < 2; });
- if (it != end(buckets)) {
- DEBUG_PRINTF("deleting %zu singleton buckets\n",
- distance(it, end(buckets)));
- buckets.erase(it, end(buckets));
+void removeSingletonBuckets(vector<vector<RoseVertex>> &buckets) {
+ auto it = remove_if(
+ begin(buckets), end(buckets),
+ [](const vector<RoseVertex> &bucket) { return bucket.size() < 2; });
+ if (it != end(buckets)) {
+ DEBUG_PRINTF("deleting %zu singleton buckets\n",
+ distance(it, end(buckets)));
+ buckets.erase(it, end(buckets));
}
}
static
-void buildInvBucketMap(const vector<vector<RoseVertex>> &buckets,
- unordered_map<RoseVertex, size_t> &inv) {
- inv.clear();
- for (size_t i = 0; i < buckets.size(); i++) {
- for (auto v : buckets[i]) {
- assert(!contains(inv, v));
- inv.emplace(v, i);
- }
- }
-}
-
-/**
- * \brief Generic splitter that will use the given split function to partition
- * the vector of buckets, then remove buckets with <= 1 entry.
- */
-template <class SplitFunction>
-void splitAndFilterBuckets(vector<vector<RoseVertex>> &buckets,
- const SplitFunction &make_split_key) {
- if (buckets.empty()) {
- return;
- }
-
+void buildInvBucketMap(const vector<vector<RoseVertex>> &buckets,
+ unordered_map<RoseVertex, size_t> &inv) {
+ inv.clear();
+ for (size_t i = 0; i < buckets.size(); i++) {
+ for (auto v : buckets[i]) {
+ assert(!contains(inv, v));
+ inv.emplace(v, i);
+ }
+ }
+}
+
+/**
+ * \brief Generic splitter that will use the given split function to partition
+ * the vector of buckets, then remove buckets with <= 1 entry.
+ */
+template <class SplitFunction>
+void splitAndFilterBuckets(vector<vector<RoseVertex>> &buckets,
+ const SplitFunction &make_split_key) {
+ if (buckets.empty()) {
+ return;
+ }
+
vector<vector<RoseVertex>> out;
- // Mapping from split key value to new bucket index.
- using key_type = decltype(make_split_key(RoseGraph::null_vertex()));
- unordered_map<key_type, size_t> dest_map;
- dest_map.reserve(buckets.front().size());
-
+ // Mapping from split key value to new bucket index.
+ using key_type = decltype(make_split_key(RoseGraph::null_vertex()));
+ unordered_map<key_type, size_t> dest_map;
+ dest_map.reserve(buckets.front().size());
+
for (const auto &bucket : buckets) {
assert(!bucket.empty());
- dest_map.clear();
+ dest_map.clear();
for (RoseVertex v : bucket) {
- auto p = dest_map.emplace(make_split_key(v), out.size());
- if (p.second) { // New key, add a bucket.
- out.emplace_back();
+ auto p = dest_map.emplace(make_split_key(v), out.size());
+ if (p.second) { // New key, add a bucket.
+ out.emplace_back();
}
- auto out_bucket = p.first->second;
+ auto out_bucket = p.first->second;
out[out_bucket].push_back(v);
}
}
- if (out.size() == buckets.size()) {
- return; // No new buckets created.
- }
-
- buckets = std::move(out);
- removeSingletonBuckets(buckets);
+ if (out.size() == buckets.size()) {
+ return; // No new buckets created.
+ }
+
+ buckets = std::move(out);
+ removeSingletonBuckets(buckets);
+}
+
+static
+void splitByReportSuffixBehaviour(const RoseGraph &g,
+ vector<vector<RoseVertex>> &buckets) {
+ // Split by report set and suffix info.
+ auto make_split_key = [&g](RoseVertex v) {
+ return hash_all(g[v].reports, g[v].suffix);
+ };
+ splitAndFilterBuckets(buckets, make_split_key);
+}
+
+static
+void splitByLiteralTable(const RoseBuildImpl &build,
+ vector<vector<RoseVertex>> &buckets) {
+ const RoseGraph &g = build.g;
+
+ // Split by literal table.
+ auto make_split_key = [&](RoseVertex v) {
+ const auto &lits = g[v].literals;
+ assert(!lits.empty());
+ auto table = build.literals.at(*lits.begin()).table;
+ return std::underlying_type<decltype(table)>::type(table);
+ };
+ splitAndFilterBuckets(buckets, make_split_key);
}
static
-void splitByReportSuffixBehaviour(const RoseGraph &g,
- vector<vector<RoseVertex>> &buckets) {
- // Split by report set and suffix info.
- auto make_split_key = [&g](RoseVertex v) {
- return hash_all(g[v].reports, g[v].suffix);
- };
- splitAndFilterBuckets(buckets, make_split_key);
-}
-
-static
-void splitByLiteralTable(const RoseBuildImpl &build,
- vector<vector<RoseVertex>> &buckets) {
- const RoseGraph &g = build.g;
-
- // Split by literal table.
- auto make_split_key = [&](RoseVertex v) {
- const auto &lits = g[v].literals;
- assert(!lits.empty());
- auto table = build.literals.at(*lits.begin()).table;
- return std::underlying_type<decltype(table)>::type(table);
- };
- splitAndFilterBuckets(buckets, make_split_key);
-}
-
-static
void splitByNeighbour(const RoseGraph &g, vector<vector<RoseVertex>> &buckets,
- unordered_map<RoseVertex, size_t> &inv, bool succ) {
+ unordered_map<RoseVertex, size_t> &inv, bool succ) {
vector<vector<RoseVertex>> extras;
map<size_t, vector<RoseVertex>> neighbours_by_bucket;
set<RoseVertex> picked;
@@ -1552,63 +1552,63 @@ void splitByNeighbour(const RoseGraph &g, vector<vector<RoseVertex>> &buckets,
}
insert(&buckets, buckets.end(), extras);
}
-
- removeSingletonBuckets(buckets);
- buildInvBucketMap(buckets, inv);
+
+ removeSingletonBuckets(buckets);
+ buildInvBucketMap(buckets, inv);
}
static
-vector<vector<RoseVertex>>
-splitDiamondMergeBuckets(CandidateSet &candidates, const RoseBuildImpl &build) {
+vector<vector<RoseVertex>>
+splitDiamondMergeBuckets(CandidateSet &candidates, const RoseBuildImpl &build) {
const RoseGraph &g = build.g;
vector<vector<RoseVertex>> buckets(1);
- buckets[0].reserve(candidates.size());
- insert(&buckets[0], buckets[0].end(), candidates);
-
- DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
-
- splitByReportSuffixBehaviour(g, buckets);
- DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
- if (buckets.empty()) {
- return buckets;
- }
-
- splitByLiteralTable(build, buckets);
- DEBUG_PRINTF("split by lit table, %zu buckets\n", buckets.size());
- if (buckets.empty()) {
- return buckets;
- }
-
- // Neighbour splits require inverse map.
- unordered_map<RoseVertex, size_t> inv;
- buildInvBucketMap(buckets, inv);
-
+ buckets[0].reserve(candidates.size());
+ insert(&buckets[0], buckets[0].end(), candidates);
+
+ DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
+
+ splitByReportSuffixBehaviour(g, buckets);
+ DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
+ if (buckets.empty()) {
+ return buckets;
+ }
+
+ splitByLiteralTable(build, buckets);
+ DEBUG_PRINTF("split by lit table, %zu buckets\n", buckets.size());
+ if (buckets.empty()) {
+ return buckets;
+ }
+
+ // Neighbour splits require inverse map.
+ unordered_map<RoseVertex, size_t> inv;
+ buildInvBucketMap(buckets, inv);
+
splitByNeighbour(g, buckets, inv, true);
- DEBUG_PRINTF("split by successor, %zu buckets\n", buckets.size());
- if (buckets.empty()) {
- return buckets;
- }
-
+ DEBUG_PRINTF("split by successor, %zu buckets\n", buckets.size());
+ if (buckets.empty()) {
+ return buckets;
+ }
+
splitByNeighbour(g, buckets, inv, false);
- DEBUG_PRINTF("split by predecessor, %zu buckets\n", buckets.size());
+ DEBUG_PRINTF("split by predecessor, %zu buckets\n", buckets.size());
return buckets;
}
-
+
static never_inline
-void diamondMergePass(CandidateSet &candidates, RoseBuildImpl &build,
+void diamondMergePass(CandidateSet &candidates, RoseBuildImpl &build,
vector<RoseVertex> *dead, bool mergeRoses,
- RoseAliasingInfo &rai) {
+ RoseAliasingInfo &rai) {
DEBUG_PRINTF("begin\n");
- RoseGraph &g = build.g;
+ RoseGraph &g = build.g;
if (candidates.empty()) {
return;
}
/* Vertices may only be diamond merged with others in the same bucket */
- auto cand_buckets = splitDiamondMergeBuckets(candidates, build);
+ auto cand_buckets = splitDiamondMergeBuckets(candidates, build);
for (const vector<RoseVertex> &siblings : cand_buckets) {
for (auto it = siblings.begin(); it != siblings.end();) {
@@ -1617,12 +1617,12 @@ void diamondMergePass(CandidateSet &candidates, RoseBuildImpl &build,
assert(contains(candidates, a));
- DEBUG_PRINTF("trying to merge %zu into somebody\n", g[a].index);
+ DEBUG_PRINTF("trying to merge %zu into somebody\n", g[a].index);
for (auto jt = it; jt != siblings.end(); ++jt) {
RoseVertex b = *jt;
assert(contains(candidates, b));
- if (!sameRoleProperties(build, rai, a, b)) {
+ if (!sameRoleProperties(build, rai, a, b)) {
DEBUG_PRINTF("diff role prop\n");
continue;
}
@@ -1633,23 +1633,23 @@ void diamondMergePass(CandidateSet &candidates, RoseBuildImpl &build,
* so we still have to checks successors and predecessors. */
if (!sameSuccessors(a, b, g)
- || !sameRightRoleProperties(build, a, b)
+ || !sameRightRoleProperties(build, a, b)
|| !samePredecessors(a, b, g)) {
DEBUG_PRINTF("not diamond\n");
continue;
}
- if (!canMergeLiterals(a, b, build)) {
+ if (!canMergeLiterals(a, b, build)) {
DEBUG_PRINTF("incompatible lits\n");
continue;
}
- if (!attemptRoseMerge(build, true, a, b, !mergeRoses, rai)) {
+ if (!attemptRoseMerge(build, true, a, b, !mergeRoses, rai)) {
DEBUG_PRINTF("rose fail\n");
continue;
}
- mergeVerticesDiamond(a, b, build, rai);
+ mergeVerticesDiamond(a, b, build, rai);
dead->push_back(a);
candidates.erase(a);
break; // next a
@@ -1665,7 +1665,7 @@ vector<RoseVertex>::iterator findLeftMergeSibling(
vector<RoseVertex>::iterator it,
const vector<RoseVertex>::iterator &end,
const RoseVertex a, const RoseBuildImpl &build,
- const RoseAliasingInfo &rai,
+ const RoseAliasingInfo &rai,
const CandidateSet &candidates) {
const RoseGraph &g = build.g;
@@ -1679,7 +1679,7 @@ vector<RoseVertex>::iterator findLeftMergeSibling(
continue;
}
- if (!sameRoleProperties(build, rai, a, b)) {
+ if (!sameRoleProperties(build, rai, a, b)) {
continue;
}
@@ -1708,66 +1708,66 @@ vector<RoseVertex>::iterator findLeftMergeSibling(
return end;
}
-static
-void getLeftMergeSiblings(const RoseBuildImpl &build, RoseVertex a,
- vector<RoseVertex> &siblings) {
- // We have to find a sibling to merge `a' with, and we select between
- // two approaches to minimize the number of vertices we have to
- // examine; which we use depends on the shape of the graph.
-
- const RoseGraph &g = build.g;
- assert(!g[a].literals.empty());
- u32 lit_id = *g[a].literals.begin();
- const auto &verts = build.literal_info.at(lit_id).vertices;
- RoseVertex pred = pickPred(a, g, build);
-
- siblings.clear();
-
- if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred) ||
- out_degree(pred, g) > verts.size()) {
- // Select sibling from amongst the vertices that share a literal.
- insert(&siblings, siblings.end(), verts);
- } else {
- // Select sibling from amongst the vertices that share a
- // predecessor.
- insert(&siblings, siblings.end(), adjacent_vertices(pred, g));
- }
-}
-
+static
+void getLeftMergeSiblings(const RoseBuildImpl &build, RoseVertex a,
+ vector<RoseVertex> &siblings) {
+ // We have to find a sibling to merge `a' with, and we select between
+ // two approaches to minimize the number of vertices we have to
+ // examine; which we use depends on the shape of the graph.
+
+ const RoseGraph &g = build.g;
+ assert(!g[a].literals.empty());
+ u32 lit_id = *g[a].literals.begin();
+ const auto &verts = build.literal_info.at(lit_id).vertices;
+ RoseVertex pred = pickPred(a, g, build);
+
+ siblings.clear();
+
+ if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred) ||
+ out_degree(pred, g) > verts.size()) {
+ // Select sibling from amongst the vertices that share a literal.
+ insert(&siblings, siblings.end(), verts);
+ } else {
+ // Select sibling from amongst the vertices that share a
+ // predecessor.
+ insert(&siblings, siblings.end(), adjacent_vertices(pred, g));
+ }
+}
+
static never_inline
-void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build,
- vector<RoseVertex> *dead, RoseAliasingInfo &rai) {
+void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build,
+ vector<RoseVertex> *dead, RoseAliasingInfo &rai) {
DEBUG_PRINTF("begin (%zu)\n", candidates.size());
vector<RoseVertex> siblings;
- auto it = candidates.begin();
+ auto it = candidates.begin();
while (it != candidates.end()) {
RoseVertex a = *it;
CandidateSet::iterator ait = it;
++it;
- getLeftMergeSiblings(build, a, siblings);
+ getLeftMergeSiblings(build, a, siblings);
- auto jt = siblings.begin();
- while (jt != siblings.end()) {
- jt = findLeftMergeSibling(jt, siblings.end(), a, build, rai,
- candidates);
- if (jt == siblings.end()) {
- break;
- }
- RoseVertex b = *jt;
- if (attemptRoseMerge(build, true, a, b, false, rai)) {
- mergeVerticesLeft(a, b, build, rai);
- dead->push_back(a);
- candidates.erase(ait);
- break; // consider next a
- }
- ++jt;
+ auto jt = siblings.begin();
+ while (jt != siblings.end()) {
+ jt = findLeftMergeSibling(jt, siblings.end(), a, build, rai,
+ candidates);
+ if (jt == siblings.end()) {
+ break;
+ }
+ RoseVertex b = *jt;
+ if (attemptRoseMerge(build, true, a, b, false, rai)) {
+ mergeVerticesLeft(a, b, build, rai);
+ dead->push_back(a);
+ candidates.erase(ait);
+ break; // consider next a
+ }
+ ++jt;
}
}
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
- assert(!hasOrphanedTops(build));
+ assert(!hasOrphanedTops(build));
}
// Can't merge vertices with different root predecessors.
@@ -1776,12 +1776,12 @@ bool safeRootPreds(RoseVertex a, RoseVertex b, const RoseGraph &g) {
set<RoseVertex> a_roots, b_roots;
for (auto u : inv_adjacent_vertices_range(a, g)) {
- if (!in_degree(u, g)) {
+ if (!in_degree(u, g)) {
a_roots.insert(u);
}
}
for (auto u : inv_adjacent_vertices_range(b, g)) {
- if (!in_degree(u, g)) {
+ if (!in_degree(u, g)) {
b_roots.insert(u);
}
}
@@ -1797,7 +1797,7 @@ vector<RoseVertex>::const_iterator findRightMergeSibling(
vector<RoseVertex>::const_iterator it,
const vector<RoseVertex>::const_iterator &end,
const RoseVertex a, const RoseBuildImpl &build,
- const RoseAliasingInfo &rai,
+ const RoseAliasingInfo &rai,
const CandidateSet &candidates) {
const RoseGraph &g = build.g;
@@ -1811,7 +1811,7 @@ vector<RoseVertex>::const_iterator findRightMergeSibling(
continue;
}
- if (!sameRoleProperties(build, rai, a, b)) {
+ if (!sameRoleProperties(build, rai, a, b)) {
continue;
}
@@ -1849,85 +1849,85 @@ vector<RoseVertex>::const_iterator findRightMergeSibling(
}
static
-void splitByRightProps(const RoseGraph &g,
- vector<vector<RoseVertex>> &buckets) {
- // Successor vector used in make_split_key. We declare it here so we can
- // reuse storage.
- vector<RoseVertex> succ;
-
- // Split by {successors, literals, reports}.
- auto make_split_key = [&](RoseVertex v) {
- succ.clear();
- insert(&succ, succ.end(), adjacent_vertices(v, g));
- sort(succ.begin(), succ.end());
- return hash_all(g[v].literals, g[v].reports, succ);
- };
- splitAndFilterBuckets(buckets, make_split_key);
+void splitByRightProps(const RoseGraph &g,
+ vector<vector<RoseVertex>> &buckets) {
+ // Successor vector used in make_split_key. We declare it here so we can
+ // reuse storage.
+ vector<RoseVertex> succ;
+
+ // Split by {successors, literals, reports}.
+ auto make_split_key = [&](RoseVertex v) {
+ succ.clear();
+ insert(&succ, succ.end(), adjacent_vertices(v, g));
+ sort(succ.begin(), succ.end());
+ return hash_all(g[v].literals, g[v].reports, succ);
+ };
+ splitAndFilterBuckets(buckets, make_split_key);
}
static never_inline
-vector<vector<RoseVertex>>
-splitRightMergeBuckets(const CandidateSet &candidates,
- const RoseBuildImpl &build) {
- const RoseGraph &g = build.g;
+vector<vector<RoseVertex>>
+splitRightMergeBuckets(const CandidateSet &candidates,
+ const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
- vector<vector<RoseVertex>> buckets(1);
- buckets[0].reserve(candidates.size());
- insert(&buckets[0], buckets[0].end(), candidates);
+ vector<vector<RoseVertex>> buckets(1);
+ buckets[0].reserve(candidates.size());
+ insert(&buckets[0], buckets[0].end(), candidates);
- DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
+ DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
- splitByReportSuffixBehaviour(g, buckets);
- DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
- if (buckets.empty()) {
- return buckets;
+ splitByReportSuffixBehaviour(g, buckets);
+ DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
+ if (buckets.empty()) {
+ return buckets;
}
- splitByRightProps(g, buckets);
- DEBUG_PRINTF("split by right-merge properties, %zu buckets\n",
- buckets.size());
- if (buckets.empty()) {
- return buckets;
+ splitByRightProps(g, buckets);
+ DEBUG_PRINTF("split by right-merge properties, %zu buckets\n",
+ buckets.size());
+ if (buckets.empty()) {
+ return buckets;
}
- return buckets;
+ return buckets;
}
static never_inline
-void rightMergePass(CandidateSet &candidates, RoseBuildImpl &build,
+void rightMergePass(CandidateSet &candidates, RoseBuildImpl &build,
vector<RoseVertex> *dead, bool mergeRoses,
- RoseAliasingInfo &rai) {
+ RoseAliasingInfo &rai) {
DEBUG_PRINTF("begin\n");
- if (candidates.empty()) {
- return;
- }
-
- auto buckets = splitRightMergeBuckets(candidates, build);
-
- for (const auto &bucket : buckets) {
- assert(!bucket.empty());
- for (auto it = bucket.begin(); it != bucket.end(); it++) {
- RoseVertex a = *it;
- for (auto jt = bucket.begin(); jt != bucket.end(); jt++) {
- jt = findRightMergeSibling(jt, bucket.end(), a, build, rai,
- candidates);
- if (jt == bucket.end()) {
- break;
- }
- RoseVertex b = *jt;
- if (attemptRoseMerge(build, false, a, b, !mergeRoses, rai)) {
- mergeVerticesRight(a, b, build, rai);
- dead->push_back(a);
- candidates.erase(a);
- break; // consider next a
- }
+ if (candidates.empty()) {
+ return;
+ }
+
+ auto buckets = splitRightMergeBuckets(candidates, build);
+
+ for (const auto &bucket : buckets) {
+ assert(!bucket.empty());
+ for (auto it = bucket.begin(); it != bucket.end(); it++) {
+ RoseVertex a = *it;
+ for (auto jt = bucket.begin(); jt != bucket.end(); jt++) {
+ jt = findRightMergeSibling(jt, bucket.end(), a, build, rai,
+ candidates);
+ if (jt == bucket.end()) {
+ break;
+ }
+ RoseVertex b = *jt;
+ if (attemptRoseMerge(build, false, a, b, !mergeRoses, rai)) {
+ mergeVerticesRight(a, b, build, rai);
+ dead->push_back(a);
+ candidates.erase(a);
+ break; // consider next a
+ }
}
}
}
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
- assert(!hasOrphanedTops(build));
+ assert(!hasOrphanedTops(build));
}
/**
@@ -1942,7 +1942,7 @@ bool hasNoDiamondSiblings(const RoseGraph &g, RoseVertex v) {
if (has_successor(v, g)) {
bool only_succ = true;
for (const auto &w : adjacent_vertices_range(v, g)) {
- if (in_degree(w, g) > 1) {
+ if (in_degree(w, g) > 1) {
only_succ = false;
break;
}
@@ -1958,7 +1958,7 @@ bool hasNoDiamondSiblings(const RoseGraph &g, RoseVertex v) {
bool only_pred = true;
for (const auto &u : inv_adjacent_vertices_range(v, g)) {
- if (out_degree(u, g) > 1) {
+ if (out_degree(u, g) > 1) {
only_pred = false;
break;
}
@@ -1993,8 +1993,8 @@ void filterDiamondCandidates(RoseGraph &g, CandidateSet &candidates) {
void aliasRoles(RoseBuildImpl &build, bool mergeRoses) {
const CompileContext &cc = build.cc;
RoseGraph &g = build.g;
- assert(!hasOrphanedTops(build));
- assert(canImplementGraphs(build));
+ assert(!hasOrphanedTops(build));
+ assert(canImplementGraphs(build));
if (!cc.grey.roseRoleAliasing || !cc.grey.roseGraphReduction) {
return;
@@ -2002,11 +2002,11 @@ void aliasRoles(RoseBuildImpl &build, bool mergeRoses) {
DEBUG_PRINTF("doing role aliasing mr=%d\n", (int)mergeRoses);
- RoseAliasingInfo rai(build);
-
+ RoseAliasingInfo rai(build);
+
mergeRoses &= cc.grey.mergeRose & cc.grey.roseMergeRosesDuringAliasing;
- CandidateSet candidates;
+ CandidateSet candidates;
findCandidates(build, &candidates);
DEBUG_PRINTF("candidates %zu\n", candidates.size());
@@ -2015,8 +2015,8 @@ void aliasRoles(RoseBuildImpl &build, bool mergeRoses) {
size_t old_dead_size = 0;
do {
old_dead_size = dead.size();
- leftMergePass(candidates, build, &dead, rai);
- rightMergePass(candidates, build, &dead, mergeRoses, rai);
+ leftMergePass(candidates, build, &dead, rai);
+ rightMergePass(candidates, build, &dead, mergeRoses, rai);
} while (old_dead_size != dead.size());
/* Diamond merge passes cannot create extra merges as they require the same
@@ -2024,312 +2024,312 @@ void aliasRoles(RoseBuildImpl &build, bool mergeRoses) {
* to a merge to different pred/succ before a diamond merge, it will still
* be afterwards. */
filterDiamondCandidates(g, candidates);
- diamondMergePass(candidates, build, &dead, mergeRoses, rai);
+ diamondMergePass(candidates, build, &dead, mergeRoses, rai);
DEBUG_PRINTF("killed %zu vertices\n", dead.size());
build.removeVertices(dead);
- assert(!hasOrphanedTops(build));
- assert(canImplementGraphs(build));
+ assert(!hasOrphanedTops(build));
+ assert(canImplementGraphs(build));
+}
+
+namespace {
+struct DupeLeafKey {
+ explicit DupeLeafKey(const RoseVertexProps &litv)
+ : literals(litv.literals), reports(litv.reports),
+ eod_accept(litv.eod_accept), suffix(litv.suffix), left(litv.left),
+ som_adjust(litv.som_adjust) {
+ DEBUG_PRINTF("eod_accept %d\n", (int)eod_accept);
+ DEBUG_PRINTF("report %u\n", left.leftfix_report);
+ DEBUG_PRINTF("lag %u\n", left.lag);
+ }
+
+ bool operator<(const DupeLeafKey &b) const {
+ const DupeLeafKey &a = *this;
+ ORDER_CHECK(literals);
+ ORDER_CHECK(eod_accept);
+ ORDER_CHECK(suffix);
+ ORDER_CHECK(reports);
+ ORDER_CHECK(som_adjust);
+ ORDER_CHECK(left.leftfix_report);
+ ORDER_CHECK(left.lag);
+ return false;
+ }
+
+ flat_set<u32> literals;
+ flat_set<ReportID> reports;
+ bool eod_accept;
+ suffix_id suffix;
+ LeftEngInfo left;
+ u32 som_adjust;
+};
+
+struct UncalcLeafKey {
+ UncalcLeafKey(const RoseGraph &g, RoseVertex v)
+ : literals(g[v].literals), rose(g[v].left) {
+ for (const auto &e : in_edges_range(v, g)) {
+ RoseVertex u = source(e, g);
+ preds.insert(make_pair(u, g[e]));
+ }
+ }
+
+ bool operator<(const UncalcLeafKey &b) const {
+ const UncalcLeafKey &a = *this;
+ ORDER_CHECK(literals);
+ ORDER_CHECK(preds);
+ ORDER_CHECK(rose);
+ return false;
+ }
+
+ flat_set<u32> literals;
+ flat_set<pair<RoseVertex, RoseEdgeProps>> preds;
+ LeftEngInfo rose;
+};
+} // namespace
+
+/**
+ * This function merges leaf vertices with the same literals and report
+ * id/suffix. The leaf vertices of the graph are inspected and a mapping of
+ * leaf vertex properties to vertices is built. If the same set of leaf
+ * properties has already been seen when we inspect a vertex, we attempt to
+ * merge the vertex in with the previously seen vertex. This process can fail
+ * if the vertices share a common predecessor vertex but have a differing,
+ * incompatible relationship (different bounds or infix) with the predecessor.
+ *
+ * This takes place after \ref dedupeSuffixes to increase effectiveness as the
+ * same suffix is required for a merge to occur.
+ *
+ * TODO: work if this is a subset of role aliasing (and if it can be eliminated)
+ * or clearly document cases that would not be covered by role aliasing.
+ */
+void mergeDupeLeaves(RoseBuildImpl &build) {
+ map<DupeLeafKey, RoseVertex> leaves;
+ vector<RoseVertex> changed;
+
+ RoseGraph &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (in_degree(v, g) == 0) {
+ assert(build.isAnyStart(v));
+ continue;
+ }
+
+ DEBUG_PRINTF("inspecting vertex index=%zu in_degree %zu "
+ "out_degree %zu\n", g[v].index, in_degree(v, g),
+ out_degree(v, g));
+
+ // Vertex must be a reporting leaf node
+ if (g[v].reports.empty() || !isLeafNode(v, g)) {
+ continue;
+ }
+
+ // At the moment, we ignore all successors of root or anchored_root,
+ // since many parts of our runtime assume that these have in-degree 1.
+ if (build.isRootSuccessor(v)) {
+ continue;
+ }
+
+ DupeLeafKey dupe(g[v]);
+ if (leaves.find(dupe) == leaves.end()) {
+ leaves.insert(make_pair(dupe, v));
+ continue;
+ }
+
+ RoseVertex t = leaves.find(dupe)->second;
+ DEBUG_PRINTF("found two leaf dupe roles, index=%zu,%zu\n", g[v].index,
+ g[t].index);
+
+ vector<RoseEdge> deadEdges;
+ for (const auto &e : in_edges_range(v, g)) {
+ RoseVertex u = source(e, g);
+ DEBUG_PRINTF("u index=%zu\n", g[u].index);
+ if (RoseEdge et = edge(u, t, g)) {
+ if (g[et].minBound <= g[e].minBound
+ && g[et].maxBound >= g[e].maxBound) {
+ DEBUG_PRINTF("remove more constrained edge\n");
+ deadEdges.push_back(e);
+ }
+ } else {
+ DEBUG_PRINTF("rehome edge: add %zu->%zu\n", g[u].index,
+ g[t].index);
+ add_edge(u, t, g[e], g);
+ deadEdges.push_back(e);
+ }
+ }
+
+ if (!deadEdges.empty()) {
+ for (auto &e : deadEdges) {
+ remove_edge(e, g);
+ }
+ changed.push_back(v);
+ g[t].min_offset = min(g[t].min_offset, g[v].min_offset);
+ g[t].max_offset = max(g[t].max_offset, g[v].max_offset);
+ }
+ }
+ DEBUG_PRINTF("find loop done\n");
+
+ // Remove any vertices that now have no in-edges.
+ size_t countRemovals = 0;
+ for (size_t i = 0; i < changed.size(); i++) {
+ RoseVertex v = changed[i];
+ if (in_degree(v, g) == 0) {
+ DEBUG_PRINTF("remove vertex\n");
+ if (!build.isVirtualVertex(v)) {
+ for (u32 lit_id : g[v].literals) {
+ build.literal_info[lit_id].vertices.erase(v);
+ }
+ }
+ remove_vertex(v, g);
+ countRemovals++;
+ }
+ }
+
+ // if we've removed anything, we need to renumber vertices
+ if (countRemovals) {
+ renumber_vertices(g);
+ DEBUG_PRINTF("removed %zu vertices.\n", countRemovals);
+ }
+}
+
+/** Merges the suffixes on the (identical) vertices in \a vcluster, used by
+ * \ref uncalcLeaves. */
+static
+void mergeCluster(RoseGraph &g, const ReportManager &rm,
+ const vector<RoseVertex> &vcluster,
+ vector<RoseVertex> &dead, const CompileContext &cc) {
+ if (vcluster.size() <= 1) {
+ return; // No merge to perform.
+ }
+
+ // Note that we batch merges up fairly crudely for performance reasons.
+ vector<RoseVertex>::const_iterator it = vcluster.begin(), it2;
+ while (it != vcluster.end()) {
+ vector<NGHolder *> cluster;
+ map<NGHolder *, RoseVertex> rev;
+
+ for (it2 = it;
+ it2 != vcluster.end() && cluster.size() < MERGE_GROUP_SIZE_MAX;
+ ++it2) {
+ RoseVertex v = *it2;
+ NGHolder *h = g[v].suffix.graph.get();
+ assert(!g[v].suffix.haig); /* should not be here if haig */
+ rev[h] = v;
+ cluster.push_back(h);
+ }
+ it = it2;
+
+ DEBUG_PRINTF("merging cluster %zu\n", cluster.size());
+ auto merged = mergeNfaCluster(cluster, &rm, cc);
+ DEBUG_PRINTF("done\n");
+
+ for (const auto &m : merged) {
+ NGHolder *h_victim = m.first; // mergee
+ NGHolder *h_winner = m.second;
+ RoseVertex victim = rev[h_victim];
+ RoseVertex winner = rev[h_winner];
+
+ LIMIT_TO_AT_MOST(&g[winner].min_offset, g[victim].min_offset);
+ ENSURE_AT_LEAST(&g[winner].max_offset, g[victim].max_offset);
+ insert(&g[winner].reports, g[victim].reports);
+
+ dead.push_back(victim);
+ }
+ }
+}
+
+static
+void findUncalcLeavesCandidates(RoseBuildImpl &build,
+ map<UncalcLeafKey, vector<RoseVertex> > &clusters,
+ deque<UncalcLeafKey> &ordered) {
+ const RoseGraph &g = build.g;
+
+ vector<RoseVertex> suffix_vertices; // vertices with suffix graphs
+ unordered_map<const NGHolder *, u32> fcount; // ref count per graph
+
+ for (auto v : vertices_range(g)) {
+ if (g[v].suffix) {
+ if (!g[v].suffix.graph) {
+ continue; /* cannot uncalc (haig/mcclellan); TODO */
+ }
+
+ assert(g[v].suffix.graph->kind == NFA_SUFFIX);
+
+ // Ref count all suffixes, as we don't want to merge a suffix
+ // that happens to be shared with a non-leaf vertex somewhere.
+ DEBUG_PRINTF("vertex %zu has suffix %p\n", g[v].index,
+ g[v].suffix.graph.get());
+ fcount[g[v].suffix.graph.get()]++;
+
+ // Vertex must be a reporting pseudo accept
+ if (!isLeafNode(v, g)) {
+ continue;
+ }
+
+ suffix_vertices.push_back(v);
+ }
+ }
+
+ for (auto v : suffix_vertices) {
+ if (in_degree(v, g) == 0) {
+ assert(build.isAnyStart(v));
+ continue;
+ }
+
+ const NGHolder *h = g[v].suffix.graph.get();
+ assert(h);
+ DEBUG_PRINTF("suffix %p\n", h);
+
+ // We can't easily merge suffixes shared with other vertices, and
+ // creating a unique copy to do so may just mean we end up tracking
+ // more NFAs. Better to leave shared suffixes alone.
+ if (fcount[h] != 1) {
+ DEBUG_PRINTF("skipping shared suffix\n");
+ continue;
+ }
+
+ UncalcLeafKey key(g, v);
+ vector<RoseVertex> &vec = clusters[key];
+ if (vec.empty()) {
+
+ ordered.push_back(key);
+ }
+ vec.push_back(v);
+ }
+
+ DEBUG_PRINTF("find loop done\n");
+}
+
+/**
+ * This function attempts to combine identical roles (same literals, same
+ * predecessors, etc) with different suffixes into a single role which
+ * activates a larger suffix. The leaf vertices of the graph with a suffix are
+ * grouped into clusters which have members triggered by identical roles. The
+ * \ref mergeNfaCluster function (from ng_uncalc_components) is then utilised
+ * to build a set of larger (and still implementable) suffixes. The graph is
+ * then updated to point to the new suffixes and any unneeded roles are
+ * removed.
+ *
+ * Note: suffixes which are shared amongst multiple roles are not considered
+ * for this pass as the individual suffixes would have to continue to exist for
+ * the other roles to trigger resulting in the transformation not producing any
+ * savings.
+ *
+ * Note: as \ref mergeNfaCluster is slow when the cluster sizes are large,
+ * clusters of more than \ref MERGE_GROUP_SIZE_MAX roles are split into smaller
+ * chunks for processing.
+ */
+void uncalcLeaves(RoseBuildImpl &build) {
+ DEBUG_PRINTF("uncalcing\n");
+
+ map<UncalcLeafKey, vector<RoseVertex> > clusters;
+ deque<UncalcLeafKey> ordered;
+ findUncalcLeavesCandidates(build, clusters, ordered);
+
+ vector<RoseVertex> dead;
+
+ for (const auto &key : ordered) {
+ DEBUG_PRINTF("cluster of size %zu\n", clusters[key].size());
+ mergeCluster(build.g, build.rm, clusters[key], dead, build.cc);
+ }
+ build.removeVertices(dead);
}
-namespace {
-struct DupeLeafKey {
- explicit DupeLeafKey(const RoseVertexProps &litv)
- : literals(litv.literals), reports(litv.reports),
- eod_accept(litv.eod_accept), suffix(litv.suffix), left(litv.left),
- som_adjust(litv.som_adjust) {
- DEBUG_PRINTF("eod_accept %d\n", (int)eod_accept);
- DEBUG_PRINTF("report %u\n", left.leftfix_report);
- DEBUG_PRINTF("lag %u\n", left.lag);
- }
-
- bool operator<(const DupeLeafKey &b) const {
- const DupeLeafKey &a = *this;
- ORDER_CHECK(literals);
- ORDER_CHECK(eod_accept);
- ORDER_CHECK(suffix);
- ORDER_CHECK(reports);
- ORDER_CHECK(som_adjust);
- ORDER_CHECK(left.leftfix_report);
- ORDER_CHECK(left.lag);
- return false;
- }
-
- flat_set<u32> literals;
- flat_set<ReportID> reports;
- bool eod_accept;
- suffix_id suffix;
- LeftEngInfo left;
- u32 som_adjust;
-};
-
-struct UncalcLeafKey {
- UncalcLeafKey(const RoseGraph &g, RoseVertex v)
- : literals(g[v].literals), rose(g[v].left) {
- for (const auto &e : in_edges_range(v, g)) {
- RoseVertex u = source(e, g);
- preds.insert(make_pair(u, g[e]));
- }
- }
-
- bool operator<(const UncalcLeafKey &b) const {
- const UncalcLeafKey &a = *this;
- ORDER_CHECK(literals);
- ORDER_CHECK(preds);
- ORDER_CHECK(rose);
- return false;
- }
-
- flat_set<u32> literals;
- flat_set<pair<RoseVertex, RoseEdgeProps>> preds;
- LeftEngInfo rose;
-};
-} // namespace
-
-/**
- * This function merges leaf vertices with the same literals and report
- * id/suffix. The leaf vertices of the graph are inspected and a mapping of
- * leaf vertex properties to vertices is built. If the same set of leaf
- * properties has already been seen when we inspect a vertex, we attempt to
- * merge the vertex in with the previously seen vertex. This process can fail
- * if the vertices share a common predecessor vertex but have a differing,
- * incompatible relationship (different bounds or infix) with the predecessor.
- *
- * This takes place after \ref dedupeSuffixes to increase effectiveness as the
- * same suffix is required for a merge to occur.
- *
- * TODO: work if this is a subset of role aliasing (and if it can be eliminated)
- * or clearly document cases that would not be covered by role aliasing.
- */
-void mergeDupeLeaves(RoseBuildImpl &build) {
- map<DupeLeafKey, RoseVertex> leaves;
- vector<RoseVertex> changed;
-
- RoseGraph &g = build.g;
- for (auto v : vertices_range(g)) {
- if (in_degree(v, g) == 0) {
- assert(build.isAnyStart(v));
- continue;
- }
-
- DEBUG_PRINTF("inspecting vertex index=%zu in_degree %zu "
- "out_degree %zu\n", g[v].index, in_degree(v, g),
- out_degree(v, g));
-
- // Vertex must be a reporting leaf node
- if (g[v].reports.empty() || !isLeafNode(v, g)) {
- continue;
- }
-
- // At the moment, we ignore all successors of root or anchored_root,
- // since many parts of our runtime assume that these have in-degree 1.
- if (build.isRootSuccessor(v)) {
- continue;
- }
-
- DupeLeafKey dupe(g[v]);
- if (leaves.find(dupe) == leaves.end()) {
- leaves.insert(make_pair(dupe, v));
- continue;
- }
-
- RoseVertex t = leaves.find(dupe)->second;
- DEBUG_PRINTF("found two leaf dupe roles, index=%zu,%zu\n", g[v].index,
- g[t].index);
-
- vector<RoseEdge> deadEdges;
- for (const auto &e : in_edges_range(v, g)) {
- RoseVertex u = source(e, g);
- DEBUG_PRINTF("u index=%zu\n", g[u].index);
- if (RoseEdge et = edge(u, t, g)) {
- if (g[et].minBound <= g[e].minBound
- && g[et].maxBound >= g[e].maxBound) {
- DEBUG_PRINTF("remove more constrained edge\n");
- deadEdges.push_back(e);
- }
- } else {
- DEBUG_PRINTF("rehome edge: add %zu->%zu\n", g[u].index,
- g[t].index);
- add_edge(u, t, g[e], g);
- deadEdges.push_back(e);
- }
- }
-
- if (!deadEdges.empty()) {
- for (auto &e : deadEdges) {
- remove_edge(e, g);
- }
- changed.push_back(v);
- g[t].min_offset = min(g[t].min_offset, g[v].min_offset);
- g[t].max_offset = max(g[t].max_offset, g[v].max_offset);
- }
- }
- DEBUG_PRINTF("find loop done\n");
-
- // Remove any vertices that now have no in-edges.
- size_t countRemovals = 0;
- for (size_t i = 0; i < changed.size(); i++) {
- RoseVertex v = changed[i];
- if (in_degree(v, g) == 0) {
- DEBUG_PRINTF("remove vertex\n");
- if (!build.isVirtualVertex(v)) {
- for (u32 lit_id : g[v].literals) {
- build.literal_info[lit_id].vertices.erase(v);
- }
- }
- remove_vertex(v, g);
- countRemovals++;
- }
- }
-
- // if we've removed anything, we need to renumber vertices
- if (countRemovals) {
- renumber_vertices(g);
- DEBUG_PRINTF("removed %zu vertices.\n", countRemovals);
- }
-}
-
-/** Merges the suffixes on the (identical) vertices in \a vcluster, used by
- * \ref uncalcLeaves. */
-static
-void mergeCluster(RoseGraph &g, const ReportManager &rm,
- const vector<RoseVertex> &vcluster,
- vector<RoseVertex> &dead, const CompileContext &cc) {
- if (vcluster.size() <= 1) {
- return; // No merge to perform.
- }
-
- // Note that we batch merges up fairly crudely for performance reasons.
- vector<RoseVertex>::const_iterator it = vcluster.begin(), it2;
- while (it != vcluster.end()) {
- vector<NGHolder *> cluster;
- map<NGHolder *, RoseVertex> rev;
-
- for (it2 = it;
- it2 != vcluster.end() && cluster.size() < MERGE_GROUP_SIZE_MAX;
- ++it2) {
- RoseVertex v = *it2;
- NGHolder *h = g[v].suffix.graph.get();
- assert(!g[v].suffix.haig); /* should not be here if haig */
- rev[h] = v;
- cluster.push_back(h);
- }
- it = it2;
-
- DEBUG_PRINTF("merging cluster %zu\n", cluster.size());
- auto merged = mergeNfaCluster(cluster, &rm, cc);
- DEBUG_PRINTF("done\n");
-
- for (const auto &m : merged) {
- NGHolder *h_victim = m.first; // mergee
- NGHolder *h_winner = m.second;
- RoseVertex victim = rev[h_victim];
- RoseVertex winner = rev[h_winner];
-
- LIMIT_TO_AT_MOST(&g[winner].min_offset, g[victim].min_offset);
- ENSURE_AT_LEAST(&g[winner].max_offset, g[victim].max_offset);
- insert(&g[winner].reports, g[victim].reports);
-
- dead.push_back(victim);
- }
- }
-}
-
-static
-void findUncalcLeavesCandidates(RoseBuildImpl &build,
- map<UncalcLeafKey, vector<RoseVertex> > &clusters,
- deque<UncalcLeafKey> &ordered) {
- const RoseGraph &g = build.g;
-
- vector<RoseVertex> suffix_vertices; // vertices with suffix graphs
- unordered_map<const NGHolder *, u32> fcount; // ref count per graph
-
- for (auto v : vertices_range(g)) {
- if (g[v].suffix) {
- if (!g[v].suffix.graph) {
- continue; /* cannot uncalc (haig/mcclellan); TODO */
- }
-
- assert(g[v].suffix.graph->kind == NFA_SUFFIX);
-
- // Ref count all suffixes, as we don't want to merge a suffix
- // that happens to be shared with a non-leaf vertex somewhere.
- DEBUG_PRINTF("vertex %zu has suffix %p\n", g[v].index,
- g[v].suffix.graph.get());
- fcount[g[v].suffix.graph.get()]++;
-
- // Vertex must be a reporting pseudo accept
- if (!isLeafNode(v, g)) {
- continue;
- }
-
- suffix_vertices.push_back(v);
- }
- }
-
- for (auto v : suffix_vertices) {
- if (in_degree(v, g) == 0) {
- assert(build.isAnyStart(v));
- continue;
- }
-
- const NGHolder *h = g[v].suffix.graph.get();
- assert(h);
- DEBUG_PRINTF("suffix %p\n", h);
-
- // We can't easily merge suffixes shared with other vertices, and
- // creating a unique copy to do so may just mean we end up tracking
- // more NFAs. Better to leave shared suffixes alone.
- if (fcount[h] != 1) {
- DEBUG_PRINTF("skipping shared suffix\n");
- continue;
- }
-
- UncalcLeafKey key(g, v);
- vector<RoseVertex> &vec = clusters[key];
- if (vec.empty()) {
-
- ordered.push_back(key);
- }
- vec.push_back(v);
- }
-
- DEBUG_PRINTF("find loop done\n");
-}
-
-/**
- * This function attempts to combine identical roles (same literals, same
- * predecessors, etc) with different suffixes into a single role which
- * activates a larger suffix. The leaf vertices of the graph with a suffix are
- * grouped into clusters which have members triggered by identical roles. The
- * \ref mergeNfaCluster function (from ng_uncalc_components) is then utilised
- * to build a set of larger (and still implementable) suffixes. The graph is
- * then updated to point to the new suffixes and any unneeded roles are
- * removed.
- *
- * Note: suffixes which are shared amongst multiple roles are not considered
- * for this pass as the individual suffixes would have to continue to exist for
- * the other roles to trigger resulting in the transformation not producing any
- * savings.
- *
- * Note: as \ref mergeNfaCluster is slow when the cluster sizes are large,
- * clusters of more than \ref MERGE_GROUP_SIZE_MAX roles are split into smaller
- * chunks for processing.
- */
-void uncalcLeaves(RoseBuildImpl &build) {
- DEBUG_PRINTF("uncalcing\n");
-
- map<UncalcLeafKey, vector<RoseVertex> > clusters;
- deque<UncalcLeafKey> ordered;
- findUncalcLeavesCandidates(build, clusters, ordered);
-
- vector<RoseVertex> dead;
-
- for (const auto &key : ordered) {
- DEBUG_PRINTF("cluster of size %zu\n", clusters[key].size());
- mergeCluster(build.g, build.rm, clusters[key], dead, build.cc);
- }
- build.removeVertices(dead);
-}
-
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.h b/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.h
index c8e71f144c9..4655f10d52e 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_role_aliasing.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,23 +26,23 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ROSE_BUILD_ROLE_ALIASING_H
-#define ROSE_BUILD_ROLE_ALIASING_H
+#ifndef ROSE_BUILD_ROLE_ALIASING_H
+#define ROSE_BUILD_ROLE_ALIASING_H
+
+/** \file
+ * \brief Rose Build: functions for reducing the size of the Rose graph
+ * through merging roles (RoseVertices) together.
+ */
-/** \file
- * \brief Rose Build: functions for reducing the size of the Rose graph
- * through merging roles (RoseVertices) together.
- */
-
namespace ue2 {
class RoseBuildImpl;
void aliasRoles(RoseBuildImpl &build, bool mergeRoses);
-void mergeDupeLeaves(RoseBuildImpl &build);
-void uncalcLeaves(RoseBuildImpl &build);
-
+void mergeDupeLeaves(RoseBuildImpl &build);
+void uncalcLeaves(RoseBuildImpl &build);
+
} // namespace ue2
#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_scatter.cpp b/contrib/libs/hyperscan/src/rose/rose_build_scatter.cpp
index 2fb923def0e..87085ae9a8d 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_scatter.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_scatter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -63,24 +63,24 @@ void merge_in(scatter_plan_raw *out, const scatter_plan_raw &in) {
insert(&out->p_u8, out->p_u8.end(), in.p_u8);
}
-scatter_plan_raw buildStateScatterPlan(u32 role_state_offset,
- u32 role_state_count, u32 left_array_count, u32 left_prefix_count,
- const RoseStateOffsets &stateOffsets, bool streaming,
- u32 leaf_array_count, u32 outfix_begin, u32 outfix_end) {
- scatter_plan_raw out;
-
+scatter_plan_raw buildStateScatterPlan(u32 role_state_offset,
+ u32 role_state_count, u32 left_array_count, u32 left_prefix_count,
+ const RoseStateOffsets &stateOffsets, bool streaming,
+ u32 leaf_array_count, u32 outfix_begin, u32 outfix_end) {
+ scatter_plan_raw out;
+
/* init role array */
scatter_plan_raw spr_role;
mmbBuildClearPlan(role_state_count, &spr_role);
rebase(&spr_role, role_state_offset);
- merge_in(&out, spr_role);
+ merge_in(&out, spr_role);
/* init rose array: turn on prefixes */
u32 rose_array_offset = stateOffsets.activeLeftArray;
scatter_plan_raw spr_rose;
mmbBuildInitRangePlan(left_array_count, 0, left_prefix_count, &spr_rose);
rebase(&spr_rose, rose_array_offset);
- merge_in(&out, spr_rose);
+ merge_in(&out, spr_rose);
/* suffix/outfix array */
scatter_plan_raw spr_leaf;
@@ -91,9 +91,9 @@ scatter_plan_raw buildStateScatterPlan(u32 role_state_offset,
mmbBuildClearPlan(leaf_array_count, &spr_leaf);
}
rebase(&spr_leaf, stateOffsets.activeLeafArray);
- merge_in(&out, spr_leaf);
-
- return out;
+ merge_in(&out, spr_leaf);
+
+ return out;
}
u32 aux_size(const scatter_plan_raw &raw) {
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_scatter.h b/contrib/libs/hyperscan/src/rose/rose_build_scatter.h
index da44b2cf54d..67a82b9937b 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_scatter.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_scatter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,10 +45,10 @@ struct scatter_plan_raw {
std::vector<scatter_unit_u8> p_u8;
};
-scatter_plan_raw buildStateScatterPlan(u32 role_state_offset,
- u32 role_state_count, u32 left_array_count, u32 left_prefix_count,
- const RoseStateOffsets &stateOffsets, bool streaming,
- u32 leaf_array_count, u32 outfix_begin, u32 outfix_end);
+scatter_plan_raw buildStateScatterPlan(u32 role_state_offset,
+ u32 role_state_count, u32 left_array_count, u32 left_prefix_count,
+ const RoseStateOffsets &stateOffsets, bool streaming,
+ u32 leaf_array_count, u32 outfix_begin, u32 outfix_end);
u32 aux_size(const scatter_plan_raw &raw);
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_util.h b/contrib/libs/hyperscan/src/rose/rose_build_util.h
index c2c964e54af..81bb68459bb 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_util.h
+++ b/contrib/libs/hyperscan/src/rose/rose_build_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,8 +36,8 @@
namespace ue2 {
-/** Max allowed width for transient graphs in block mode */
-#define ROSE_BLOCK_TRANSIENT_MAX_WIDTH 255U
+/** Max allowed width for transient graphs in block mode */
+#define ROSE_BLOCK_TRANSIENT_MAX_WIDTH 255U
/**
* \brief Add two Rose depths together, coping correctly with infinity at
diff --git a/contrib/libs/hyperscan/src/rose/rose_build_width.cpp b/contrib/libs/hyperscan/src/rose/rose_build_width.cpp
index 4f11a2fcf8b..182b62ee6fb 100644
--- a/contrib/libs/hyperscan/src/rose/rose_build_width.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_build_width.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -77,20 +77,20 @@ u32 findMinWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) {
u32 minWidth = ROSE_BOUND_INF;
for (auto v : reachable) {
if (g[v].eod_accept) {
- DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index);
+ DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index);
continue;
}
const u32 w = g[v].min_offset;
if (!g[v].reports.empty()) {
- DEBUG_PRINTF("%zu can fire report at offset %u\n", g[v].index, w);
+ DEBUG_PRINTF("%zu can fire report at offset %u\n", g[v].index, w);
minWidth = min(minWidth, w);
}
if (is_end_anchored(g, v)) {
- DEBUG_PRINTF("%zu can fire eod report at offset %u\n", g[v].index,
- w);
+ DEBUG_PRINTF("%zu can fire eod report at offset %u\n", g[v].index,
+ w);
minWidth = min(minWidth, w);
}
@@ -99,7 +99,7 @@ u32 findMinWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) {
assert(suffix_width.is_reachable());
DEBUG_PRINTF("%zu has suffix with top %u (width %s), can fire "
"report at %u\n",
- g[v].index, g[v].suffix.top, suffix_width.str().c_str(),
+ g[v].index, g[v].suffix.top, suffix_width.str().c_str(),
w + suffix_width);
minWidth = min(minWidth, w + suffix_width);
}
@@ -204,10 +204,10 @@ u32 findMaxBAWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) {
// Everyone's anchored, so the max width can be taken from the max
// max_offset on our vertices (so long as all accepts are ACCEPT_EOD).
for (auto v : reachable) {
- DEBUG_PRINTF("inspecting vert %zu\n", g[v].index);
+ DEBUG_PRINTF("inspecting vert %zu\n", g[v].index);
if (g[v].eod_accept) {
- DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index);
+ DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index);
continue;
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_common.h b/contrib/libs/hyperscan/src/rose/rose_common.h
index ad18d5364a9..34678b8fcc4 100644
--- a/contrib/libs/hyperscan/src/rose/rose_common.h
+++ b/contrib/libs/hyperscan/src/rose/rose_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -41,16 +41,16 @@
/** \brief Length in bytes of a reach bitvector, used by the lookaround code. */
#define REACH_BITVECTOR_LEN 32
-/** \brief Length in bytes of a reach bitvector for multi-path lookaround. */
-#define MULTI_REACH_BITVECTOR_LEN 256
-
-/**
- * \brief The max offset from the leftmost byte to the rightmost byte in
- * multi-path lookaround.
- */
-#define MULTIPATH_MAX_LEN 16
-
-/** \brief Value used to represent an invalid Rose program offset. */
-#define ROSE_INVALID_PROG_OFFSET 0
-
+/** \brief Length in bytes of a reach bitvector for multi-path lookaround. */
+#define MULTI_REACH_BITVECTOR_LEN 256
+
+/**
+ * \brief The max offset from the leftmost byte to the rightmost byte in
+ * multi-path lookaround.
+ */
+#define MULTIPATH_MAX_LEN 16
+
+/** \brief Value used to represent an invalid Rose program offset. */
+#define ROSE_INVALID_PROG_OFFSET 0
+
#endif // ROSE_COMMON_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_graph.h b/contrib/libs/hyperscan/src/rose/rose_graph.h
index 1cf59ca0c91..b5bf1985d8d 100644
--- a/contrib/libs/hyperscan/src/rose/rose_graph.h
+++ b/contrib/libs/hyperscan/src/rose/rose_graph.h
@@ -39,11 +39,11 @@
#include "ue2common.h"
#include "rose_build.h"
-#include "rose_internal.h"
+#include "rose_internal.h"
#include "nfa/nfa_internal.h" // for MO_INVALID_IDX
#include "util/depth.h"
-#include "util/flat_containers.h"
-#include "util/ue2_graph.h"
+#include "util/flat_containers.h"
+#include "util/ue2_graph.h"
#include <memory>
#include <set>
@@ -53,7 +53,7 @@ namespace ue2 {
struct CastleProto;
struct raw_dfa;
struct raw_som_dfa;
-struct TamaProto;
+struct TamaProto;
/** \brief Table type for a literal. */
enum rose_literal_table {
@@ -64,14 +64,14 @@ enum rose_literal_table {
ROSE_EVENT //!< "literal-like" events, such as EOD
};
-/** \brief Edge history types. */
-enum RoseRoleHistory {
- ROSE_ROLE_HISTORY_NONE, //!< no special history
- ROSE_ROLE_HISTORY_ANCH, //!< previous role is at a fixed offset
- ROSE_ROLE_HISTORY_LAST_BYTE, //!< previous role can only match at EOD
- ROSE_ROLE_HISTORY_INVALID //!< history not yet assigned
-};
-
+/** \brief Edge history types. */
+enum RoseRoleHistory {
+ ROSE_ROLE_HISTORY_NONE, //!< no special history
+ ROSE_ROLE_HISTORY_ANCH, //!< previous role is at a fixed offset
+ ROSE_ROLE_HISTORY_LAST_BYTE, //!< previous role can only match at EOD
+ ROSE_ROLE_HISTORY_INVALID //!< history not yet assigned
+};
+
#include "util/order_check.h"
/** \brief Provides information about the (pre|in)fix engine to the left of a
@@ -81,10 +81,10 @@ struct LeftEngInfo {
std::shared_ptr<CastleProto> castle;
std::shared_ptr<raw_dfa> dfa;
std::shared_ptr<raw_som_dfa> haig;
- std::shared_ptr<TamaProto> tamarama;
+ std::shared_ptr<TamaProto> tamarama;
u32 lag = 0U;
ReportID leftfix_report = MO_INVALID_IDX;
- depth dfa_min_width{0};
+ depth dfa_min_width{0};
depth dfa_max_width = depth::infinity();
bool operator==(const LeftEngInfo &other) const {
@@ -92,7 +92,7 @@ struct LeftEngInfo {
&& other.castle == castle
&& other.dfa == dfa
&& other.haig == haig
- && other.tamarama == tamarama
+ && other.tamarama == tamarama
&& other.lag == lag
&& other.leftfix_report == leftfix_report;
}
@@ -105,12 +105,12 @@ struct LeftEngInfo {
ORDER_CHECK(castle);
ORDER_CHECK(dfa);
ORDER_CHECK(haig);
- ORDER_CHECK(tamarama);
+ ORDER_CHECK(tamarama);
ORDER_CHECK(lag);
ORDER_CHECK(leftfix_report);
return false;
}
- size_t hash() const;
+ size_t hash() const;
void reset(void);
explicit operator bool() const;
bool tracksSom() const { return !!haig; }
@@ -124,14 +124,14 @@ struct RoseSuffixInfo {
std::shared_ptr<CastleProto> castle;
std::shared_ptr<raw_som_dfa> haig;
std::shared_ptr<raw_dfa> rdfa;
- std::shared_ptr<TamaProto> tamarama;
- depth dfa_min_width{0};
+ std::shared_ptr<TamaProto> tamarama;
+ depth dfa_min_width{0};
depth dfa_max_width = depth::infinity();
bool operator==(const RoseSuffixInfo &b) const;
bool operator!=(const RoseSuffixInfo &b) const { return !(*this == b); }
bool operator<(const RoseSuffixInfo &b) const;
- size_t hash() const;
+ size_t hash() const;
void reset(void);
explicit operator bool() const { return graph || castle || haig || rdfa || tamarama; }
};
@@ -139,7 +139,7 @@ struct RoseSuffixInfo {
/** \brief Properties attached to each Rose graph vertex. */
struct RoseVertexProps {
/** \brief Unique dense vertex index. Used for BGL algorithms. */
- size_t index = ~size_t{0};
+ size_t index = ~size_t{0};
/** \brief IDs of literals in the Rose literal map. */
flat_set<u32> literals;
@@ -183,9 +183,9 @@ struct RoseVertexProps {
/** \brief Properties attached to each Rose graph edge. */
/* bounds are distance from end of prev to start of the next */
struct RoseEdgeProps {
- /** \brief Unique dense vertex index. Used for BGL algorithms. */
- size_t index = ~size_t{0};
-
+ /** \brief Unique dense vertex index. Used for BGL algorithms. */
+ size_t index = ~size_t{0};
+
/**
* \brief Minimum distance from the end of the source role's match to the
* start of the target role's match.
@@ -219,9 +219,9 @@ bool operator<(const RoseEdgeProps &a, const RoseEdgeProps &b);
/**
* \brief Core Rose graph structure.
*/
-struct RoseGraph : public ue2_graph<RoseGraph, RoseVertexProps, RoseEdgeProps> {
- friend class RoseBuildImpl; /* to allow index renumbering */
-};
+struct RoseGraph : public ue2_graph<RoseGraph, RoseVertexProps, RoseEdgeProps> {
+ friend class RoseBuildImpl; /* to allow index renumbering */
+};
using RoseVertex = RoseGraph::vertex_descriptor;
using RoseEdge = RoseGraph::edge_descriptor;
diff --git a/contrib/libs/hyperscan/src/rose/rose_in_graph.h b/contrib/libs/hyperscan/src/rose/rose_in_graph.h
index 1cf7b220454..da0ea08da13 100644
--- a/contrib/libs/hyperscan/src/rose/rose_in_graph.h
+++ b/contrib/libs/hyperscan/src/rose/rose_in_graph.h
@@ -45,8 +45,8 @@
#include "ue2common.h"
#include "rose/rose_common.h"
-#include "util/flat_containers.h"
-#include "util/ue2_graph.h"
+#include "util/flat_containers.h"
+#include "util/ue2_graph.h"
#include "util/ue2string.h"
#include <memory>
@@ -55,7 +55,7 @@ namespace ue2 {
class NGHolder;
struct raw_som_dfa;
-struct raw_dfa;
+struct raw_dfa;
enum RoseInVertexType {
RIV_LITERAL,
@@ -105,12 +105,12 @@ public:
ROSE_BOUND_INF);
}
- /* for when there is a suffix graph which handles the reports */
- static RoseInVertexProps makeAcceptEod() {
- return RoseInVertexProps(RIV_ACCEPT_EOD, ue2_literal(), 0,
- ROSE_BOUND_INF);
- }
-
+ /* for when there is a suffix graph which handles the reports */
+ static RoseInVertexProps makeAcceptEod() {
+ return RoseInVertexProps(RIV_ACCEPT_EOD, ue2_literal(), 0,
+ ROSE_BOUND_INF);
+ }
+
static RoseInVertexProps makeStart(bool anchored) {
DEBUG_PRINTF("making %s\n", anchored ? "anchored start" : "start");
if (anchored) {
@@ -167,12 +167,12 @@ struct RoseInEdgeProps {
/** \brief Maximum bound on 'dot' repeat between literals. */
u32 maxBound;
- /** \brief Graph on edge. Graph is end to (end - lag). */
+ /** \brief Graph on edge. Graph is end to (end - lag). */
std::shared_ptr<NGHolder> graph;
- /** \brief DFA version of graph, if we have already determinised. */
- std::shared_ptr<raw_dfa> dfa;
-
+ /** \brief DFA version of graph, if we have already determinised. */
+ std::shared_ptr<raw_dfa> dfa;
+
/** \brief Haig version of graph, if required. */
std::shared_ptr<raw_som_dfa> haig;
@@ -183,11 +183,11 @@ struct RoseInEdgeProps {
u32 graph_lag;
/** \brief Unique edge index. */
- size_t index = 0;
-};
+ size_t index = 0;
+};
-struct RoseInGraph
- : public ue2_graph<RoseInGraph, RoseInVertexProps, RoseInEdgeProps> {
+struct RoseInGraph
+ : public ue2_graph<RoseInGraph, RoseInVertexProps, RoseInEdgeProps> {
};
typedef RoseInGraph::vertex_descriptor RoseInVertex;
typedef RoseInGraph::edge_descriptor RoseInEdge;
diff --git a/contrib/libs/hyperscan/src/rose/rose_in_util.cpp b/contrib/libs/hyperscan/src/rose/rose_in_util.cpp
index e24c9fa08c4..cb531017e36 100644
--- a/contrib/libs/hyperscan/src/rose/rose_in_util.cpp
+++ b/contrib/libs/hyperscan/src/rose/rose_in_util.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -51,11 +51,11 @@ namespace ue2 {
* at the front and all the predecessors of a vertex occur earlier in the list
* than the vertex. */
vector<RoseInVertex> topo_order(const RoseInGraph &g) {
- assert(hasCorrectlyNumberedVertices(g));
+ assert(hasCorrectlyNumberedVertices(g));
vector<RoseInVertex> v_order;
- v_order.reserve(num_vertices(g));
+ v_order.reserve(num_vertices(g));
- boost::topological_sort(g, back_inserter(v_order));
+ boost::topological_sort(g, back_inserter(v_order));
reverse(v_order.begin(), v_order.end()); /* put starts at the front */
@@ -92,8 +92,8 @@ private:
}
unique_ptr<RoseInGraph> cloneRoseGraph(const RoseInGraph &ig) {
- assert(hasCorrectlyNumberedVertices(ig));
- unique_ptr<RoseInGraph> out = std::make_unique<RoseInGraph>();
+ assert(hasCorrectlyNumberedVertices(ig));
+ unique_ptr<RoseInGraph> out = std::make_unique<RoseInGraph>();
unordered_map<const NGHolder *, shared_ptr<NGHolder>> graph_map;
unordered_map<const raw_som_dfa *, shared_ptr<raw_som_dfa>> haig_map;
@@ -109,7 +109,7 @@ unique_ptr<RoseInGraph> cloneRoseGraph(const RoseInGraph &ig) {
}
copy_graph(ig, *out,
- boost::edge_copy(RoseEdgeCopier(ig, *out, graph_map, haig_map)));
+ boost::edge_copy(RoseEdgeCopier(ig, *out, graph_map, haig_map)));
return out;
}
diff --git a/contrib/libs/hyperscan/src/rose/rose_in_util.h b/contrib/libs/hyperscan/src/rose/rose_in_util.h
index f3e248e7243..1f3c4ef78ad 100644
--- a/contrib/libs/hyperscan/src/rose/rose_in_util.h
+++ b/contrib/libs/hyperscan/src/rose/rose_in_util.h
@@ -46,11 +46,11 @@ void calcVertexOffsets(RoseInGraph &ig);
enum nfa_kind whatRoseIsThis(const RoseInGraph &in, const RoseInEdge &e);
void pruneUseless(RoseInGraph &g);
-inline
-bool is_any_accept(RoseInVertex v, const RoseInGraph &g) {
- return g[v].type == RIV_ACCEPT || g[v].type == RIV_ACCEPT_EOD;
+inline
+bool is_any_accept(RoseInVertex v, const RoseInGraph &g) {
+ return g[v].type == RIV_ACCEPT || g[v].type == RIV_ACCEPT_EOD;
+}
+
}
-}
-
#endif
diff --git a/contrib/libs/hyperscan/src/rose/rose_internal.h b/contrib/libs/hyperscan/src/rose/rose_internal.h
index ac2d6e72882..7bd6779c3d4 100644
--- a/contrib/libs/hyperscan/src/rose/rose_internal.h
+++ b/contrib/libs/hyperscan/src/rose/rose_internal.h
@@ -68,15 +68,15 @@ typedef u64a rose_group;
/* Rose Literal Sources
*
- * Rose currently gets events (mainly roseProcessMatch calls) from a number of
- * sources:
+ * Rose currently gets events (mainly roseProcessMatch calls) from a number of
+ * sources:
* 1) The floating table
* 2) The anchored table
* 3) Delayed literals
- * 4) Suffix NFAs
- * 5) Literal masks
- * 5) End anchored table
- * 6) Prefix / Infix nfas
+ * 4) Suffix NFAs
+ * 5) Literal masks
+ * 5) End anchored table
+ * 6) Prefix / Infix nfas
*
* Care is required to ensure that events appear to come into Rose in order
* (or sufficiently ordered for Rose to cope). Generally the progress of the
@@ -99,7 +99,7 @@ typedef u64a rose_group;
* NFA queues are run to the current point (floating or delayed literal) as
* appropriate.
*
- * Literal Masks:
+ * Literal Masks:
* These are triggered from either floating literals or delayed literals and
* inspect the data behind them. Matches are raised at the same location as the
* trigger literal so there are no ordering issues. Masks are always pure
@@ -144,7 +144,7 @@ struct LeftNfaInfo {
u32 stopTable; // stop table index, or ROSE_OFFSET_INVALID
u8 transient; /**< 0 if not transient, else max width of transient prefix */
char infix; /* TODO: make flags */
- char eager; /**< nfa should be run eagerly to first match or death */
+ char eager; /**< nfa should be run eagerly to first match or death */
char eod_check; /**< nfa is used by the event eod literal */
u32 countingMiracleOffset; /** if not 0, offset to RoseCountingMiracle. */
rose_group squash_mask; /* & mask applied when rose nfa dies */
@@ -170,11 +170,11 @@ struct NfaInfo {
#define OWB_ZOMBIE_ALWAYS_YES 128 /* nfa will always answer yes to any rose
* prefix checks */
-/* offset of the status flags in the stream state. */
-#define ROSE_STATE_OFFSET_STATUS_FLAGS 0
+/* offset of the status flags in the stream state. */
+#define ROSE_STATE_OFFSET_STATUS_FLAGS 0
-/* offset of role mmbit in stream state (just after the status flag byte). */
-#define ROSE_STATE_OFFSET_ROLE_MMBIT sizeof(u8)
+/* offset of role mmbit in stream state (just after the status flag byte). */
+#define ROSE_STATE_OFFSET_ROLE_MMBIT sizeof(u8)
/**
* \brief Rose state offsets.
@@ -184,23 +184,23 @@ struct NfaInfo {
*
* State not covered by this structure includes:
*
- * -# the first byte, containing the status bitmask
+ * -# the first byte, containing the status bitmask
* -# the role state multibit
*/
struct RoseStateOffsets {
/** History buffer.
*
- * Max size of history is RoseEngine::historyRequired. */
+ * Max size of history is RoseEngine::historyRequired. */
u32 history;
- /** Exhausted multibit.
+ /** Exhausted multibit.
*
- * entry per exhaustible key (used by Highlander mode). If a bit is set,
+ * entry per exhaustible key (used by Highlander mode). If a bit is set,
* reports with that ekey should not be delivered to the user. */
u32 exhausted;
/** size in bytes of exhausted multibit */
- u32 exhausted_size;
+ u32 exhausted_size;
/** Logical multibit.
*
@@ -221,13 +221,13 @@ struct RoseStateOffsets {
/** Multibit for active suffix/outfix engines. */
u32 activeLeafArray;
- /** Size of multibit for active suffix/outfix engines in bytes. */
- u32 activeLeafArray_size;
-
- /** Multibit for active leftfix (prefix/infix) engines. */
+ /** Size of multibit for active suffix/outfix engines in bytes. */
+ u32 activeLeafArray_size;
+
+ /** Multibit for active leftfix (prefix/infix) engines. */
u32 activeLeftArray;
- /** Size of multibit for active leftfix (prefix/infix) engines in bytes. */
+ /** Size of multibit for active leftfix (prefix/infix) engines in bytes. */
u32 activeLeftArray_size;
/** Table of lag information (stored as one byte per engine) for active
@@ -243,12 +243,12 @@ struct RoseStateOffsets {
/** Size of packed Rose groups value, in bytes. */
u32 groups_size;
- /** State for long literal support. */
- u32 longLitState;
+ /** State for long literal support. */
+ u32 longLitState;
+
+ /** Size of the long literal state. */
+ u32 longLitState_size;
- /** Size of the long literal state. */
- u32 longLitState_size;
-
/** Packed SOM location slots. */
u32 somLocation;
@@ -258,29 +258,29 @@ struct RoseStateOffsets {
/** Multibit guarding SOM location slots. */
u32 somWritable;
- /** Size of each of the somValid and somWritable multibits, in bytes. */
- u32 somMultibit_size;
-
- /** Begin of the region where NFA engine state is stored.
- * The NFA state region extends to end. */
- u32 nfaStateBegin;
-
+ /** Size of each of the somValid and somWritable multibits, in bytes. */
+ u32 somMultibit_size;
+
+ /** Begin of the region where NFA engine state is stored.
+ * The NFA state region extends to end. */
+ u32 nfaStateBegin;
+
/** Total size of Rose state, in bytes. */
u32 end;
};
struct RoseBoundaryReports {
- /** \brief 0 if no reports list, otherwise offset of program to run to
- * deliver reports at EOD. */
- u32 reportEodOffset;
-
- /** \brief 0 if no reports list, otherwise offset of program to run to
- * deliver reports at offset 0. */
- u32 reportZeroOffset;
-
- /** \brief 0 if no reports list, otherwise offset of program to run to
- * deliver reports if EOD is at offset 0. Superset of other programs. */
- u32 reportZeroEodOffset;
+ /** \brief 0 if no reports list, otherwise offset of program to run to
+ * deliver reports at EOD. */
+ u32 reportEodOffset;
+
+ /** \brief 0 if no reports list, otherwise offset of program to run to
+ * deliver reports at offset 0. */
+ u32 reportZeroOffset;
+
+ /** \brief 0 if no reports list, otherwise offset of program to run to
+ * deliver reports if EOD is at offset 0. Superset of other programs. */
+ u32 reportZeroEodOffset;
};
/* NFA Queue Assignment
@@ -310,19 +310,19 @@ struct RoseBoundaryReports {
#define ROSE_RUNTIME_PURE_LITERAL 1
#define ROSE_RUNTIME_SINGLE_OUTFIX 2
-/**
- * \brief Runtime structure header for Rose.
- *
- * Runtime structure header for Rose.
- * In memory, we follow this with:
- * -# the "engine blob"
- * -# anchored 'literal' matcher table
- * -# floating literal matcher table
- * -# eod-anchored literal matcher table
- * -# small block table
- * -# array of NFA offsets, one per queue
- * -# array of state offsets, one per queue (+)
- *
+/**
+ * \brief Runtime structure header for Rose.
+ *
+ * Runtime structure header for Rose.
+ * In memory, we follow this with:
+ * -# the "engine blob"
+ * -# anchored 'literal' matcher table
+ * -# floating literal matcher table
+ * -# eod-anchored literal matcher table
+ * -# small block table
+ * -# array of NFA offsets, one per queue
+ * -# array of state offsets, one per queue (+)
+ *
* (+) stateOffset array note: Offsets in the array are either into the stream
* state (normal case) or into the tstate region of scratch (for transient rose
* nfas). Rose nfa info table can distinguish the cases.
@@ -350,11 +350,11 @@ struct RoseEngine {
u32 logicalTreeOffset; /**< offset to mapping from lkey to LogicalOp */
u32 combInfoMapOffset; /**< offset to mapping from ckey to combInfo */
u32 dkeyCount; /**< number of dedupe keys */
- u32 dkeyLogSize; /**< size of fatbit for storing dkey log (bytes) */
+ u32 dkeyLogSize; /**< size of fatbit for storing dkey log (bytes) */
u32 invDkeyOffset; /**< offset to table mapping from dkeys to the external
* report ids */
u32 somLocationCount; /**< number of som locations required */
- u32 somLocationFatbitSize; /**< size of SOM location fatbit (bytes) */
+ u32 somLocationFatbitSize; /**< size of SOM location fatbit (bytes) */
u32 rolesWithStateCount; // number of roles with entries in state bitset
u32 stateSize; /* size of the state bitset
* WARNING: not the size of the rose state */
@@ -366,9 +366,9 @@ struct RoseEngine {
u32 amatcherOffset; // offset of the anchored literal matcher (bytes)
u32 ematcherOffset; // offset of the eod-anchored literal matcher (bytes)
u32 fmatcherOffset; // offset of the floating literal matcher (bytes)
- u32 drmatcherOffset; // offset of the delayed rebuild table (bytes)
+ u32 drmatcherOffset; // offset of the delayed rebuild table (bytes)
u32 sbmatcherOffset; // offset of the small-block literal matcher (bytes)
- u32 longLitTableOffset; // offset of the long literal table
+ u32 longLitTableOffset; // offset of the long literal table
u32 amatcherMinWidth; /**< minimum number of bytes required for a pattern
* involved with the anchored table to produce a full
* match. */
@@ -384,48 +384,48 @@ struct RoseEngine {
u32 fmatcherMaxBiAnchoredWidth; /**< maximum number of bytes that can still
* produce a match for a pattern involved
* with the anchored table. */
-
- /**
- * \brief Offset of u32 array of program offsets for reports used by
- * output-exposed engines.
- */
- u32 reportProgramOffset;
-
- /**
- * \brief Number of programs for reports used by output-exposed engines.
- */
- u32 reportProgramCount;
-
- /**
- * \brief Offset of u32 array of program offsets for delayed replay of
- * literals.
- */
- u32 delayProgramOffset;
-
- /**
- * \brief Offset of u32 array of program offsets for anchored literals.
- */
- u32 anchoredProgramOffset;
-
+
+ /**
+ * \brief Offset of u32 array of program offsets for reports used by
+ * output-exposed engines.
+ */
+ u32 reportProgramOffset;
+
+ /**
+ * \brief Number of programs for reports used by output-exposed engines.
+ */
+ u32 reportProgramCount;
+
+ /**
+ * \brief Offset of u32 array of program offsets for delayed replay of
+ * literals.
+ */
+ u32 delayProgramOffset;
+
+ /**
+ * \brief Offset of u32 array of program offsets for anchored literals.
+ */
+ u32 anchoredProgramOffset;
+
u32 activeArrayCount; //number of nfas tracked in the active array
u32 activeLeftCount; //number of nfas tracked in the active rose array
u32 queueCount; /**< number of nfa queues */
- u32 activeQueueArraySize; //!< size of fatbit for active queues (bytes)
-
- u32 eagerIterOffset; /**< offset to sparse iter for eager prefixes or 0 if
- * none */
-
- /** \brief Number of keys used by CHECK_SET_HANDLED instructions in role
- * programs. */
- u32 handledKeyCount;
-
- /** \brief Size of the handled keys fatbit in scratch (bytes). */
- u32 handledKeyFatbitSize;
-
+ u32 activeQueueArraySize; //!< size of fatbit for active queues (bytes)
+
+ u32 eagerIterOffset; /**< offset to sparse iter for eager prefixes or 0 if
+ * none */
+
+ /** \brief Number of keys used by CHECK_SET_HANDLED instructions in role
+ * programs. */
+ u32 handledKeyCount;
+
+ /** \brief Size of the handled keys fatbit in scratch (bytes). */
+ u32 handledKeyFatbitSize;
+
u32 leftOffset;
u32 roseCount;
- u32 eodProgramOffset; //!< EOD program, otherwise 0.
+ u32 eodProgramOffset; //!< EOD program, otherwise 0.
u32 flushCombProgramOffset; /**< FlushCombination program, otherwise 0 */
u32 lastFlushCombProgramOffset; /**< LastFlushCombination program,
* otherwise 0 */
@@ -453,12 +453,12 @@ struct RoseEngine {
* table */
u32 nfaInfoOffset; /* offset to the nfa info offset array */
rose_group initialGroups;
- rose_group floating_group_mask; /* groups that are used by the ftable */
+ rose_group floating_group_mask; /* groups that are used by the ftable */
u32 size; // (bytes)
u32 delay_count; /* number of delayed literal ids. */
- u32 delay_fatbit_size; //!< size of each delay fatbit in scratch (bytes)
+ u32 delay_fatbit_size; //!< size of each delay fatbit in scratch (bytes)
u32 anchored_count; /* number of anchored literal ids */
- u32 anchored_fatbit_size; //!< size of each anch fatbit in scratch (bytes)
+ u32 anchored_fatbit_size; //!< size of each anch fatbit in scratch (bytes)
u32 maxFloatingDelayedMatch; /* max offset that a delayed literal can
* usefully be reported */
u32 delayRebuildLength; /* length of the history region which needs to be
@@ -477,7 +477,7 @@ struct RoseEngine {
u32 ematcherRegionSize; /* max region size to pass to ematcher */
u32 somRevCount; /**< number of som reverse nfas */
u32 somRevOffsetOffset; /**< offset to array of offsets to som rev nfas */
- u32 longLitStreamState; // size in bytes
+ u32 longLitStreamState; // size in bytes
struct scatter_full_plan state_init;
};
@@ -488,72 +488,72 @@ struct ALIGN_CL_DIRECTIVE anchored_matcher_info {
u32 anchoredMinDistance; /* start of region to run anchored table over */
};
-/**
- * \brief Long literal subtable for a particular mode (caseful or nocase).
- */
-struct RoseLongLitSubtable {
- /**
- * \brief Offset of the hash table (relative to RoseLongLitTable base).
- *
- * Offset is zero if no such table exists.
- */
- u32 hashOffset;
-
- /**
- * \brief Offset of the bloom filter (relative to RoseLongLitTable base).
- *
- * Offset is zero if no such table exists.
- */
- u32 bloomOffset;
-
- /** \brief lg2 of the size of the hash table. */
- u8 hashBits;
-
- /** \brief Size of the bloom filter in bits. */
- u8 bloomBits;
-
- /** \brief Number of bits of packed stream state used. */
- u8 streamStateBits;
-};
-
-/**
- * \brief Long literal table header.
- */
-struct RoseLongLitTable {
- /**
- * \brief Total size of the whole table (including strings, bloom filters,
- * hash tables).
- */
- u32 size;
-
- /** \brief Caseful sub-table (hash table and bloom filter). */
- struct RoseLongLitSubtable caseful;
-
- /** \brief Caseless sub-table (hash table and bloom filter). */
- struct RoseLongLitSubtable nocase;
-
- /** \brief Total size of packed stream state in bytes. */
- u8 streamStateBytes;
-
- /** \brief Max length of literal prefixes. */
- u8 maxLen;
-};
-
-/**
- * \brief One of these structures per hash table entry in our long literal
- * table.
- */
-struct RoseLongLitHashEntry {
- /**
- * \brief Offset of the literal string itself, relative to
- * RoseLongLitTable base. Zero if this bucket is empty.
- */
- u32 str_offset;
-
- /** \brief Length of the literal string. */
- u32 str_len;
-};
-
+/**
+ * \brief Long literal subtable for a particular mode (caseful or nocase).
+ */
+struct RoseLongLitSubtable {
+ /**
+ * \brief Offset of the hash table (relative to RoseLongLitTable base).
+ *
+ * Offset is zero if no such table exists.
+ */
+ u32 hashOffset;
+
+ /**
+ * \brief Offset of the bloom filter (relative to RoseLongLitTable base).
+ *
+ * Offset is zero if no such table exists.
+ */
+ u32 bloomOffset;
+
+ /** \brief lg2 of the size of the hash table. */
+ u8 hashBits;
+
+ /** \brief Size of the bloom filter in bits. */
+ u8 bloomBits;
+
+ /** \brief Number of bits of packed stream state used. */
+ u8 streamStateBits;
+};
+
+/**
+ * \brief Long literal table header.
+ */
+struct RoseLongLitTable {
+ /**
+ * \brief Total size of the whole table (including strings, bloom filters,
+ * hash tables).
+ */
+ u32 size;
+
+ /** \brief Caseful sub-table (hash table and bloom filter). */
+ struct RoseLongLitSubtable caseful;
+
+ /** \brief Caseless sub-table (hash table and bloom filter). */
+ struct RoseLongLitSubtable nocase;
+
+ /** \brief Total size of packed stream state in bytes. */
+ u8 streamStateBytes;
+
+ /** \brief Max length of literal prefixes. */
+ u8 maxLen;
+};
+
+/**
+ * \brief One of these structures per hash table entry in our long literal
+ * table.
+ */
+struct RoseLongLitHashEntry {
+ /**
+ * \brief Offset of the literal string itself, relative to
+ * RoseLongLitTable base. Zero if this bucket is empty.
+ */
+ u32 str_offset;
+
+ /** \brief Length of the literal string. */
+ u32 str_len;
+};
+
static really_inline
const struct anchored_matcher_info *getALiteralMatcher(
const struct RoseEngine *t) {
diff --git a/contrib/libs/hyperscan/src/rose/rose_program.h b/contrib/libs/hyperscan/src/rose/rose_program.h
index 056b30828da..7e21303cb7c 100644
--- a/contrib/libs/hyperscan/src/rose/rose_program.h
+++ b/contrib/libs/hyperscan/src/rose/rose_program.h
@@ -1,188 +1,188 @@
-/*
+/*
* Copyright (c) 2015-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Rose data structures to do with role programs.
- */
-
-#ifndef ROSE_ROSE_PROGRAM_H
-#define ROSE_ROSE_PROGRAM_H
-
-#include "som/som_operation.h"
-#include "rose_internal.h"
-#include "ue2common.h"
-#include "util/simd_types.h"
-
-/** \brief Minimum alignment for each instruction in memory. */
-#define ROSE_INSTR_MIN_ALIGN 8U
-
-/** \brief Role program instruction opcodes. */
-enum RoseInstructionCode {
- ROSE_INSTR_END, //!< End of program.
- ROSE_INSTR_ANCHORED_DELAY, //!< Delay until after anchored matcher.
- ROSE_INSTR_CHECK_LIT_EARLY, //!< Skip matches before floating min offset.
- ROSE_INSTR_CHECK_GROUPS, //!< Check that literal groups are on.
- ROSE_INSTR_CHECK_ONLY_EOD, //!< Role matches only at EOD.
- ROSE_INSTR_CHECK_BOUNDS, //!< Bounds on distance from offset 0.
- ROSE_INSTR_CHECK_NOT_HANDLED, //!< Test & set role in "handled".
- ROSE_INSTR_CHECK_SINGLE_LOOKAROUND, //!< Single lookaround check.
- ROSE_INSTR_CHECK_LOOKAROUND, //!< Lookaround check.
- ROSE_INSTR_CHECK_MASK, //!< 8-bytes mask check.
- ROSE_INSTR_CHECK_MASK_32, //!< 32-bytes and/cmp/neg mask check.
- ROSE_INSTR_CHECK_BYTE, //!< Single Byte check.
- ROSE_INSTR_CHECK_SHUFTI_16x8, //!< Check 16-byte data by 8-bucket shufti.
- ROSE_INSTR_CHECK_SHUFTI_32x8, //!< Check 32-byte data by 8-bucket shufti.
- ROSE_INSTR_CHECK_SHUFTI_16x16, //!< Check 16-byte data by 16-bucket shufti.
- ROSE_INSTR_CHECK_SHUFTI_32x16, //!< Check 32-byte data by 16-bucket shufti.
- ROSE_INSTR_CHECK_INFIX, //!< Infix engine must be in accept state.
- ROSE_INSTR_CHECK_PREFIX, //!< Prefix engine must be in accept state.
- ROSE_INSTR_PUSH_DELAYED, //!< Push delayed literal matches.
- ROSE_INSTR_DUMMY_NOP, //!< NOP. Should not exist in build programs.
- ROSE_INSTR_CATCH_UP, //!< Catch up engines, anchored matches.
- ROSE_INSTR_CATCH_UP_MPV, //!< Catch up the MPV.
- ROSE_INSTR_SOM_ADJUST, //!< Set SOM from a distance to EOM.
- ROSE_INSTR_SOM_LEFTFIX, //!< Acquire SOM from a leftfix engine.
- ROSE_INSTR_SOM_FROM_REPORT, //!< Acquire SOM from a som_operation.
- ROSE_INSTR_SOM_ZERO, //!< Set SOM to zero.
- ROSE_INSTR_TRIGGER_INFIX, //!< Trigger an infix engine.
- ROSE_INSTR_TRIGGER_SUFFIX, //!< Trigger a suffix engine.
- ROSE_INSTR_DEDUPE, //!< Run deduplication for report.
- ROSE_INSTR_DEDUPE_SOM, //!< Run deduplication for SOM report.
- ROSE_INSTR_REPORT_CHAIN, //!< Fire a chained report (MPV).
- ROSE_INSTR_REPORT_SOM_INT, //!< Manipulate SOM only.
- ROSE_INSTR_REPORT_SOM_AWARE, //!< Manipulate SOM from SOM-aware source.
-
- /** \brief Fire a report. */
- ROSE_INSTR_REPORT,
-
- /** \brief Fire an exhaustible report. */
- ROSE_INSTR_REPORT_EXHAUST,
-
- /** \brief Fire a SOM report. */
- ROSE_INSTR_REPORT_SOM,
-
- /** \brief Fire an exhaustible SOM report. */
- ROSE_INSTR_REPORT_SOM_EXHAUST,
-
- /** \brief Super-instruction combining DEDUPE and REPORT. */
- ROSE_INSTR_DEDUPE_AND_REPORT,
-
- /**
- * \brief Fire a report and stop program execution. This is a
- * specialisation intended for short, frequently-executed programs.
- */
- ROSE_INSTR_FINAL_REPORT,
-
- ROSE_INSTR_CHECK_EXHAUSTED, //!< Check if an ekey has already been set.
- ROSE_INSTR_CHECK_MIN_LENGTH, //!< Check (EOM - SOM) against min length.
- ROSE_INSTR_SET_STATE, //!< Switch a state index on.
- ROSE_INSTR_SET_GROUPS, //!< Set some literal group bits.
- ROSE_INSTR_SQUASH_GROUPS, //!< Conditionally turn off some groups.
- ROSE_INSTR_CHECK_STATE, //!< Test a single bit in the state multibit.
- ROSE_INSTR_SPARSE_ITER_BEGIN, //!< Begin running a sparse iter over states.
- ROSE_INSTR_SPARSE_ITER_NEXT, //!< Continue running sparse iter over states.
- ROSE_INSTR_SPARSE_ITER_ANY, //!< Test for any bit in the sparse iterator.
-
- /** \brief Check outfixes and suffixes for EOD and fire reports if so. */
- ROSE_INSTR_ENGINES_EOD,
-
- /** \brief Catch up and check active suffixes for EOD and fire reports if
- * so. */
- ROSE_INSTR_SUFFIXES_EOD,
-
- /** \brief Run the EOD-anchored HWLM literal matcher. */
- ROSE_INSTR_MATCHER_EOD,
-
- /**
- * \brief Confirm a case-sensitive literal at the current offset. In
- * streaming mode, this makes use of the long literal table.
- */
- ROSE_INSTR_CHECK_LONG_LIT,
-
- /**
- * \brief Confirm a case-insensitive literal at the current offset. In
- * streaming mode, this makes use of the long literal table.
- */
- ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
-
- /**
- * \brief Confirm a case-sensitive "medium length" literal at the current
- * offset. In streaming mode, this will check history if needed.
- */
- ROSE_INSTR_CHECK_MED_LIT,
-
- /**
- * \brief Confirm a case-insensitive "medium length" literal at the current
- * offset. In streaming mode, this will check history if needed.
- */
- ROSE_INSTR_CHECK_MED_LIT_NOCASE,
-
- /**
- * \brief Clear the "work done" flag used by the SQUASH_GROUPS instruction.
- */
- ROSE_INSTR_CLEAR_WORK_DONE,
-
- /** \brief Check lookaround if it has multiple paths. */
- ROSE_INSTR_MULTIPATH_LOOKAROUND,
-
- /**
- * \brief Use shufti to check lookaround with multiple paths. The total
- * length of the paths is 16 bytes at most and shufti has 8 buckets.
- * All paths can be at most 16 bytes long.
- */
- ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
-
- /**
- * \brief Use shufti to check lookaround with multiple paths. The total
- * length of the paths is 32 bytes at most and shufti has 8 buckets.
- * All paths can be at most 16 bytes long.
- */
- ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
-
- /**
- * \brief Use shufti to check lookaround with multiple paths. The total
- * length of the paths is 32 bytes at most and shufti has 16 buckets.
- * All paths can be at most 16 bytes long.
- */
- ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
-
- /**
- * \brief Use shufti to check multiple paths lookaround. The total
- * length of the paths is 64 bytes at most and shufti has 8 buckets.
- * All paths can be at most 16 bytes long.
- */
- ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
-
- /**
- * \brief Jump to the program of included literal.
- */
- ROSE_INSTR_INCLUDED_JUMP,
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Rose data structures to do with role programs.
+ */
+
+#ifndef ROSE_ROSE_PROGRAM_H
+#define ROSE_ROSE_PROGRAM_H
+
+#include "som/som_operation.h"
+#include "rose_internal.h"
+#include "ue2common.h"
+#include "util/simd_types.h"
+
+/** \brief Minimum alignment for each instruction in memory. */
+#define ROSE_INSTR_MIN_ALIGN 8U
+
+/** \brief Role program instruction opcodes. */
+enum RoseInstructionCode {
+ ROSE_INSTR_END, //!< End of program.
+ ROSE_INSTR_ANCHORED_DELAY, //!< Delay until after anchored matcher.
+ ROSE_INSTR_CHECK_LIT_EARLY, //!< Skip matches before floating min offset.
+ ROSE_INSTR_CHECK_GROUPS, //!< Check that literal groups are on.
+ ROSE_INSTR_CHECK_ONLY_EOD, //!< Role matches only at EOD.
+ ROSE_INSTR_CHECK_BOUNDS, //!< Bounds on distance from offset 0.
+ ROSE_INSTR_CHECK_NOT_HANDLED, //!< Test & set role in "handled".
+ ROSE_INSTR_CHECK_SINGLE_LOOKAROUND, //!< Single lookaround check.
+ ROSE_INSTR_CHECK_LOOKAROUND, //!< Lookaround check.
+ ROSE_INSTR_CHECK_MASK, //!< 8-bytes mask check.
+ ROSE_INSTR_CHECK_MASK_32, //!< 32-bytes and/cmp/neg mask check.
+ ROSE_INSTR_CHECK_BYTE, //!< Single Byte check.
+ ROSE_INSTR_CHECK_SHUFTI_16x8, //!< Check 16-byte data by 8-bucket shufti.
+ ROSE_INSTR_CHECK_SHUFTI_32x8, //!< Check 32-byte data by 8-bucket shufti.
+ ROSE_INSTR_CHECK_SHUFTI_16x16, //!< Check 16-byte data by 16-bucket shufti.
+ ROSE_INSTR_CHECK_SHUFTI_32x16, //!< Check 32-byte data by 16-bucket shufti.
+ ROSE_INSTR_CHECK_INFIX, //!< Infix engine must be in accept state.
+ ROSE_INSTR_CHECK_PREFIX, //!< Prefix engine must be in accept state.
+ ROSE_INSTR_PUSH_DELAYED, //!< Push delayed literal matches.
+ ROSE_INSTR_DUMMY_NOP, //!< NOP. Should not exist in build programs.
+ ROSE_INSTR_CATCH_UP, //!< Catch up engines, anchored matches.
+ ROSE_INSTR_CATCH_UP_MPV, //!< Catch up the MPV.
+ ROSE_INSTR_SOM_ADJUST, //!< Set SOM from a distance to EOM.
+ ROSE_INSTR_SOM_LEFTFIX, //!< Acquire SOM from a leftfix engine.
+ ROSE_INSTR_SOM_FROM_REPORT, //!< Acquire SOM from a som_operation.
+ ROSE_INSTR_SOM_ZERO, //!< Set SOM to zero.
+ ROSE_INSTR_TRIGGER_INFIX, //!< Trigger an infix engine.
+ ROSE_INSTR_TRIGGER_SUFFIX, //!< Trigger a suffix engine.
+ ROSE_INSTR_DEDUPE, //!< Run deduplication for report.
+ ROSE_INSTR_DEDUPE_SOM, //!< Run deduplication for SOM report.
+ ROSE_INSTR_REPORT_CHAIN, //!< Fire a chained report (MPV).
+ ROSE_INSTR_REPORT_SOM_INT, //!< Manipulate SOM only.
+ ROSE_INSTR_REPORT_SOM_AWARE, //!< Manipulate SOM from SOM-aware source.
+
+ /** \brief Fire a report. */
+ ROSE_INSTR_REPORT,
+
+ /** \brief Fire an exhaustible report. */
+ ROSE_INSTR_REPORT_EXHAUST,
+
+ /** \brief Fire a SOM report. */
+ ROSE_INSTR_REPORT_SOM,
+
+ /** \brief Fire an exhaustible SOM report. */
+ ROSE_INSTR_REPORT_SOM_EXHAUST,
+
+ /** \brief Super-instruction combining DEDUPE and REPORT. */
+ ROSE_INSTR_DEDUPE_AND_REPORT,
+
+ /**
+ * \brief Fire a report and stop program execution. This is a
+ * specialisation intended for short, frequently-executed programs.
+ */
+ ROSE_INSTR_FINAL_REPORT,
+
+ ROSE_INSTR_CHECK_EXHAUSTED, //!< Check if an ekey has already been set.
+ ROSE_INSTR_CHECK_MIN_LENGTH, //!< Check (EOM - SOM) against min length.
+ ROSE_INSTR_SET_STATE, //!< Switch a state index on.
+ ROSE_INSTR_SET_GROUPS, //!< Set some literal group bits.
+ ROSE_INSTR_SQUASH_GROUPS, //!< Conditionally turn off some groups.
+ ROSE_INSTR_CHECK_STATE, //!< Test a single bit in the state multibit.
+ ROSE_INSTR_SPARSE_ITER_BEGIN, //!< Begin running a sparse iter over states.
+ ROSE_INSTR_SPARSE_ITER_NEXT, //!< Continue running sparse iter over states.
+ ROSE_INSTR_SPARSE_ITER_ANY, //!< Test for any bit in the sparse iterator.
+
+ /** \brief Check outfixes and suffixes for EOD and fire reports if so. */
+ ROSE_INSTR_ENGINES_EOD,
+
+ /** \brief Catch up and check active suffixes for EOD and fire reports if
+ * so. */
+ ROSE_INSTR_SUFFIXES_EOD,
+
+ /** \brief Run the EOD-anchored HWLM literal matcher. */
+ ROSE_INSTR_MATCHER_EOD,
+
+ /**
+ * \brief Confirm a case-sensitive literal at the current offset. In
+ * streaming mode, this makes use of the long literal table.
+ */
+ ROSE_INSTR_CHECK_LONG_LIT,
+
+ /**
+ * \brief Confirm a case-insensitive literal at the current offset. In
+ * streaming mode, this makes use of the long literal table.
+ */
+ ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
+
+ /**
+ * \brief Confirm a case-sensitive "medium length" literal at the current
+ * offset. In streaming mode, this will check history if needed.
+ */
+ ROSE_INSTR_CHECK_MED_LIT,
+
+ /**
+ * \brief Confirm a case-insensitive "medium length" literal at the current
+ * offset. In streaming mode, this will check history if needed.
+ */
+ ROSE_INSTR_CHECK_MED_LIT_NOCASE,
+
+ /**
+ * \brief Clear the "work done" flag used by the SQUASH_GROUPS instruction.
+ */
+ ROSE_INSTR_CLEAR_WORK_DONE,
+
+ /** \brief Check lookaround if it has multiple paths. */
+ ROSE_INSTR_MULTIPATH_LOOKAROUND,
+
+ /**
+ * \brief Use shufti to check lookaround with multiple paths. The total
+ * length of the paths is 16 bytes at most and shufti has 8 buckets.
+ * All paths can be at most 16 bytes long.
+ */
+ ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
+
+ /**
+ * \brief Use shufti to check lookaround with multiple paths. The total
+ * length of the paths is 32 bytes at most and shufti has 8 buckets.
+ * All paths can be at most 16 bytes long.
+ */
+ ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
+
+ /**
+ * \brief Use shufti to check lookaround with multiple paths. The total
+ * length of the paths is 32 bytes at most and shufti has 16 buckets.
+ * All paths can be at most 16 bytes long.
+ */
+ ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
+
+ /**
+ * \brief Use shufti to check multiple paths lookaround. The total
+ * length of the paths is 64 bytes at most and shufti has 8 buckets.
+ * All paths can be at most 16 bytes long.
+ */
+ ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
+
+ /**
+ * \brief Jump to the program of included literal.
+ */
+ ROSE_INSTR_INCLUDED_JUMP,
+
/**
* \brief Set matching status of a sub-expression.
*/
@@ -213,82 +213,82 @@ enum RoseInstructionCode {
ROSE_INSTR_CHECK_MASK_64, //!< 64-bytes and/cmp/neg mask check.
LAST_ROSE_INSTRUCTION = ROSE_INSTR_CHECK_MASK_64 //!< Sentinel.
-};
-
-struct ROSE_STRUCT_END {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_ANCHORED_DELAY {
- u8 code; //!< From enum RoseInstructionCode.
- rose_group groups; //!< Bitmask.
- u32 anch_id; //!< Program to restart after the delay.
- u32 done_jump; //!< Jump forward this many bytes if we have to delay.
-};
-
-struct ROSE_STRUCT_CHECK_LIT_EARLY {
- u8 code; //!< From enum RoseInstructionCode.
- u32 min_offset; //!< Minimum offset for this literal.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-/** Note: check failure will halt program. */
-struct ROSE_STRUCT_CHECK_GROUPS {
- u8 code; //!< From enum RoseInstructionCode.
- rose_group groups; //!< Bitmask.
-};
-
-struct ROSE_STRUCT_CHECK_ONLY_EOD {
- u8 code; //!< From enum RoseInstructionCode.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_BOUNDS {
- u8 code; //!< From enum RoseInstructionCode.
- u64a min_bound; //!< Min distance from zero.
- u64a max_bound; //!< Max distance from zero.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_NOT_HANDLED {
- u8 code; //!< From enum RoseInstructionCode.
- u32 key; //!< Key in the "handled_roles" fatbit in scratch.
- u32 fail_jump; //!< Jump forward this many bytes if we have seen key before.
-};
-
-struct ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND {
- u8 code; //!< From enum RoseInstructionCode.
- s8 offset; //!< The offset of the byte to examine.
- u32 reach_index; //!< Index for lookaround reach bitvectors.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_LOOKAROUND {
- u8 code; //!< From enum RoseInstructionCode.
- u32 look_index; //!< Offset in bytecode of lookaround offset list.
- u32 reach_index; //!< Offset in bytecode of lookaround reach bitvectors.
- u32 count; //!< The count of lookaround entries in one instruction.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MASK {
- u8 code; //!< From enum roseInstructionCode.
- u64a and_mask; //!< 8-byte and mask.
- u64a cmp_mask; //!< 8-byte cmp mask.
- u64a neg_mask; //!< 8-byte negation mask.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MASK_32 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 and_mask[32]; //!< 32-byte and mask.
- u8 cmp_mask[32]; //!< 32-byte cmp mask.
- u32 neg_mask; //!< negation mask with 32 bits.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
+};
+
+struct ROSE_STRUCT_END {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_ANCHORED_DELAY {
+ u8 code; //!< From enum RoseInstructionCode.
+ rose_group groups; //!< Bitmask.
+ u32 anch_id; //!< Program to restart after the delay.
+ u32 done_jump; //!< Jump forward this many bytes if we have to delay.
+};
+
+struct ROSE_STRUCT_CHECK_LIT_EARLY {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 min_offset; //!< Minimum offset for this literal.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+/** Note: check failure will halt program. */
+struct ROSE_STRUCT_CHECK_GROUPS {
+ u8 code; //!< From enum RoseInstructionCode.
+ rose_group groups; //!< Bitmask.
+};
+
+struct ROSE_STRUCT_CHECK_ONLY_EOD {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_BOUNDS {
+ u8 code; //!< From enum RoseInstructionCode.
+ u64a min_bound; //!< Min distance from zero.
+ u64a max_bound; //!< Max distance from zero.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_NOT_HANDLED {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 key; //!< Key in the "handled_roles" fatbit in scratch.
+ u32 fail_jump; //!< Jump forward this many bytes if we have seen key before.
+};
+
+struct ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND {
+ u8 code; //!< From enum RoseInstructionCode.
+ s8 offset; //!< The offset of the byte to examine.
+ u32 reach_index; //!< Index for lookaround reach bitvectors.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_LOOKAROUND {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 look_index; //!< Offset in bytecode of lookaround offset list.
+ u32 reach_index; //!< Offset in bytecode of lookaround reach bitvectors.
+ u32 count; //!< The count of lookaround entries in one instruction.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MASK {
+ u8 code; //!< From enum roseInstructionCode.
+ u64a and_mask; //!< 8-byte and mask.
+ u64a cmp_mask; //!< 8-byte cmp mask.
+ u64a neg_mask; //!< 8-byte negation mask.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MASK_32 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 and_mask[32]; //!< 32-byte and mask.
+ u8 cmp_mask[32]; //!< 32-byte cmp mask.
+ u32 neg_mask; //!< negation mask with 32 bits.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
struct ROSE_STRUCT_CHECK_MASK_64 {
u8 code; //!< From enum RoseInstructionCode.
u8 and_mask[64]; //!< 64-byte and mask.
@@ -298,57 +298,57 @@ struct ROSE_STRUCT_CHECK_MASK_64 {
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
-struct ROSE_STRUCT_CHECK_BYTE {
- u8 code; //!< From enum RoseInstructionCode.
- u8 and_mask; //!< 8-bits and mask.
- u8 cmp_mask; //!< 8-bits cmp mask.
- u8 negation; //!< Flag about negation.
- s32 offset; //!< The relative offset.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-// Since m128 and m256 could be missaligned in the bytecode,
-// we'll use u8[16] and u8[32] instead in all rose_check_shufti structures.
-struct ROSE_STRUCT_CHECK_SHUFTI_16x8 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 nib_mask[32]; //!< High 16 and low 16 bits nibble mask in shufti.
- u8 bucket_select_mask[16]; //!< Mask for bucket assigning.
- u32 neg_mask; //!< Negation mask in low 16 bits.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_SHUFTI_32x8 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[16]; //!< High nibble mask in shufti.
- u8 lo_mask[16]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask[32]; //!< Mask for bucket assigning.
- u32 neg_mask; //!< 32 bits negation mask.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_SHUFTI_16x16 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[32]; //!< High nibble mask in shufti.
- u8 lo_mask[32]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask[32]; //!< Mask for bucket assigning.
- u32 neg_mask; //!< Negation mask in low 16 bits.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_SHUFTI_32x16 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[32]; //!< High nibble mask in shufti.
- u8 lo_mask[32]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask_hi[32]; //!< Bucket mask for high 8 buckets.
- u8 bucket_select_mask_lo[32]; //!< Bucket mask for low 8 buckets.
- u32 neg_mask; //!< 32 bits negation mask.
- s32 offset; //!< Relative offset of the first byte.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
+struct ROSE_STRUCT_CHECK_BYTE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 and_mask; //!< 8-bits and mask.
+ u8 cmp_mask; //!< 8-bits cmp mask.
+ u8 negation; //!< Flag about negation.
+ s32 offset; //!< The relative offset.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+// Since m128 and m256 could be missaligned in the bytecode,
+// we'll use u8[16] and u8[32] instead in all rose_check_shufti structures.
+struct ROSE_STRUCT_CHECK_SHUFTI_16x8 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 nib_mask[32]; //!< High 16 and low 16 bits nibble mask in shufti.
+ u8 bucket_select_mask[16]; //!< Mask for bucket assigning.
+ u32 neg_mask; //!< Negation mask in low 16 bits.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_SHUFTI_32x8 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[16]; //!< High nibble mask in shufti.
+ u8 lo_mask[16]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask[32]; //!< Mask for bucket assigning.
+ u32 neg_mask; //!< 32 bits negation mask.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_SHUFTI_16x16 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[32]; //!< High nibble mask in shufti.
+ u8 lo_mask[32]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask[32]; //!< Mask for bucket assigning.
+ u32 neg_mask; //!< Negation mask in low 16 bits.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_SHUFTI_32x16 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[32]; //!< High nibble mask in shufti.
+ u8 lo_mask[32]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask_hi[32]; //!< Bucket mask for high 8 buckets.
+ u8 bucket_select_mask_lo[32]; //!< Bucket mask for low 8 buckets.
+ u32 neg_mask; //!< 32 bits negation mask.
+ s32 offset; //!< Relative offset of the first byte.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
struct ROSE_STRUCT_CHECK_SHUFTI_64x8 {
u8 code; //!< From enum RoseInstructionCode.
u8 hi_mask[64]; //!< High nibble mask in shufti.
@@ -372,331 +372,331 @@ struct ROSE_STRUCT_CHECK_SHUFTI_64x16 {
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
-struct ROSE_STRUCT_CHECK_INFIX {
- u8 code; //!< From enum RoseInstructionCode.
- u32 queue; //!< Queue of leftfix to check.
- u32 lag; //!< Lag of leftfix for this case.
- ReportID report; //!< ReportID of leftfix to check.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_PREFIX {
- u8 code; //!< From enum RoseInstructionCode.
- u32 queue; //!< Queue of leftfix to check.
- u32 lag; //!< Lag of leftfix for this case.
- ReportID report; //!< ReportID of leftfix to check.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_PUSH_DELAYED {
- u8 code; //!< From enum RoseInstructionCode.
- u8 delay; // Number of bytes to delay.
- u32 index; // Delay literal index (relative to first delay lit).
-};
-
-struct ROSE_STRUCT_DUMMY_NOP {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_CATCH_UP {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_CATCH_UP_MPV {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_SOM_ADJUST {
- u8 code; //!< From enum RoseInstructionCode.
- u32 distance; //!< Distance to EOM.
-};
-
-struct ROSE_STRUCT_SOM_LEFTFIX {
- u8 code; //!< From enum RoseInstructionCode.
- u32 queue; //!< Queue index of leftfix providing SOM.
- u32 lag; //!< Lag of leftfix for this case.
-};
-
-struct ROSE_STRUCT_SOM_FROM_REPORT {
- u8 code; //!< From enum RoseInstructionCode.
- struct som_operation som;
-};
-
-struct ROSE_STRUCT_SOM_ZERO {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_TRIGGER_INFIX {
- u8 code; //!< From enum RoseInstructionCode.
- u8 cancel; //!< Cancels previous top event.
- u32 queue; //!< Queue index of infix.
- u32 event; //!< Queue event, from MQE_*.
-};
-
-struct ROSE_STRUCT_TRIGGER_SUFFIX {
- u8 code; //!< From enum RoseInstructionCode.
- u32 queue; //!< Queue index of suffix.
- u32 event; //!< Queue event, from MQE_*.
-};
-
-struct ROSE_STRUCT_DEDUPE {
- u8 code; //!< From enum RoseInstructionCode.
- u8 quash_som; //!< Force SOM to zero for this report.
- u32 dkey; //!< Dedupe key.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_DEDUPE_SOM {
- u8 code; //!< From enum RoseInstructionCode.
- u8 quash_som; //!< Force SOM to zero for this report.
- u32 dkey; //!< Dedupe key.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_REPORT_CHAIN {
- u8 code; //!< From enum RoseInstructionCode.
- u32 event; //!< Queue event, from MQE_*. Must be a top.
-
- /**
- * \brief Number of bytes behind us that we are allowed to squash
- * identical top events on the queue.
- */
- u64a top_squash_distance;
-};
-
-struct ROSE_STRUCT_REPORT_SOM_INT {
- u8 code; //!< From enum RoseInstructionCode.
- struct som_operation som;
-};
-
-struct ROSE_STRUCT_REPORT_SOM_AWARE {
- u8 code; //!< From enum RoseInstructionCode.
- struct som_operation som;
-};
-
-struct ROSE_STRUCT_REPORT {
- u8 code; //!< From enum RoseInstructionCode.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
-};
-
-struct ROSE_STRUCT_REPORT_EXHAUST {
- u8 code; //!< From enum RoseInstructionCode.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
- u32 ekey; //!< Exhaustion key.
-};
-
-struct ROSE_STRUCT_REPORT_SOM {
- u8 code; //!< From enum RoseInstructionCode.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
-};
-
-struct ROSE_STRUCT_REPORT_SOM_EXHAUST {
- u8 code; //!< From enum RoseInstructionCode.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
- u32 ekey; //!< Exhaustion key.
-};
-
-struct ROSE_STRUCT_DEDUPE_AND_REPORT {
- u8 code; //!< From enum RoseInstructionCode.
- u8 quash_som; //!< Force SOM to zero for this report.
- u32 dkey; //!< Dedupe key.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_FINAL_REPORT {
- u8 code; //!< From enum RoseInstructionCode.
- ReportID onmatch; //!< Report ID to deliver to user.
- s32 offset_adjust; //!< Offset adjustment to apply to end offset.
-};
-
-struct ROSE_STRUCT_CHECK_EXHAUSTED {
- u8 code; //!< From enum RoseInstructionCode.
- u32 ekey; //!< Exhaustion key to check.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MIN_LENGTH {
- u8 code; //!< From enum RoseInstructionCode.
- s32 end_adj; //!< Offset adjustment to add to EOM first.
- u64a min_length; //!< Minimum distance from SOM to EOM.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_SET_STATE {
- u8 code; //!< From enum RoseInstructionCode.
- u32 index; //!< State index in multibit.
-};
-
-struct ROSE_STRUCT_SET_GROUPS {
- u8 code; //!< From enum RoseInstructionCode.
- rose_group groups; //!< Bitmask to OR into groups.
-};
-
-struct ROSE_STRUCT_SQUASH_GROUPS {
- u8 code; //!< From enum RoseInstructionCode.
- rose_group groups; //!< Bitmask to AND into groups.
-};
-
-struct ROSE_STRUCT_CHECK_STATE {
- u8 code; //!< From enum RoseInstructionCode.
- u32 index; //!< State index in the role multibit.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-/**
- * Note that the offsets in the jump table are always relative to the start of
- * the program, not the current instruction.
- */
-struct ROSE_STRUCT_SPARSE_ITER_BEGIN {
- u8 code; //!< From enum RoseInstructionCode.
- u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
- u32 jump_table; //!< Offset of jump table indexed by sparse iterator.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-/**
- * Note that the offsets in the jump table are always relative to the start of
- * the program, not the current instruction.
- */
-struct ROSE_STRUCT_SPARSE_ITER_NEXT {
- u8 code; //!< From enum RoseInstructionCode.
- u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
- u32 jump_table; //!< Offset of jump table indexed by sparse iterator.
- u32 state; // Current state index.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_SPARSE_ITER_ANY {
- u8 code; //!< From enum RoseInstructionCode.
- u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_ENGINES_EOD {
- u8 code; //!< From enum RoseInstructionCode.
- u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
-};
-
-struct ROSE_STRUCT_SUFFIXES_EOD {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_MATCHER_EOD {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_CHECK_LONG_LIT {
- u8 code; //!< From enum RoseInstructionCode.
- u32 lit_offset; //!< Offset of literal string.
- u32 lit_length; //!< Length of literal string.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_LONG_LIT_NOCASE {
- u8 code; //!< From enum RoseInstructionCode.
- u32 lit_offset; //!< Offset of literal string.
- u32 lit_length; //!< Length of literal string.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MED_LIT {
- u8 code; //!< From enum RoseInstructionCode.
- u32 lit_offset; //!< Offset of literal string.
- u32 lit_length; //!< Length of literal string.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MED_LIT_NOCASE {
- u8 code; //!< From enum RoseInstructionCode.
- u32 lit_offset; //!< Offset of literal string.
- u32 lit_length; //!< Length of literal string.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CLEAR_WORK_DONE {
- u8 code; //!< From enum RoseInstructionCode.
-};
-
-struct ROSE_STRUCT_MULTIPATH_LOOKAROUND {
- u8 code; //!< From enum RoseInstructionCode.
- u32 look_index; //!< Offset in bytecode of lookaround offset list.
- u32 reach_index; //!< Offset in bytecode of lookaround reach bitvectors.
- u32 count; //!< The lookaround byte numbers for each path.
- s32 last_start; //!< The latest start offset among 8 paths.
- u8 start_mask[MULTIPATH_MAX_LEN]; /*!< Used to initialize path if left-most
- * data is missed. */
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 nib_mask[2 * sizeof(m128)]; //!< High and low nibble mask in shufti.
- u8 bucket_select_mask[sizeof(m128)]; //!< Mask for bucket assigning.
- u8 data_select_mask[sizeof(m128)]; //!< Shuffle mask for data ordering.
- u32 hi_bits_mask; //!< High-bits used in multi-path validation.
- u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
- u32 neg_mask; //!< 64 bits negation mask.
- s32 base_offset; //!< Relative offset of the first byte.
- s32 last_start; //!< The latest start offset among 8 paths.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[sizeof(m128)]; //!< High nibble mask in shufti.
- u8 lo_mask[sizeof(m128)]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask[sizeof(m256)]; //!< Mask for bucket assigning.
- u8 data_select_mask[sizeof(m256)]; //!< Shuffle mask for data ordering.
- u32 hi_bits_mask; //!< High-bits used in multi-path validation.
- u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
- u32 neg_mask; //!< 64 bits negation mask.
- s32 base_offset; //!< Relative offset of the first byte.
- s32 last_start; //!< The latest start offset among 8 paths.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[sizeof(m256)]; //!< High nibble mask in shufti.
- u8 lo_mask[sizeof(m256)]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask_hi[sizeof(m256)]; //!< Mask for bucket assigning.
- u8 bucket_select_mask_lo[sizeof(m256)]; //!< Mask for bucket assigning.
- u8 data_select_mask[sizeof(m256)]; //!< Shuffle mask for data ordering.
- u32 hi_bits_mask; //!< High-bits used in multi-path validation.
- u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
- u32 neg_mask; //!< 64 bits negation mask.
- s32 base_offset; //!< Relative offset of the first byte.
- s32 last_start; //!< The latest start offset among 8 paths.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64 {
- u8 code; //!< From enum RoseInstructionCode.
- u8 hi_mask[sizeof(m128)]; //!< High nibble mask in shufti.
- u8 lo_mask[sizeof(m128)]; //!< Low nibble mask in shufti.
- u8 bucket_select_mask[2 * sizeof(m256)]; //!< Mask for bucket assigning.
- u8 data_select_mask[2 * sizeof(m256)]; //!< Shuffle mask for data ordering.
- u64a hi_bits_mask; //!< High-bits used in multi-path validation.
- u64a lo_bits_mask; //!< Low-bits used in multi-path validation.
- u64a neg_mask; //!< 64 bits negation mask.
- s32 base_offset; //!< Relative offset of the first byte.
- s32 last_start; //!< The latest start offset among 8 paths.
- u32 fail_jump; //!< Jump forward this many bytes on failure.
-};
-
-struct ROSE_STRUCT_INCLUDED_JUMP {
- u8 code; //!< From enum RoseInstructionCode.
- u8 squash; //!< FDR confirm squash mask for included literal.
- u32 child_offset; //!< Program offset of included literal.
-};
+struct ROSE_STRUCT_CHECK_INFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 queue; //!< Queue of leftfix to check.
+ u32 lag; //!< Lag of leftfix for this case.
+ ReportID report; //!< ReportID of leftfix to check.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_PREFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 queue; //!< Queue of leftfix to check.
+ u32 lag; //!< Lag of leftfix for this case.
+ ReportID report; //!< ReportID of leftfix to check.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_PUSH_DELAYED {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 delay; // Number of bytes to delay.
+ u32 index; // Delay literal index (relative to first delay lit).
+};
+
+struct ROSE_STRUCT_DUMMY_NOP {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_CATCH_UP {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_CATCH_UP_MPV {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_SOM_ADJUST {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 distance; //!< Distance to EOM.
+};
+
+struct ROSE_STRUCT_SOM_LEFTFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 queue; //!< Queue index of leftfix providing SOM.
+ u32 lag; //!< Lag of leftfix for this case.
+};
+
+struct ROSE_STRUCT_SOM_FROM_REPORT {
+ u8 code; //!< From enum RoseInstructionCode.
+ struct som_operation som;
+};
+
+struct ROSE_STRUCT_SOM_ZERO {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_TRIGGER_INFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 cancel; //!< Cancels previous top event.
+ u32 queue; //!< Queue index of infix.
+ u32 event; //!< Queue event, from MQE_*.
+};
+
+struct ROSE_STRUCT_TRIGGER_SUFFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 queue; //!< Queue index of suffix.
+ u32 event; //!< Queue event, from MQE_*.
+};
+
+struct ROSE_STRUCT_DEDUPE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 quash_som; //!< Force SOM to zero for this report.
+ u32 dkey; //!< Dedupe key.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_DEDUPE_SOM {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 quash_som; //!< Force SOM to zero for this report.
+ u32 dkey; //!< Dedupe key.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_REPORT_CHAIN {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 event; //!< Queue event, from MQE_*. Must be a top.
+
+ /**
+ * \brief Number of bytes behind us that we are allowed to squash
+ * identical top events on the queue.
+ */
+ u64a top_squash_distance;
+};
+
+struct ROSE_STRUCT_REPORT_SOM_INT {
+ u8 code; //!< From enum RoseInstructionCode.
+ struct som_operation som;
+};
+
+struct ROSE_STRUCT_REPORT_SOM_AWARE {
+ u8 code; //!< From enum RoseInstructionCode.
+ struct som_operation som;
+};
+
+struct ROSE_STRUCT_REPORT {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+};
+
+struct ROSE_STRUCT_REPORT_EXHAUST {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+ u32 ekey; //!< Exhaustion key.
+};
+
+struct ROSE_STRUCT_REPORT_SOM {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+};
+
+struct ROSE_STRUCT_REPORT_SOM_EXHAUST {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+ u32 ekey; //!< Exhaustion key.
+};
+
+struct ROSE_STRUCT_DEDUPE_AND_REPORT {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 quash_som; //!< Force SOM to zero for this report.
+ u32 dkey; //!< Dedupe key.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_FINAL_REPORT {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+};
+
+struct ROSE_STRUCT_CHECK_EXHAUSTED {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 ekey; //!< Exhaustion key to check.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MIN_LENGTH {
+ u8 code; //!< From enum RoseInstructionCode.
+ s32 end_adj; //!< Offset adjustment to add to EOM first.
+ u64a min_length; //!< Minimum distance from SOM to EOM.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_SET_STATE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 index; //!< State index in multibit.
+};
+
+struct ROSE_STRUCT_SET_GROUPS {
+ u8 code; //!< From enum RoseInstructionCode.
+ rose_group groups; //!< Bitmask to OR into groups.
+};
+
+struct ROSE_STRUCT_SQUASH_GROUPS {
+ u8 code; //!< From enum RoseInstructionCode.
+ rose_group groups; //!< Bitmask to AND into groups.
+};
+
+struct ROSE_STRUCT_CHECK_STATE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 index; //!< State index in the role multibit.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+/**
+ * Note that the offsets in the jump table are always relative to the start of
+ * the program, not the current instruction.
+ */
+struct ROSE_STRUCT_SPARSE_ITER_BEGIN {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
+ u32 jump_table; //!< Offset of jump table indexed by sparse iterator.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+/**
+ * Note that the offsets in the jump table are always relative to the start of
+ * the program, not the current instruction.
+ */
+struct ROSE_STRUCT_SPARSE_ITER_NEXT {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
+ u32 jump_table; //!< Offset of jump table indexed by sparse iterator.
+ u32 state; // Current state index.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_SPARSE_ITER_ANY {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_ENGINES_EOD {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
+};
+
+struct ROSE_STRUCT_SUFFIXES_EOD {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_MATCHER_EOD {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_CHECK_LONG_LIT {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 lit_offset; //!< Offset of literal string.
+ u32 lit_length; //!< Length of literal string.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_LONG_LIT_NOCASE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 lit_offset; //!< Offset of literal string.
+ u32 lit_length; //!< Length of literal string.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MED_LIT {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 lit_offset; //!< Offset of literal string.
+ u32 lit_length; //!< Length of literal string.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MED_LIT_NOCASE {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 lit_offset; //!< Offset of literal string.
+ u32 lit_length; //!< Length of literal string.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CLEAR_WORK_DONE {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
+struct ROSE_STRUCT_MULTIPATH_LOOKAROUND {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 look_index; //!< Offset in bytecode of lookaround offset list.
+ u32 reach_index; //!< Offset in bytecode of lookaround reach bitvectors.
+ u32 count; //!< The lookaround byte numbers for each path.
+ s32 last_start; //!< The latest start offset among 8 paths.
+ u8 start_mask[MULTIPATH_MAX_LEN]; /*!< Used to initialize path if left-most
+ * data is missed. */
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 nib_mask[2 * sizeof(m128)]; //!< High and low nibble mask in shufti.
+ u8 bucket_select_mask[sizeof(m128)]; //!< Mask for bucket assigning.
+ u8 data_select_mask[sizeof(m128)]; //!< Shuffle mask for data ordering.
+ u32 hi_bits_mask; //!< High-bits used in multi-path validation.
+ u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
+ u32 neg_mask; //!< 64 bits negation mask.
+ s32 base_offset; //!< Relative offset of the first byte.
+ s32 last_start; //!< The latest start offset among 8 paths.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[sizeof(m128)]; //!< High nibble mask in shufti.
+ u8 lo_mask[sizeof(m128)]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask[sizeof(m256)]; //!< Mask for bucket assigning.
+ u8 data_select_mask[sizeof(m256)]; //!< Shuffle mask for data ordering.
+ u32 hi_bits_mask; //!< High-bits used in multi-path validation.
+ u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
+ u32 neg_mask; //!< 64 bits negation mask.
+ s32 base_offset; //!< Relative offset of the first byte.
+ s32 last_start; //!< The latest start offset among 8 paths.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[sizeof(m256)]; //!< High nibble mask in shufti.
+ u8 lo_mask[sizeof(m256)]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask_hi[sizeof(m256)]; //!< Mask for bucket assigning.
+ u8 bucket_select_mask_lo[sizeof(m256)]; //!< Mask for bucket assigning.
+ u8 data_select_mask[sizeof(m256)]; //!< Shuffle mask for data ordering.
+ u32 hi_bits_mask; //!< High-bits used in multi-path validation.
+ u32 lo_bits_mask; //!< Low-bits used in multi-path validation.
+ u32 neg_mask; //!< 64 bits negation mask.
+ s32 base_offset; //!< Relative offset of the first byte.
+ s32 last_start; //!< The latest start offset among 8 paths.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64 {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 hi_mask[sizeof(m128)]; //!< High nibble mask in shufti.
+ u8 lo_mask[sizeof(m128)]; //!< Low nibble mask in shufti.
+ u8 bucket_select_mask[2 * sizeof(m256)]; //!< Mask for bucket assigning.
+ u8 data_select_mask[2 * sizeof(m256)]; //!< Shuffle mask for data ordering.
+ u64a hi_bits_mask; //!< High-bits used in multi-path validation.
+ u64a lo_bits_mask; //!< Low-bits used in multi-path validation.
+ u64a neg_mask; //!< 64 bits negation mask.
+ s32 base_offset; //!< Relative offset of the first byte.
+ s32 last_start; //!< The latest start offset among 8 paths.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_INCLUDED_JUMP {
+ u8 code; //!< From enum RoseInstructionCode.
+ u8 squash; //!< FDR confirm squash mask for included literal.
+ u32 child_offset; //!< Program offset of included literal.
+};
struct ROSE_STRUCT_SET_LOGICAL {
u8 code; //!< From enum RoseInstructionCode.
@@ -721,4 +721,4 @@ struct ROSE_STRUCT_SET_EXHAUST {
struct ROSE_STRUCT_LAST_FLUSH_COMBINATION {
u8 code; //!< From enum RoseInstructionCode.
};
-#endif // ROSE_ROSE_PROGRAM_H
+#endif // ROSE_ROSE_PROGRAM_H
diff --git a/contrib/libs/hyperscan/src/rose/rose_types.h b/contrib/libs/hyperscan/src/rose/rose_types.h
index ee64cddd6bb..9dcef1cef06 100644
--- a/contrib/libs/hyperscan/src/rose/rose_types.h
+++ b/contrib/libs/hyperscan/src/rose/rose_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,46 +26,46 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/** \file
- * \brief Rose runtime types (callbacks, etc).
- */
-
+/** \file
+ * \brief Rose runtime types (callbacks, etc).
+ */
+
#ifndef ROSE_TYPES_H
#define ROSE_TYPES_H
#include "ue2common.h"
-struct hs_scratch;
+struct hs_scratch;
+
+/**
+ * \brief Continue without checking for exhaustion.
+ *
+ * \ref RoseCallback return value indicating that execution should continue and
+ * that it is not necessary to check if all reports have been exhausted.
+ */
+#define ROSE_CONTINUE_MATCHING_NO_EXHAUST 2
-/**
- * \brief Continue without checking for exhaustion.
- *
- * \ref RoseCallback return value indicating that execution should continue and
- * that it is not necessary to check if all reports have been exhausted.
- */
-#define ROSE_CONTINUE_MATCHING_NO_EXHAUST 2
-
-/**
- * \brief The type for a Rose callback.
- *
- * \return
- * - \ref MO_HALT_MATCHING if matching should terminate;
- * - \ref MO_CONTINUE_MATCHING if matching should continue;
- * - \ref ROSE_CONTINUE_MATCHING_NO_EXHAUST if matching should continue and no
- * exhaustion is possible.
- */
-typedef int (*RoseCallback)(u64a offset, ReportID id,
- struct hs_scratch *scratch);
-
-/**
- * \brief The type for a Rose callback which also tracks start of match.
- *
- * Behaves just like \ref RoseCallback except that it is provided with both a
- * start and an end offset.
- *
- * \see RoseCallback
- */
+/**
+ * \brief The type for a Rose callback.
+ *
+ * \return
+ * - \ref MO_HALT_MATCHING if matching should terminate;
+ * - \ref MO_CONTINUE_MATCHING if matching should continue;
+ * - \ref ROSE_CONTINUE_MATCHING_NO_EXHAUST if matching should continue and no
+ * exhaustion is possible.
+ */
+typedef int (*RoseCallback)(u64a offset, ReportID id,
+ struct hs_scratch *scratch);
+
+/**
+ * \brief The type for a Rose callback which also tracks start of match.
+ *
+ * Behaves just like \ref RoseCallback except that it is provided with both a
+ * start and an end offset.
+ *
+ * \see RoseCallback
+ */
typedef int (*RoseCallbackSom)(u64a from_offset, u64a to_offset, ReportID id,
- struct hs_scratch *scratch);
+ struct hs_scratch *scratch);
#endif
diff --git a/contrib/libs/hyperscan/src/rose/runtime.h b/contrib/libs/hyperscan/src/rose/runtime.h
index 5a57222df20..5fbb2b7416a 100644
--- a/contrib/libs/hyperscan/src/rose/runtime.h
+++ b/contrib/libs/hyperscan/src/rose/runtime.h
@@ -33,33 +33,33 @@
#ifndef ROSE_RUNTIME_H
#define ROSE_RUNTIME_H
-#include "rose_internal.h"
+#include "rose_internal.h"
#include "scratch.h"
#include "util/partial_store.h"
/*
* ROSE STATE LAYOUT:
- *
- * - runtime status byte (halt status, delay rebuild dirty, etc)
- * - rose state multibit
- * - active leaf array (multibit)
- * - active leftfix array (multibit)
- * - leftfix lag table
- * - anchored matcher state
- * - literal groups
- * - history buffer
- * - exhausted bitvector
- * - som slots, som multibit arrays
- * - nfa stream state (for each nfa)
+ *
+ * - runtime status byte (halt status, delay rebuild dirty, etc)
+ * - rose state multibit
+ * - active leaf array (multibit)
+ * - active leftfix array (multibit)
+ * - leftfix lag table
+ * - anchored matcher state
+ * - literal groups
+ * - history buffer
+ * - exhausted bitvector
+ * - som slots, som multibit arrays
+ * - nfa stream state (for each nfa)
*/
#define rose_inline really_inline
-/* Maximum offset that we will eagerly run prefixes to. Beyond this point, eager
- * prefixes are always run in exactly the same way as normal prefixes. */
-#define EAGER_STOP_OFFSET 64
+/* Maximum offset that we will eagerly run prefixes to. Beyond this point, eager
+ * prefixes are always run in exactly the same way as normal prefixes. */
+#define EAGER_STOP_OFFSET 64
+
-
static really_inline
const void *getByOffset(const struct RoseEngine *t, u32 offset) {
assert(offset < t->size);
@@ -67,49 +67,49 @@ const void *getByOffset(const struct RoseEngine *t, u32 offset) {
}
static really_inline
-void *getRoleState(char *state) {
- return state + ROSE_STATE_OFFSET_ROLE_MMBIT;
+void *getRoleState(char *state) {
+ return state + ROSE_STATE_OFFSET_ROLE_MMBIT;
}
/** \brief Fetch the active array for suffix nfas. */
static really_inline
-u8 *getActiveLeafArray(const struct RoseEngine *t, char *state) {
- return (u8 *)(state + t->stateOffsets.activeLeafArray);
+u8 *getActiveLeafArray(const struct RoseEngine *t, char *state) {
+ return (u8 *)(state + t->stateOffsets.activeLeafArray);
}
/** \brief Fetch the active array for rose nfas. */
static really_inline
-u8 *getActiveLeftArray(const struct RoseEngine *t, char *state) {
- return (u8 *)(state + t->stateOffsets.activeLeftArray);
+u8 *getActiveLeftArray(const struct RoseEngine *t, char *state) {
+ return (u8 *)(state + t->stateOffsets.activeLeftArray);
}
static really_inline
-rose_group loadGroups(const struct RoseEngine *t, const char *state) {
+rose_group loadGroups(const struct RoseEngine *t, const char *state) {
return partial_load_u64a(state + t->stateOffsets.groups,
t->stateOffsets.groups_size);
}
static really_inline
-void storeGroups(const struct RoseEngine *t, char *state, rose_group groups) {
+void storeGroups(const struct RoseEngine *t, char *state, rose_group groups) {
partial_store_u64a(state + t->stateOffsets.groups, groups,
t->stateOffsets.groups_size);
}
static really_inline
-u8 *getLongLitState(const struct RoseEngine *t, char *state) {
- return (u8 *)(state + t->stateOffsets.longLitState);
+u8 *getLongLitState(const struct RoseEngine *t, char *state) {
+ return (u8 *)(state + t->stateOffsets.longLitState);
}
static really_inline
-u8 *getLeftfixLagTable(const struct RoseEngine *t, char *state) {
- return (u8 *)(state + t->stateOffsets.leftfixLagTable);
+u8 *getLeftfixLagTable(const struct RoseEngine *t, char *state) {
+ return (u8 *)(state + t->stateOffsets.leftfixLagTable);
}
static really_inline
-const u8 *getLeftfixLagTableConst(const struct RoseEngine *t,
- const char *state) {
- return (const u8 *)(state + t->stateOffsets.leftfixLagTable);
+const u8 *getLeftfixLagTableConst(const struct RoseEngine *t,
+ const char *state) {
+ return (const u8 *)(state + t->stateOffsets.leftfixLagTable);
}
static really_inline
diff --git a/contrib/libs/hyperscan/src/rose/stream.c b/contrib/libs/hyperscan/src/rose/stream.c
index b9c0c4b7586..26268dd5741 100644
--- a/contrib/libs/hyperscan/src/rose/stream.c
+++ b/contrib/libs/hyperscan/src/rose/stream.c
@@ -31,10 +31,10 @@
#include "infix.h"
#include "match.h"
#include "miracle.h"
-#include "program_runtime.h"
-#include "rose.h"
-#include "rose_internal.h"
-#include "stream_long_lit.h"
+#include "program_runtime.h"
+#include "rose.h"
+#include "rose_internal.h"
+#include "stream_long_lit.h"
#include "hwlm/hwlm.h"
#include "nfa/mcclellan.h"
#include "nfa/nfa_api.h"
@@ -46,7 +46,7 @@ static rose_inline
void runAnchoredTableStream(const struct RoseEngine *t, const void *atable,
size_t alen, u64a offset,
struct hs_scratch *scratch) {
- char *state_base = scratch->core_info.state + t->stateOffsets.anchorState;
+ char *state_base = scratch->core_info.state + t->stateOffsets.anchorState;
const struct anchored_matcher_info *curr = atable;
do {
@@ -77,7 +77,7 @@ void runAnchoredTableStream(const struct RoseEngine *t, const void *atable,
goto next_nfa;
}
} else {
- if (!unaligned_load_u16(state)) {
+ if (!unaligned_load_u16(state)) {
goto next_nfa;
}
}
@@ -86,11 +86,11 @@ void runAnchoredTableStream(const struct RoseEngine *t, const void *atable,
if (nfa->type == MCCLELLAN_NFA_8) {
nfaExecMcClellan8_SimpStream(nfa, state, scratch->core_info.buf,
start, adj, alen, roseAnchoredCallback,
- scratch);
+ scratch);
} else {
nfaExecMcClellan16_SimpStream(nfa, state, scratch->core_info.buf,
- start, adj, alen,
- roseAnchoredCallback, scratch);
+ start, adj, alen,
+ roseAnchoredCallback, scratch);
}
next_nfa:
@@ -129,7 +129,7 @@ enum MiracleAction {
};
static really_inline
-enum MiracleAction roseScanForMiracles(const struct RoseEngine *t, char *state,
+enum MiracleAction roseScanForMiracles(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, u32 qi,
const struct LeftNfaInfo *left,
const struct NFA *nfa) {
@@ -178,7 +178,7 @@ found_miracle:
nfaQueueInitState(q->nfa, q);
} else {
if (miracle_loc > end_loc - t->historyRequired) {
- char *streamState = state + getNfaInfoByQueue(t, qi)->stateOffset;
+ char *streamState = state + getNfaInfoByQueue(t, qi)->stateOffset;
u64a offset = ci->buf_offset + miracle_loc;
u8 key = offset ? getByteBefore(ci, miracle_loc) : 0;
DEBUG_PRINTF("init state, key=0x%02x, offset=%llu\n", key, offset);
@@ -193,7 +193,7 @@ found_miracle:
miracle_loc);
if (!q_active) {
fatbit_set(scratch->aqa, qCount, qi);
- initRoseQueue(t, qi, left, scratch);
+ initRoseQueue(t, qi, left, scratch);
}
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, miracle_loc);
@@ -206,7 +206,7 @@ found_miracle:
static really_inline
-char roseCatchUpLeftfix(const struct RoseEngine *t, char *state,
+char roseCatchUpLeftfix(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, u32 qi,
const struct LeftNfaInfo *left) {
assert(!left->transient); // active roses only
@@ -239,7 +239,7 @@ char roseCatchUpLeftfix(const struct RoseEngine *t, char *state,
}
if (!fatbit_set(scratch->aqa, qCount, qi)) {
- initRoseQueue(t, qi, left, scratch);
+ initRoseQueue(t, qi, left, scratch);
s32 sp;
if (ci->buf_offset) {
@@ -294,7 +294,7 @@ char roseCatchUpLeftfix(const struct RoseEngine *t, char *state,
DEBUG_PRINTF("infix died of old age\n");
return 0;
}
- reduceInfixQueue(q, last_loc, left->maxQueueLen, q->nfa->maxWidth);
+ reduceInfixQueue(q, last_loc, left->maxQueueLen, q->nfa->maxWidth);
}
DEBUG_PRINTF("end scan at %lld\n", last_loc);
@@ -324,7 +324,7 @@ char roseCatchUpLeftfix(const struct RoseEngine *t, char *state,
}
static rose_inline
-void roseCatchUpLeftfixes(const struct RoseEngine *t, char *state,
+void roseCatchUpLeftfixes(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch) {
if (!t->activeLeftIterOffset) {
// No sparse iter, no non-transient roses.
@@ -344,12 +344,12 @@ void roseCatchUpLeftfixes(const struct RoseEngine *t, char *state,
const struct LeftNfaInfo *left_table = getLeftTable(t);
const struct mmbit_sparse_iter *it = getActiveLeftIter(t);
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
-
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+
u32 idx = 0;
- u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
+ u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
for (; ri != MMB_INVALID;
- ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
+ ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
const struct LeftNfaInfo *left = left_table + ri;
u32 qi = ri + t->leftfixBeginQueue;
DEBUG_PRINTF("leftfix %u of %u, maxLag=%u, infix=%d\n", ri, arCount,
@@ -366,7 +366,7 @@ void roseCatchUpLeftfixes(const struct RoseEngine *t, char *state,
// Saves out stream state for all our active suffix NFAs.
static rose_inline
-void roseSaveNfaStreamState(const struct RoseEngine *t, char *state,
+void roseSaveNfaStreamState(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch) {
struct mq *queues = scratch->queues;
u8 *aa = getActiveLeafArray(t, state);
@@ -394,165 +394,165 @@ void roseSaveNfaStreamState(const struct RoseEngine *t, char *state,
}
static rose_inline
-void ensureStreamNeatAndTidy(const struct RoseEngine *t, char *state,
+void ensureStreamNeatAndTidy(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, size_t length,
- u64a offset) {
+ u64a offset) {
struct RoseContext *tctxt = &scratch->tctxt;
- if (roseCatchUpTo(t, scratch, length + scratch->core_info.buf_offset) ==
- HWLM_TERMINATE_MATCHING) {
+ if (roseCatchUpTo(t, scratch, length + scratch->core_info.buf_offset) ==
+ HWLM_TERMINATE_MATCHING) {
return; /* dead; no need to clean up state. */
}
roseSaveNfaStreamState(t, state, scratch);
roseCatchUpLeftfixes(t, state, scratch);
- roseFlushLastByteHistory(t, scratch, offset + length);
+ roseFlushLastByteHistory(t, scratch, offset + length);
tctxt->lastEndOffset = offset + length;
storeGroups(t, state, tctxt->groups);
- storeLongLiteralState(t, state, scratch);
+ storeLongLiteralState(t, state, scratch);
}
static really_inline
-void do_rebuild(const struct RoseEngine *t, struct hs_scratch *scratch) {
- assert(t->drmatcherOffset);
+void do_rebuild(const struct RoseEngine *t, struct hs_scratch *scratch) {
+ assert(t->drmatcherOffset);
assert(!can_stop_matching(scratch));
-
- const struct HWLM *hwlm = getByOffset(t, t->drmatcherOffset);
+
+ const struct HWLM *hwlm = getByOffset(t, t->drmatcherOffset);
size_t len = MIN(scratch->core_info.hlen, t->delayRebuildLength);
const u8 *buf = scratch->core_info.hbuf + scratch->core_info.hlen - len;
DEBUG_PRINTF("BEGIN FLOATING REBUILD over %zu bytes\n", len);
- scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
-
- hwlmExec(hwlm, buf, len, 0, roseDelayRebuildCallback, scratch,
+ scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
+
+ hwlmExec(hwlm, buf, len, 0, roseDelayRebuildCallback, scratch,
scratch->tctxt.groups);
assert(!can_stop_matching(scratch));
}
-static rose_inline
-void runEagerPrefixesStream(const struct RoseEngine *t,
- struct hs_scratch *scratch) {
- if (!t->eagerIterOffset
- || scratch->core_info.buf_offset >= EAGER_STOP_OFFSET) {
- return;
- }
-
- char *state = scratch->core_info.state;
- u8 *ara = getActiveLeftArray(t, state); /* indexed by offsets into
- * left_table */
- const u32 arCount = t->activeLeftCount;
- const u32 qCount = t->queueCount;
- const struct LeftNfaInfo *left_table = getLeftTable(t);
- const struct mmbit_sparse_iter *it = getByOffset(t, t->eagerIterOffset);
-
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
-
- u32 idx = 0;
- u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
- for (; ri != MMB_INVALID;
- ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
- const struct LeftNfaInfo *left = left_table + ri;
- u32 qi = ri + t->leftfixBeginQueue;
- DEBUG_PRINTF("leftfix %u of %u, maxLag=%u\n", ri, arCount, left->maxLag);
-
- assert(!fatbit_isset(scratch->aqa, qCount, qi));
- assert(left->eager);
- assert(!left->infix);
-
- struct mq *q = scratch->queues + qi;
- const struct NFA *nfa = getNfaByQueue(t, qi);
- s64a loc = MIN(scratch->core_info.len,
- EAGER_STOP_OFFSET - scratch->core_info.buf_offset);
-
- fatbit_set(scratch->aqa, qCount, qi);
- initRoseQueue(t, qi, left, scratch);
-
- if (scratch->core_info.buf_offset) {
- s64a sp = left->transient ? -(s64a)scratch->core_info.hlen
- : -(s64a)loadRoseDelay(t, state, left);
- pushQueueAt(q, 0, MQE_START, sp);
- if (scratch->core_info.buf_offset + sp > 0) {
- loadStreamState(nfa, q, sp);
- /* if the leftfix fix is currently in a match state, we cannot
- * advance it. */
- if (nfaInAnyAcceptState(nfa, q)) {
- continue;
- }
- pushQueueAt(q, 1, MQE_END, loc);
- } else {
- pushQueueAt(q, 1, MQE_TOP, sp);
- pushQueueAt(q, 2, MQE_END, loc);
- nfaQueueInitState(q->nfa, q);
- }
- } else {
- pushQueueAt(q, 0, MQE_START, 0);
- pushQueueAt(q, 1, MQE_TOP, 0);
- pushQueueAt(q, 2, MQE_END, loc);
- nfaQueueInitState(nfa, q);
- }
-
- char alive = nfaQueueExecToMatch(q->nfa, q, loc);
-
- if (!alive) {
- DEBUG_PRINTF("queue %u dead, squashing\n", qi);
- mmbit_unset(ara, arCount, ri);
- fatbit_unset(scratch->aqa, qCount, qi);
- scratch->tctxt.groups &= left->squash_mask;
- } else if (q->cur == q->end) {
- assert(alive != MO_MATCHES_PENDING);
- /* unlike in block mode we cannot squash groups if there is no match
- * in this block as we need the groups on for later stream writes */
- /* TODO: investigate possibility of a method to suppress groups for
- * a single stream block. */
- DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
- q->cur = q->end = 0;
- pushQueueAt(q, 0, MQE_START, loc);
- } else {
- assert(alive == MO_MATCHES_PENDING);
- DEBUG_PRINTF("queue %u unfinished, nfa lives\n", qi);
- q->end--; /* remove end item */
- }
- }
-}
-
-static really_inline
-int can_never_match(const struct RoseEngine *t, char *state,
- struct hs_scratch *scratch, size_t length, u64a offset) {
- struct RoseContext *tctxt = &scratch->tctxt;
-
- if (tctxt->groups) {
- DEBUG_PRINTF("still has active groups\n");
- return 0;
- }
-
- if (offset + length <= t->anchoredDistance) { /* not < as may have eod */
- DEBUG_PRINTF("still in anchored region\n");
- return 0;
- }
-
- if (t->lastByteHistoryIterOffset) { /* last byte history is hard */
- DEBUG_PRINTF("last byte history\n");
- return 0;
- }
-
- if (mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
- DEBUG_PRINTF("active leaf\n");
- return 0;
- }
-
- return 1;
-}
-
-void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
- DEBUG_PRINTF("OH HAI [%llu, %llu)\n", scratch->core_info.buf_offset,
- scratch->core_info.buf_offset + (u64a)scratch->core_info.len);
+static rose_inline
+void runEagerPrefixesStream(const struct RoseEngine *t,
+ struct hs_scratch *scratch) {
+ if (!t->eagerIterOffset
+ || scratch->core_info.buf_offset >= EAGER_STOP_OFFSET) {
+ return;
+ }
+
+ char *state = scratch->core_info.state;
+ u8 *ara = getActiveLeftArray(t, state); /* indexed by offsets into
+ * left_table */
+ const u32 arCount = t->activeLeftCount;
+ const u32 qCount = t->queueCount;
+ const struct LeftNfaInfo *left_table = getLeftTable(t);
+ const struct mmbit_sparse_iter *it = getByOffset(t, t->eagerIterOffset);
+
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+
+ u32 idx = 0;
+ u32 ri = mmbit_sparse_iter_begin(ara, arCount, &idx, it, si_state);
+ for (; ri != MMB_INVALID;
+ ri = mmbit_sparse_iter_next(ara, arCount, ri, &idx, it, si_state)) {
+ const struct LeftNfaInfo *left = left_table + ri;
+ u32 qi = ri + t->leftfixBeginQueue;
+ DEBUG_PRINTF("leftfix %u of %u, maxLag=%u\n", ri, arCount, left->maxLag);
+
+ assert(!fatbit_isset(scratch->aqa, qCount, qi));
+ assert(left->eager);
+ assert(!left->infix);
+
+ struct mq *q = scratch->queues + qi;
+ const struct NFA *nfa = getNfaByQueue(t, qi);
+ s64a loc = MIN(scratch->core_info.len,
+ EAGER_STOP_OFFSET - scratch->core_info.buf_offset);
+
+ fatbit_set(scratch->aqa, qCount, qi);
+ initRoseQueue(t, qi, left, scratch);
+
+ if (scratch->core_info.buf_offset) {
+ s64a sp = left->transient ? -(s64a)scratch->core_info.hlen
+ : -(s64a)loadRoseDelay(t, state, left);
+ pushQueueAt(q, 0, MQE_START, sp);
+ if (scratch->core_info.buf_offset + sp > 0) {
+ loadStreamState(nfa, q, sp);
+ /* if the leftfix fix is currently in a match state, we cannot
+ * advance it. */
+ if (nfaInAnyAcceptState(nfa, q)) {
+ continue;
+ }
+ pushQueueAt(q, 1, MQE_END, loc);
+ } else {
+ pushQueueAt(q, 1, MQE_TOP, sp);
+ pushQueueAt(q, 2, MQE_END, loc);
+ nfaQueueInitState(q->nfa, q);
+ }
+ } else {
+ pushQueueAt(q, 0, MQE_START, 0);
+ pushQueueAt(q, 1, MQE_TOP, 0);
+ pushQueueAt(q, 2, MQE_END, loc);
+ nfaQueueInitState(nfa, q);
+ }
+
+ char alive = nfaQueueExecToMatch(q->nfa, q, loc);
+
+ if (!alive) {
+ DEBUG_PRINTF("queue %u dead, squashing\n", qi);
+ mmbit_unset(ara, arCount, ri);
+ fatbit_unset(scratch->aqa, qCount, qi);
+ scratch->tctxt.groups &= left->squash_mask;
+ } else if (q->cur == q->end) {
+ assert(alive != MO_MATCHES_PENDING);
+ /* unlike in block mode we cannot squash groups if there is no match
+ * in this block as we need the groups on for later stream writes */
+ /* TODO: investigate possibility of a method to suppress groups for
+ * a single stream block. */
+ DEBUG_PRINTF("queue %u finished, nfa lives\n", qi);
+ q->cur = q->end = 0;
+ pushQueueAt(q, 0, MQE_START, loc);
+ } else {
+ assert(alive == MO_MATCHES_PENDING);
+ DEBUG_PRINTF("queue %u unfinished, nfa lives\n", qi);
+ q->end--; /* remove end item */
+ }
+ }
+}
+
+static really_inline
+int can_never_match(const struct RoseEngine *t, char *state,
+ struct hs_scratch *scratch, size_t length, u64a offset) {
+ struct RoseContext *tctxt = &scratch->tctxt;
+
+ if (tctxt->groups) {
+ DEBUG_PRINTF("still has active groups\n");
+ return 0;
+ }
+
+ if (offset + length <= t->anchoredDistance) { /* not < as may have eod */
+ DEBUG_PRINTF("still in anchored region\n");
+ return 0;
+ }
+
+ if (t->lastByteHistoryIterOffset) { /* last byte history is hard */
+ DEBUG_PRINTF("last byte history\n");
+ return 0;
+ }
+
+ if (mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
+ DEBUG_PRINTF("active leaf\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
+ DEBUG_PRINTF("OH HAI [%llu, %llu)\n", scratch->core_info.buf_offset,
+ scratch->core_info.buf_offset + (u64a)scratch->core_info.len);
assert(t);
assert(scratch->core_info.hbuf);
assert(scratch->core_info.buf);
- // We should not have been called if we've already been told to terminate
- // matching.
- assert(!told_to_stop_matching(scratch));
-
+ // We should not have been called if we've already been told to terminate
+ // matching.
+ assert(!told_to_stop_matching(scratch));
+
assert(mmbit_sparse_iter_state_size(t->rolesWithStateCount)
< MAX_SPARSE_ITER_STATES);
@@ -568,7 +568,7 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
return;
}
- char *state = scratch->core_info.state;
+ char *state = scratch->core_info.state;
struct RoseContext *tctxt = &scratch->tctxt;
tctxt->mpv_inactive = 0;
@@ -583,8 +583,8 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
tctxt->minNonMpvMatchOffset = offset;
tctxt->next_mpv_offset = 0;
- DEBUG_PRINTF("BEGIN: history len=%zu, buffer len=%zu groups=%016llx\n",
- scratch->core_info.hlen, scratch->core_info.len, tctxt->groups);
+ DEBUG_PRINTF("BEGIN: history len=%zu, buffer len=%zu groups=%016llx\n",
+ scratch->core_info.hlen, scratch->core_info.len, tctxt->groups);
fatbit_clear(scratch->aqa);
scratch->al_log_sum = 0;
@@ -594,7 +594,7 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
streamInitSufPQ(t, state, scratch);
}
- runEagerPrefixesStream(t, scratch);
+ runEagerPrefixesStream(t, scratch);
u32 alen = t->anchoredDistance > offset ?
MIN(length + offset, t->anchoredDistance) - offset : 0;
@@ -611,13 +611,13 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
const struct HWLM *ftable = getFLiteralMatcher(t);
if (ftable) {
- // Load in long literal table state and set up "fake history" buffers
- // (ll_buf, etc, used by the CHECK_LONG_LIT instruction). Note that this
- // must be done here in order to ensure that it happens before any path
- // that leads to storeLongLiteralState(), which relies on these buffers.
- loadLongLiteralState(t, state, scratch);
-
- if (t->noFloatingRoots && !roseHasInFlightMatches(t, state, scratch)) {
+ // Load in long literal table state and set up "fake history" buffers
+ // (ll_buf, etc, used by the CHECK_LONG_LIT instruction). Note that this
+ // must be done here in order to ensure that it happens before any path
+ // that leads to storeLongLiteralState(), which relies on these buffers.
+ loadLongLiteralState(t, state, scratch);
+
+ if (t->noFloatingRoots && !roseHasInFlightMatches(t, state, scratch)) {
DEBUG_PRINTF("skip FLOATING: no inflight matches\n");
goto flush_delay_and_exit;
}
@@ -630,18 +630,18 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
size_t hlength = scratch->core_info.hlen;
- char rebuild = hlength &&
- (scratch->core_info.status & STATUS_DELAY_DIRTY) &&
- (t->maxFloatingDelayedMatch == ROSE_BOUND_INF ||
- offset < t->maxFloatingDelayedMatch);
+ char rebuild = hlength &&
+ (scratch->core_info.status & STATUS_DELAY_DIRTY) &&
+ (t->maxFloatingDelayedMatch == ROSE_BOUND_INF ||
+ offset < t->maxFloatingDelayedMatch);
DEBUG_PRINTF("**rebuild %hhd status %hhu mfdm %u, offset %llu\n",
- rebuild, scratch->core_info.status,
- t->maxFloatingDelayedMatch, offset);
+ rebuild, scratch->core_info.status,
+ t->maxFloatingDelayedMatch, offset);
+
+ if (rebuild) { /* rebuild floating delayed match stuff */
+ do_rebuild(t, scratch);
+ }
- if (rebuild) { /* rebuild floating delayed match stuff */
- do_rebuild(t, scratch);
- }
-
if (!flen) {
goto flush_delay_and_exit;
}
@@ -660,93 +660,93 @@ void roseStreamExec(const struct RoseEngine *t, struct hs_scratch *scratch) {
DEBUG_PRINTF("start=%zu\n", start);
DEBUG_PRINTF("BEGIN FLOATING (over %zu/%zu)\n", flen, length);
- hwlmExecStreaming(ftable, flen, start, roseFloatingCallback, scratch,
- tctxt->groups & t->floating_group_mask);
+ hwlmExecStreaming(ftable, flen, start, roseFloatingCallback, scratch,
+ tctxt->groups & t->floating_group_mask);
}
flush_delay_and_exit:
DEBUG_PRINTF("flushing floating\n");
- if (cleanUpDelayed(t, scratch, length, offset) == HWLM_TERMINATE_MATCHING) {
+ if (cleanUpDelayed(t, scratch, length, offset) == HWLM_TERMINATE_MATCHING) {
return;
}
exit:
DEBUG_PRINTF("CLEAN UP TIME\n");
if (!can_stop_matching(scratch)) {
- ensureStreamNeatAndTidy(t, state, scratch, length, offset);
+ ensureStreamNeatAndTidy(t, state, scratch, length, offset);
+ }
+
+ if (!told_to_stop_matching(scratch)
+ && can_never_match(t, state, scratch, length, offset)) {
+ DEBUG_PRINTF("PATTERN SET IS EXHAUSTED\n");
+ scratch->core_info.status = STATUS_EXHAUSTED;
+ return;
}
-
- if (!told_to_stop_matching(scratch)
- && can_never_match(t, state, scratch, length, offset)) {
- DEBUG_PRINTF("PATTERN SET IS EXHAUSTED\n");
- scratch->core_info.status = STATUS_EXHAUSTED;
- return;
- }
-
- DEBUG_PRINTF("DONE STREAMING SCAN, status = %u\n",
- scratch->core_info.status);
+
+ DEBUG_PRINTF("DONE STREAMING SCAN, status = %u\n",
+ scratch->core_info.status);
return;
}
-
-static rose_inline
-void roseStreamInitEod(const struct RoseEngine *t, u64a offset,
- struct hs_scratch *scratch) {
- struct RoseContext *tctxt = &scratch->tctxt;
- /* TODO: diff groups for eod */
- tctxt->groups = loadGroups(t, scratch->core_info.state);
- tctxt->lit_offset_adjust = scratch->core_info.buf_offset
- - scratch->core_info.hlen
- + 1; // index after last byte
- tctxt->delayLastEndOffset = offset;
- tctxt->lastEndOffset = offset;
- tctxt->filledDelayedSlots = 0;
- tctxt->lastMatchOffset = 0;
+
+static rose_inline
+void roseStreamInitEod(const struct RoseEngine *t, u64a offset,
+ struct hs_scratch *scratch) {
+ struct RoseContext *tctxt = &scratch->tctxt;
+ /* TODO: diff groups for eod */
+ tctxt->groups = loadGroups(t, scratch->core_info.state);
+ tctxt->lit_offset_adjust = scratch->core_info.buf_offset
+ - scratch->core_info.hlen
+ + 1; // index after last byte
+ tctxt->delayLastEndOffset = offset;
+ tctxt->lastEndOffset = offset;
+ tctxt->filledDelayedSlots = 0;
+ tctxt->lastMatchOffset = 0;
tctxt->lastCombMatchOffset = offset; /* DO NOT set 0 here! */
- tctxt->minMatchOffset = offset;
- tctxt->minNonMpvMatchOffset = offset;
- tctxt->next_mpv_offset = offset;
-
- scratch->catchup_pq.qm_size = 0;
- scratch->al_log_sum = 0; /* clear the anchored logs */
-
- fatbit_clear(scratch->aqa);
-}
-
-void roseStreamEodExec(const struct RoseEngine *t, u64a offset,
- struct hs_scratch *scratch) {
- assert(scratch);
- assert(t->requiresEodCheck);
- DEBUG_PRINTF("ci buf %p/%zu his %p/%zu\n", scratch->core_info.buf,
- scratch->core_info.len, scratch->core_info.hbuf,
- scratch->core_info.hlen);
-
- // We should not have been called if we've already been told to terminate
- // matching.
- assert(!told_to_stop_matching(scratch));
-
- if (t->maxBiAnchoredWidth != ROSE_BOUND_INF
- && offset > t->maxBiAnchoredWidth) {
- DEBUG_PRINTF("bailing, we are beyond max width\n");
- /* also some of the history/state may be stale */
- return;
- }
-
- if (!t->eodProgramOffset) {
- DEBUG_PRINTF("no eod program\n");
- return;
- }
-
- roseStreamInitEod(t, offset, scratch);
-
- DEBUG_PRINTF("running eod program at %u\n", t->eodProgramOffset);
-
- // There should be no pending delayed literals.
- assert(!scratch->tctxt.filledDelayedSlots);
-
- const u64a som = 0;
- const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
-
- // Note: we ignore the result, as this is the last thing to ever happen on
- // a scan.
- roseRunProgram(t, scratch, t->eodProgramOffset, som, offset, flags);
-}
+ tctxt->minMatchOffset = offset;
+ tctxt->minNonMpvMatchOffset = offset;
+ tctxt->next_mpv_offset = offset;
+
+ scratch->catchup_pq.qm_size = 0;
+ scratch->al_log_sum = 0; /* clear the anchored logs */
+
+ fatbit_clear(scratch->aqa);
+}
+
+void roseStreamEodExec(const struct RoseEngine *t, u64a offset,
+ struct hs_scratch *scratch) {
+ assert(scratch);
+ assert(t->requiresEodCheck);
+ DEBUG_PRINTF("ci buf %p/%zu his %p/%zu\n", scratch->core_info.buf,
+ scratch->core_info.len, scratch->core_info.hbuf,
+ scratch->core_info.hlen);
+
+ // We should not have been called if we've already been told to terminate
+ // matching.
+ assert(!told_to_stop_matching(scratch));
+
+ if (t->maxBiAnchoredWidth != ROSE_BOUND_INF
+ && offset > t->maxBiAnchoredWidth) {
+ DEBUG_PRINTF("bailing, we are beyond max width\n");
+ /* also some of the history/state may be stale */
+ return;
+ }
+
+ if (!t->eodProgramOffset) {
+ DEBUG_PRINTF("no eod program\n");
+ return;
+ }
+
+ roseStreamInitEod(t, offset, scratch);
+
+ DEBUG_PRINTF("running eod program at %u\n", t->eodProgramOffset);
+
+ // There should be no pending delayed literals.
+ assert(!scratch->tctxt.filledDelayedSlots);
+
+ const u64a som = 0;
+ const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP;
+
+ // Note: we ignore the result, as this is the last thing to ever happen on
+ // a scan.
+ roseRunProgram(t, scratch, t->eodProgramOffset, som, offset, flags);
+}
diff --git a/contrib/libs/hyperscan/src/rose/stream_long_lit.h b/contrib/libs/hyperscan/src/rose/stream_long_lit.h
index 34bc00e2862..df9b57f4e27 100644
--- a/contrib/libs/hyperscan/src/rose/stream_long_lit.h
+++ b/contrib/libs/hyperscan/src/rose/stream_long_lit.h
@@ -1,372 +1,372 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef STREAM_LONG_LIT_H
-#define STREAM_LONG_LIT_H
-
-#include "rose.h"
-#include "rose_common.h"
-#include "rose_internal.h"
-#include "stream_long_lit_hash.h"
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef STREAM_LONG_LIT_H
+#define STREAM_LONG_LIT_H
+
+#include "rose.h"
+#include "rose_common.h"
+#include "rose_internal.h"
+#include "stream_long_lit_hash.h"
#include "util/compare.h"
-#include "util/copybytes.h"
-
-static really_inline
-const struct RoseLongLitHashEntry *
-getHashTableBase(const struct RoseLongLitTable *ll_table,
- const struct RoseLongLitSubtable *ll_sub) {
- assert(ll_sub->hashOffset);
- return (const struct RoseLongLitHashEntry *)((const char *)ll_table +
- ll_sub->hashOffset);
-}
-
-// Reads from stream state and unpacks values into stream state table.
-static really_inline
-void loadLongLitStreamState(const struct RoseLongLitTable *ll_table,
- const u8 *ll_state, u32 *state_case,
- u32 *state_nocase) {
- assert(ll_table);
- assert(ll_state);
- assert(state_case && state_nocase);
-
- u8 ss_bytes = ll_table->streamStateBytes;
- u8 ssb = ll_table->caseful.streamStateBits;
- UNUSED u8 ssb_nc = ll_table->nocase.streamStateBits;
- assert(ss_bytes == (ssb + ssb_nc + 7) / 8);
-
-#if defined(ARCH_32_BIT)
- // On 32-bit hosts, we may be able to avoid having to do any u64a
- // manipulation at all.
- if (ss_bytes <= 4) {
- u32 ssb_mask = (1U << ssb) - 1;
- u32 streamVal = partial_load_u32(ll_state, ss_bytes);
- *state_case = (u32)(streamVal & ssb_mask);
- *state_nocase = (u32)(streamVal >> ssb);
- return;
- }
-#endif
-
- u64a ssb_mask = (1ULL << ssb) - 1;
- u64a streamVal = partial_load_u64a(ll_state, ss_bytes);
- *state_case = (u32)(streamVal & ssb_mask);
- *state_nocase = (u32)(streamVal >> ssb);
-}
-
-static rose_inline
-void loadLongLiteralStateMode(struct hs_scratch *scratch,
- const struct RoseLongLitTable *ll_table,
- const struct RoseLongLitSubtable *ll_sub,
- const u32 state, const char nocase) {
- if (!state) {
- DEBUG_PRINTF("no state for %s\n", nocase ? "caseless" : "caseful");
- return;
- }
-
- const struct RoseLongLitHashEntry *tab = getHashTableBase(ll_table, ll_sub);
- const struct RoseLongLitHashEntry *ent = tab + state - 1;
-
- assert(ent->str_offset + ent->str_len <= ll_table->size);
- const u8 *found_buf = (const u8 *)ll_table + ent->str_offset;
- size_t found_sz = ent->str_len;
-
- struct RoseContext *tctxt = &scratch->tctxt;
- if (nocase) {
- tctxt->ll_buf_nocase = found_buf;
- tctxt->ll_len_nocase = found_sz;
- } else {
- tctxt->ll_buf = found_buf;
- tctxt->ll_len = found_sz;
- }
-}
-
-static rose_inline
-void loadLongLiteralState(const struct RoseEngine *t, char *state,
- struct hs_scratch *scratch) {
- if (!t->longLitTableOffset) {
- return;
- }
-
- // If we don't have any long literals in play, these values must point to
- // the real history buffer so that CHECK_LONG_LIT instructions examine the
- // history buffer.
- scratch->tctxt.ll_buf = scratch->core_info.hbuf;
- scratch->tctxt.ll_len = scratch->core_info.hlen;
- scratch->tctxt.ll_buf_nocase = scratch->core_info.hbuf;
- scratch->tctxt.ll_len_nocase = scratch->core_info.hlen;
-
- if (!scratch->core_info.hlen) {
- return;
- }
-
- const struct RoseLongLitTable *ll_table =
- getByOffset(t, t->longLitTableOffset);
- const u8 *ll_state = getLongLitState(t, state);
-
- u32 state_case;
- u32 state_nocase;
- loadLongLitStreamState(ll_table, ll_state, &state_case, &state_nocase);
-
- DEBUG_PRINTF("loaded {%u, %u}\n", state_case, state_nocase);
-
- loadLongLiteralStateMode(scratch, ll_table, &ll_table->caseful,
- state_case, 0);
- loadLongLiteralStateMode(scratch, ll_table, &ll_table->nocase,
- state_nocase, 1);
-}
-
-static rose_inline
-char confirmLongLiteral(const struct RoseLongLitTable *ll_table,
- const struct hs_scratch *scratch,
- const struct RoseLongLitHashEntry *ent,
- const char nocase) {
- assert(ent->str_offset + ent->str_len <= ll_table->size);
- const u8 *s = (const u8 *)ll_table + ent->str_offset;
- size_t len = ent->str_len;
- const u8 *buf = scratch->core_info.buf;
- const size_t buf_len = scratch->core_info.len;
-
- if (len > buf_len) {
- const struct RoseContext *tctxt = &scratch->tctxt;
- const u8 *hist = nocase ? tctxt->ll_buf_nocase : tctxt->ll_buf;
- size_t hist_len = nocase ? tctxt->ll_len_nocase : tctxt->ll_len;
-
- if (len > buf_len + hist_len) {
- return 0; // Break out - not enough total history
- }
-
- size_t overhang = len - buf_len;
- assert(overhang <= hist_len);
-
- if (cmpForward(hist + hist_len - overhang, s, overhang, nocase)) {
- return 0;
- }
- s += overhang;
- len -= overhang;
- }
-
- // if we got here, we don't need history or we compared ok out of history
- assert(len <= buf_len);
-
- if (cmpForward(buf + buf_len - len, s, len, nocase)) {
- return 0;
- }
-
- return 1;
-}
-
-static rose_inline
-const u8 *prepScanBuffer(const struct core_info *ci,
- const struct RoseLongLitTable *ll_table, u8 *tempbuf) {
- const u8 hash_len = ll_table->maxLen;
- assert(hash_len >= LONG_LIT_HASH_LEN);
-
- // Our hash function operates over LONG_LIT_HASH_LEN bytes, starting from
- // location (end of buffer - hash_len). If this block can be satisfied
- // entirely from either the current buffer or the history buffer, we pass
- // in the pointer directly; otherwise we must make a copy.
-
- const u8 *base;
-
- if (hash_len > ci->len) {
- size_t overhang = hash_len - ci->len;
- if (overhang >= LONG_LIT_HASH_LEN) {
- // Can read enough to hash from inside the history buffer.
- assert(overhang <= ci->hlen);
- base = ci->hbuf + ci->hlen - overhang;
- } else {
- // Copy: first chunk from history buffer.
- assert(overhang <= ci->hlen);
+#include "util/copybytes.h"
+
+static really_inline
+const struct RoseLongLitHashEntry *
+getHashTableBase(const struct RoseLongLitTable *ll_table,
+ const struct RoseLongLitSubtable *ll_sub) {
+ assert(ll_sub->hashOffset);
+ return (const struct RoseLongLitHashEntry *)((const char *)ll_table +
+ ll_sub->hashOffset);
+}
+
+// Reads from stream state and unpacks values into stream state table.
+static really_inline
+void loadLongLitStreamState(const struct RoseLongLitTable *ll_table,
+ const u8 *ll_state, u32 *state_case,
+ u32 *state_nocase) {
+ assert(ll_table);
+ assert(ll_state);
+ assert(state_case && state_nocase);
+
+ u8 ss_bytes = ll_table->streamStateBytes;
+ u8 ssb = ll_table->caseful.streamStateBits;
+ UNUSED u8 ssb_nc = ll_table->nocase.streamStateBits;
+ assert(ss_bytes == (ssb + ssb_nc + 7) / 8);
+
+#if defined(ARCH_32_BIT)
+ // On 32-bit hosts, we may be able to avoid having to do any u64a
+ // manipulation at all.
+ if (ss_bytes <= 4) {
+ u32 ssb_mask = (1U << ssb) - 1;
+ u32 streamVal = partial_load_u32(ll_state, ss_bytes);
+ *state_case = (u32)(streamVal & ssb_mask);
+ *state_nocase = (u32)(streamVal >> ssb);
+ return;
+ }
+#endif
+
+ u64a ssb_mask = (1ULL << ssb) - 1;
+ u64a streamVal = partial_load_u64a(ll_state, ss_bytes);
+ *state_case = (u32)(streamVal & ssb_mask);
+ *state_nocase = (u32)(streamVal >> ssb);
+}
+
+static rose_inline
+void loadLongLiteralStateMode(struct hs_scratch *scratch,
+ const struct RoseLongLitTable *ll_table,
+ const struct RoseLongLitSubtable *ll_sub,
+ const u32 state, const char nocase) {
+ if (!state) {
+ DEBUG_PRINTF("no state for %s\n", nocase ? "caseless" : "caseful");
+ return;
+ }
+
+ const struct RoseLongLitHashEntry *tab = getHashTableBase(ll_table, ll_sub);
+ const struct RoseLongLitHashEntry *ent = tab + state - 1;
+
+ assert(ent->str_offset + ent->str_len <= ll_table->size);
+ const u8 *found_buf = (const u8 *)ll_table + ent->str_offset;
+ size_t found_sz = ent->str_len;
+
+ struct RoseContext *tctxt = &scratch->tctxt;
+ if (nocase) {
+ tctxt->ll_buf_nocase = found_buf;
+ tctxt->ll_len_nocase = found_sz;
+ } else {
+ tctxt->ll_buf = found_buf;
+ tctxt->ll_len = found_sz;
+ }
+}
+
+static rose_inline
+void loadLongLiteralState(const struct RoseEngine *t, char *state,
+ struct hs_scratch *scratch) {
+ if (!t->longLitTableOffset) {
+ return;
+ }
+
+ // If we don't have any long literals in play, these values must point to
+ // the real history buffer so that CHECK_LONG_LIT instructions examine the
+ // history buffer.
+ scratch->tctxt.ll_buf = scratch->core_info.hbuf;
+ scratch->tctxt.ll_len = scratch->core_info.hlen;
+ scratch->tctxt.ll_buf_nocase = scratch->core_info.hbuf;
+ scratch->tctxt.ll_len_nocase = scratch->core_info.hlen;
+
+ if (!scratch->core_info.hlen) {
+ return;
+ }
+
+ const struct RoseLongLitTable *ll_table =
+ getByOffset(t, t->longLitTableOffset);
+ const u8 *ll_state = getLongLitState(t, state);
+
+ u32 state_case;
+ u32 state_nocase;
+ loadLongLitStreamState(ll_table, ll_state, &state_case, &state_nocase);
+
+ DEBUG_PRINTF("loaded {%u, %u}\n", state_case, state_nocase);
+
+ loadLongLiteralStateMode(scratch, ll_table, &ll_table->caseful,
+ state_case, 0);
+ loadLongLiteralStateMode(scratch, ll_table, &ll_table->nocase,
+ state_nocase, 1);
+}
+
+static rose_inline
+char confirmLongLiteral(const struct RoseLongLitTable *ll_table,
+ const struct hs_scratch *scratch,
+ const struct RoseLongLitHashEntry *ent,
+ const char nocase) {
+ assert(ent->str_offset + ent->str_len <= ll_table->size);
+ const u8 *s = (const u8 *)ll_table + ent->str_offset;
+ size_t len = ent->str_len;
+ const u8 *buf = scratch->core_info.buf;
+ const size_t buf_len = scratch->core_info.len;
+
+ if (len > buf_len) {
+ const struct RoseContext *tctxt = &scratch->tctxt;
+ const u8 *hist = nocase ? tctxt->ll_buf_nocase : tctxt->ll_buf;
+ size_t hist_len = nocase ? tctxt->ll_len_nocase : tctxt->ll_len;
+
+ if (len > buf_len + hist_len) {
+ return 0; // Break out - not enough total history
+ }
+
+ size_t overhang = len - buf_len;
+ assert(overhang <= hist_len);
+
+ if (cmpForward(hist + hist_len - overhang, s, overhang, nocase)) {
+ return 0;
+ }
+ s += overhang;
+ len -= overhang;
+ }
+
+ // if we got here, we don't need history or we compared ok out of history
+ assert(len <= buf_len);
+
+ if (cmpForward(buf + buf_len - len, s, len, nocase)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static rose_inline
+const u8 *prepScanBuffer(const struct core_info *ci,
+ const struct RoseLongLitTable *ll_table, u8 *tempbuf) {
+ const u8 hash_len = ll_table->maxLen;
+ assert(hash_len >= LONG_LIT_HASH_LEN);
+
+ // Our hash function operates over LONG_LIT_HASH_LEN bytes, starting from
+ // location (end of buffer - hash_len). If this block can be satisfied
+ // entirely from either the current buffer or the history buffer, we pass
+ // in the pointer directly; otherwise we must make a copy.
+
+ const u8 *base;
+
+ if (hash_len > ci->len) {
+ size_t overhang = hash_len - ci->len;
+ if (overhang >= LONG_LIT_HASH_LEN) {
+ // Can read enough to hash from inside the history buffer.
+ assert(overhang <= ci->hlen);
+ base = ci->hbuf + ci->hlen - overhang;
+ } else {
+ // Copy: first chunk from history buffer.
+ assert(overhang <= ci->hlen);
copy_upto_64_bytes(tempbuf, ci->hbuf + ci->hlen - overhang,
- overhang);
- // Copy: second chunk from current buffer.
- size_t copy_buf_len = LONG_LIT_HASH_LEN - overhang;
- assert(copy_buf_len <= ci->len);
+ overhang);
+ // Copy: second chunk from current buffer.
+ size_t copy_buf_len = LONG_LIT_HASH_LEN - overhang;
+ assert(copy_buf_len <= ci->len);
copy_upto_64_bytes(tempbuf + overhang, ci->buf, copy_buf_len);
- // Read from our temporary buffer for the hash.
- base = tempbuf;
- }
- } else {
- // Can read enough to hash from inside the current buffer.
- base = ci->buf + ci->len - hash_len;
- }
-
- return base;
-}
-
-#ifndef NDEBUG
-// Defensive checking (used in assert) that these table values don't overflow
-// the range available.
-static really_inline
-char streamingTableOverflow(u32 state_case, u32 state_nocase, u8 ssb,
- u8 ssb_nc) {
- u32 ssb_mask = (1ULL << (ssb)) - 1;
- if (state_case & ~ssb_mask) {
- return 1;
- }
- u32 ssb_nc_mask = (1ULL << (ssb_nc)) - 1;
- if (state_nocase & ~ssb_nc_mask) {
- return 1;
- }
- return 0;
-}
-#endif
-
-// Reads from stream state table and packs values into stream state.
-static rose_inline
-void storeLongLitStreamState(const struct RoseLongLitTable *ll_table,
- u8 *ll_state, u32 state_case, u32 state_nocase) {
- assert(ll_table);
- assert(ll_state);
-
- u8 ss_bytes = ll_table->streamStateBytes;
- u8 ssb = ll_table->caseful.streamStateBits;
- UNUSED u8 ssb_nc = ll_table->nocase.streamStateBits;
- assert(ss_bytes == ROUNDUP_N(ssb + ssb_nc, 8) / 8);
- assert(!streamingTableOverflow(state_case, state_nocase, ssb, ssb_nc));
-
-#if defined(ARCH_32_BIT)
- // On 32-bit hosts, we may be able to avoid having to do any u64a
- // manipulation at all.
- if (ss_bytes <= 4) {
- u32 stagingStreamState = state_case;
- stagingStreamState |= (state_nocase << ssb);
- partial_store_u32(ll_state, stagingStreamState, ss_bytes);
- return;
- }
-#endif
-
- u64a stagingStreamState = (u64a)state_case;
- stagingStreamState |= (u64a)state_nocase << ssb;
- partial_store_u64a(ll_state, stagingStreamState, ss_bytes);
-}
-
-static really_inline
-char has_bit(const u8 *data, u32 bit) {
- return (data[bit / 8] >> (bit % 8)) & 1;
-}
-
-static rose_inline
-char bloomHasKey(const u8 *bloom, u32 bloom_mask, u32 hash) {
- return has_bit(bloom, hash & bloom_mask);
-}
-
-static rose_inline
-char checkBloomFilter(const struct RoseLongLitTable *ll_table,
- const struct RoseLongLitSubtable *ll_sub,
- const u8 *scan_buf, char nocase) {
- assert(ll_sub->bloomBits);
-
- const u8 *bloom = (const u8 *)ll_table + ll_sub->bloomOffset;
- const u32 bloom_mask = (1U << ll_sub->bloomBits) - 1;
-
- char v = 1;
- v &= bloomHasKey(bloom, bloom_mask, bloomHash_1(scan_buf, nocase));
- v &= bloomHasKey(bloom, bloom_mask, bloomHash_2(scan_buf, nocase));
- v &= bloomHasKey(bloom, bloom_mask, bloomHash_3(scan_buf, nocase));
- return v;
-}
-
-/**
- * \brief Look for a hit in the hash table.
- *
- * Returns zero if not found, otherwise returns (bucket + 1).
- */
-static rose_inline
-u32 checkHashTable(const struct RoseLongLitTable *ll_table,
- const struct RoseLongLitSubtable *ll_sub, const u8 *scan_buf,
- const struct hs_scratch *scratch, char nocase) {
- const u32 nbits = ll_sub->hashBits;
- assert(nbits && nbits < 32);
- const u32 num_entries = 1U << nbits;
-
- const struct RoseLongLitHashEntry *tab = getHashTableBase(ll_table, ll_sub);
-
- u32 hash = hashLongLiteral(scan_buf, LONG_LIT_HASH_LEN, nocase);
- u32 bucket = hash & ((1U << nbits) - 1);
-
- while (tab[bucket].str_offset != 0) {
- DEBUG_PRINTF("checking bucket %u\n", bucket);
- if (confirmLongLiteral(ll_table, scratch, &tab[bucket], nocase)) {
- DEBUG_PRINTF("found hit for bucket %u\n", bucket);
- return bucket + 1;
- }
-
- if (++bucket == num_entries) {
- bucket = 0;
- }
- }
-
- return 0;
-}
-
-static rose_inline
-void storeLongLiteralState(const struct RoseEngine *t, char *state,
- struct hs_scratch *scratch) {
- if (!t->longLitTableOffset) {
- DEBUG_PRINTF("no table\n");
- return;
- }
-
- struct core_info *ci = &scratch->core_info;
- const struct RoseLongLitTable *ll_table =
- getByOffset(t, t->longLitTableOffset);
- assert(ll_table->maxLen);
-
- DEBUG_PRINTF("maxLen=%u, len=%zu, hlen=%zu\n", ll_table->maxLen, ci->len,
- ci->hlen);
-
- u32 state_case = 0;
- u32 state_nocase = 0;
-
- // If we don't have enough history, we don't need to do anything.
- if (ll_table->maxLen <= ci->len + ci->hlen) {
- u8 tempbuf[LONG_LIT_HASH_LEN];
- const u8 *scan_buf = prepScanBuffer(ci, ll_table, tempbuf);
-
- if (ll_table->caseful.hashBits &&
- checkBloomFilter(ll_table, &ll_table->caseful, scan_buf, 0)) {
- state_case = checkHashTable(ll_table, &ll_table->caseful, scan_buf,
- scratch, 0);
- }
-
- if (ll_table->nocase.hashBits &&
- checkBloomFilter(ll_table, &ll_table->nocase, scan_buf, 1)) {
- state_nocase = checkHashTable(ll_table, &ll_table->nocase, scan_buf,
- scratch, 1);
- }
- } else {
- DEBUG_PRINTF("not enough history (%zu bytes)\n", ci->len + ci->hlen);
- }
-
- DEBUG_PRINTF("store {%u, %u}\n", state_case, state_nocase);
-
- u8 *ll_state = getLongLitState(t, state);
- storeLongLitStreamState(ll_table, ll_state, state_case, state_nocase);
-}
-
-#endif // STREAM_LONG_LIT_H
+ // Read from our temporary buffer for the hash.
+ base = tempbuf;
+ }
+ } else {
+ // Can read enough to hash from inside the current buffer.
+ base = ci->buf + ci->len - hash_len;
+ }
+
+ return base;
+}
+
+#ifndef NDEBUG
+// Defensive checking (used in assert) that these table values don't overflow
+// the range available.
+static really_inline
+char streamingTableOverflow(u32 state_case, u32 state_nocase, u8 ssb,
+ u8 ssb_nc) {
+ u32 ssb_mask = (1ULL << (ssb)) - 1;
+ if (state_case & ~ssb_mask) {
+ return 1;
+ }
+ u32 ssb_nc_mask = (1ULL << (ssb_nc)) - 1;
+ if (state_nocase & ~ssb_nc_mask) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+// Reads from stream state table and packs values into stream state.
+static rose_inline
+void storeLongLitStreamState(const struct RoseLongLitTable *ll_table,
+ u8 *ll_state, u32 state_case, u32 state_nocase) {
+ assert(ll_table);
+ assert(ll_state);
+
+ u8 ss_bytes = ll_table->streamStateBytes;
+ u8 ssb = ll_table->caseful.streamStateBits;
+ UNUSED u8 ssb_nc = ll_table->nocase.streamStateBits;
+ assert(ss_bytes == ROUNDUP_N(ssb + ssb_nc, 8) / 8);
+ assert(!streamingTableOverflow(state_case, state_nocase, ssb, ssb_nc));
+
+#if defined(ARCH_32_BIT)
+ // On 32-bit hosts, we may be able to avoid having to do any u64a
+ // manipulation at all.
+ if (ss_bytes <= 4) {
+ u32 stagingStreamState = state_case;
+ stagingStreamState |= (state_nocase << ssb);
+ partial_store_u32(ll_state, stagingStreamState, ss_bytes);
+ return;
+ }
+#endif
+
+ u64a stagingStreamState = (u64a)state_case;
+ stagingStreamState |= (u64a)state_nocase << ssb;
+ partial_store_u64a(ll_state, stagingStreamState, ss_bytes);
+}
+
+static really_inline
+char has_bit(const u8 *data, u32 bit) {
+ return (data[bit / 8] >> (bit % 8)) & 1;
+}
+
+static rose_inline
+char bloomHasKey(const u8 *bloom, u32 bloom_mask, u32 hash) {
+ return has_bit(bloom, hash & bloom_mask);
+}
+
+static rose_inline
+char checkBloomFilter(const struct RoseLongLitTable *ll_table,
+ const struct RoseLongLitSubtable *ll_sub,
+ const u8 *scan_buf, char nocase) {
+ assert(ll_sub->bloomBits);
+
+ const u8 *bloom = (const u8 *)ll_table + ll_sub->bloomOffset;
+ const u32 bloom_mask = (1U << ll_sub->bloomBits) - 1;
+
+ char v = 1;
+ v &= bloomHasKey(bloom, bloom_mask, bloomHash_1(scan_buf, nocase));
+ v &= bloomHasKey(bloom, bloom_mask, bloomHash_2(scan_buf, nocase));
+ v &= bloomHasKey(bloom, bloom_mask, bloomHash_3(scan_buf, nocase));
+ return v;
+}
+
+/**
+ * \brief Look for a hit in the hash table.
+ *
+ * Returns zero if not found, otherwise returns (bucket + 1).
+ */
+static rose_inline
+u32 checkHashTable(const struct RoseLongLitTable *ll_table,
+ const struct RoseLongLitSubtable *ll_sub, const u8 *scan_buf,
+ const struct hs_scratch *scratch, char nocase) {
+ const u32 nbits = ll_sub->hashBits;
+ assert(nbits && nbits < 32);
+ const u32 num_entries = 1U << nbits;
+
+ const struct RoseLongLitHashEntry *tab = getHashTableBase(ll_table, ll_sub);
+
+ u32 hash = hashLongLiteral(scan_buf, LONG_LIT_HASH_LEN, nocase);
+ u32 bucket = hash & ((1U << nbits) - 1);
+
+ while (tab[bucket].str_offset != 0) {
+ DEBUG_PRINTF("checking bucket %u\n", bucket);
+ if (confirmLongLiteral(ll_table, scratch, &tab[bucket], nocase)) {
+ DEBUG_PRINTF("found hit for bucket %u\n", bucket);
+ return bucket + 1;
+ }
+
+ if (++bucket == num_entries) {
+ bucket = 0;
+ }
+ }
+
+ return 0;
+}
+
+static rose_inline
+void storeLongLiteralState(const struct RoseEngine *t, char *state,
+ struct hs_scratch *scratch) {
+ if (!t->longLitTableOffset) {
+ DEBUG_PRINTF("no table\n");
+ return;
+ }
+
+ struct core_info *ci = &scratch->core_info;
+ const struct RoseLongLitTable *ll_table =
+ getByOffset(t, t->longLitTableOffset);
+ assert(ll_table->maxLen);
+
+ DEBUG_PRINTF("maxLen=%u, len=%zu, hlen=%zu\n", ll_table->maxLen, ci->len,
+ ci->hlen);
+
+ u32 state_case = 0;
+ u32 state_nocase = 0;
+
+ // If we don't have enough history, we don't need to do anything.
+ if (ll_table->maxLen <= ci->len + ci->hlen) {
+ u8 tempbuf[LONG_LIT_HASH_LEN];
+ const u8 *scan_buf = prepScanBuffer(ci, ll_table, tempbuf);
+
+ if (ll_table->caseful.hashBits &&
+ checkBloomFilter(ll_table, &ll_table->caseful, scan_buf, 0)) {
+ state_case = checkHashTable(ll_table, &ll_table->caseful, scan_buf,
+ scratch, 0);
+ }
+
+ if (ll_table->nocase.hashBits &&
+ checkBloomFilter(ll_table, &ll_table->nocase, scan_buf, 1)) {
+ state_nocase = checkHashTable(ll_table, &ll_table->nocase, scan_buf,
+ scratch, 1);
+ }
+ } else {
+ DEBUG_PRINTF("not enough history (%zu bytes)\n", ci->len + ci->hlen);
+ }
+
+ DEBUG_PRINTF("store {%u, %u}\n", state_case, state_nocase);
+
+ u8 *ll_state = getLongLitState(t, state);
+ storeLongLitStreamState(ll_table, ll_state, state_case, state_nocase);
+}
+
+#endif // STREAM_LONG_LIT_H
diff --git a/contrib/libs/hyperscan/src/rose/stream_long_lit_hash.h b/contrib/libs/hyperscan/src/rose/stream_long_lit_hash.h
index ec476edfbe0..041f05e6098 100644
--- a/contrib/libs/hyperscan/src/rose/stream_long_lit_hash.h
+++ b/contrib/libs/hyperscan/src/rose/stream_long_lit_hash.h
@@ -1,105 +1,105 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef STREAM_LONG_LIT_HASH_H
-#define STREAM_LONG_LIT_HASH_H
-
-#include "ue2common.h"
-#include "util/bitutils.h"
-#include "util/unaligned.h"
-
-/** \brief Length of the buffer operated on by \ref hashLongLiteral(). */
-#define LONG_LIT_HASH_LEN 24
-
-/** \brief Multiplier used by al the hash functions below. */
-#define HASH_MULTIPLIER 0x0b4e0ef37bc32127ULL
-
-/** \brief Hash function used for long literal table in streaming mode. */
-static really_inline
-u32 hashLongLiteral(const u8 *ptr, UNUSED size_t len, char nocase) {
- // We unconditionally hash LONG_LIT_HASH_LEN bytes; all use cases of this
- // hash are for strings longer than this.
- assert(len >= 24);
-
- u64a v1 = unaligned_load_u64a(ptr);
- u64a v2 = unaligned_load_u64a(ptr + 8);
- u64a v3 = unaligned_load_u64a(ptr + 16);
- if (nocase) {
- v1 &= OCTO_CASE_CLEAR;
- v2 &= OCTO_CASE_CLEAR;
- v3 &= OCTO_CASE_CLEAR;
- }
- v1 *= HASH_MULTIPLIER;
- v2 *= HASH_MULTIPLIER * HASH_MULTIPLIER;
- v3 *= HASH_MULTIPLIER * HASH_MULTIPLIER * HASH_MULTIPLIER;
- v1 >>= 32;
- v2 >>= 32;
- v3 >>= 32;
- return v1 ^ v2 ^ v3;
-}
-
-/**
- * \brief Internal, used by the bloom filter hash functions below. Hashes 16
- * bytes beginning at (ptr + offset).
- */
-static really_inline
-u32 bloomHash_i(const u8 *ptr, u32 offset, u64a multiplier, char nocase) {
- assert(offset + 16 <= LONG_LIT_HASH_LEN);
-
- u64a v = unaligned_load_u64a(ptr + offset);
- if (nocase) {
- v &= OCTO_CASE_CLEAR;
- }
- v *= multiplier;
- return v >> 32;
-}
-
-/*
- * We ensure that we see every byte the first LONG_LIT_HASH_LEN bytes of input
- * data (using at least one of the following functions).
- */
-
-static really_inline
-u32 bloomHash_1(const u8 *ptr, char nocase) {
- const u64a multiplier = HASH_MULTIPLIER;
- return bloomHash_i(ptr, 0, multiplier, nocase);
-}
-
-static really_inline
-u32 bloomHash_2(const u8 *ptr, char nocase) {
- const u64a multiplier = HASH_MULTIPLIER * HASH_MULTIPLIER;
- return bloomHash_i(ptr, 4, multiplier, nocase);
-}
-
-static really_inline
-u32 bloomHash_3(const u8 *ptr, char nocase) {
- const u64a multiplier = HASH_MULTIPLIER * HASH_MULTIPLIER * HASH_MULTIPLIER;
- return bloomHash_i(ptr, 8, multiplier, nocase);
-}
-
-#endif // STREAM_LONG_LIT_HASH_H
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef STREAM_LONG_LIT_HASH_H
+#define STREAM_LONG_LIT_HASH_H
+
+#include "ue2common.h"
+#include "util/bitutils.h"
+#include "util/unaligned.h"
+
+/** \brief Length of the buffer operated on by \ref hashLongLiteral(). */
+#define LONG_LIT_HASH_LEN 24
+
+/** \brief Multiplier used by al the hash functions below. */
+#define HASH_MULTIPLIER 0x0b4e0ef37bc32127ULL
+
+/** \brief Hash function used for long literal table in streaming mode. */
+static really_inline
+u32 hashLongLiteral(const u8 *ptr, UNUSED size_t len, char nocase) {
+ // We unconditionally hash LONG_LIT_HASH_LEN bytes; all use cases of this
+ // hash are for strings longer than this.
+ assert(len >= 24);
+
+ u64a v1 = unaligned_load_u64a(ptr);
+ u64a v2 = unaligned_load_u64a(ptr + 8);
+ u64a v3 = unaligned_load_u64a(ptr + 16);
+ if (nocase) {
+ v1 &= OCTO_CASE_CLEAR;
+ v2 &= OCTO_CASE_CLEAR;
+ v3 &= OCTO_CASE_CLEAR;
+ }
+ v1 *= HASH_MULTIPLIER;
+ v2 *= HASH_MULTIPLIER * HASH_MULTIPLIER;
+ v3 *= HASH_MULTIPLIER * HASH_MULTIPLIER * HASH_MULTIPLIER;
+ v1 >>= 32;
+ v2 >>= 32;
+ v3 >>= 32;
+ return v1 ^ v2 ^ v3;
+}
+
+/**
+ * \brief Internal, used by the bloom filter hash functions below. Hashes 16
+ * bytes beginning at (ptr + offset).
+ */
+static really_inline
+u32 bloomHash_i(const u8 *ptr, u32 offset, u64a multiplier, char nocase) {
+ assert(offset + 16 <= LONG_LIT_HASH_LEN);
+
+ u64a v = unaligned_load_u64a(ptr + offset);
+ if (nocase) {
+ v &= OCTO_CASE_CLEAR;
+ }
+ v *= multiplier;
+ return v >> 32;
+}
+
+/*
+ * We ensure that we see every byte the first LONG_LIT_HASH_LEN bytes of input
+ * data (using at least one of the following functions).
+ */
+
+static really_inline
+u32 bloomHash_1(const u8 *ptr, char nocase) {
+ const u64a multiplier = HASH_MULTIPLIER;
+ return bloomHash_i(ptr, 0, multiplier, nocase);
+}
+
+static really_inline
+u32 bloomHash_2(const u8 *ptr, char nocase) {
+ const u64a multiplier = HASH_MULTIPLIER * HASH_MULTIPLIER;
+ return bloomHash_i(ptr, 4, multiplier, nocase);
+}
+
+static really_inline
+u32 bloomHash_3(const u8 *ptr, char nocase) {
+ const u64a multiplier = HASH_MULTIPLIER * HASH_MULTIPLIER * HASH_MULTIPLIER;
+ return bloomHash_i(ptr, 8, multiplier, nocase);
+}
+
+#endif // STREAM_LONG_LIT_HASH_H
diff --git a/contrib/libs/hyperscan/src/rose/validate_mask.h b/contrib/libs/hyperscan/src/rose/validate_mask.h
index 5f0a2735029..8191db52f8a 100644
--- a/contrib/libs/hyperscan/src/rose/validate_mask.h
+++ b/contrib/libs/hyperscan/src/rose/validate_mask.h
@@ -1,46 +1,46 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef VALIDATE_MASK_H
-#define VALIDATE_MASK_H
-
-#include "ue2common.h"
-#include "util/simd_utils.h"
-
-#if defined(DEBUG)
-static
-void validateMask32Print(const u8 *mask) {
- int i;
- for (i = 0; i < 32; i++) {
- printf("%02x", mask[i]);
- }
- printf("\n");
-}
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef VALIDATE_MASK_H
+#define VALIDATE_MASK_H
+
+#include "ue2common.h"
+#include "util/simd_utils.h"
+
+#if defined(DEBUG)
+static
+void validateMask32Print(const u8 *mask) {
+ int i;
+ for (i = 0; i < 32; i++) {
+ printf("%02x", mask[i]);
+ }
+ printf("\n");
+}
#ifdef HAVE_AVX512
static
@@ -51,81 +51,81 @@ void validateMask64Print(const u8 *mask) {
}
printf("\n");
}
-#endif
#endif
-
-// check positive bytes in cmp_result.
-// return one if the check passed, zero otherwise.
-static really_inline
-int posValidateMask(const u64a cmp_result, const u64a pos_mask) {
- return !(cmp_result & pos_mask);
-}
-
-/*
- * check negative bytes in cmp_result.
- * return one if any byte in cmp_result is not 0, zero otherwise.
- * check lowest 7 bits and highest bit of every byte respectively.
- */
-static really_inline
-int negValidateMask(const u64a cmp_result, const u64a neg_mask) {
- const u64a count_mask = 0x7f7f7f7f7f7f7f7f;
- // check lowest 7 bits of every byte.
- // the highest bit should be 1 if check passed.
- u64a check_low = (cmp_result & count_mask) + count_mask;
- // check the highest bit of every byte.
- // combine the highest bit and 0x7f to 0xff if check passes.
- // flip all 0xff to 0x00 and 0x7f to 0x80.
- u64a check_all = ~(check_low | cmp_result | count_mask);
- return !(check_all & neg_mask);
-}
-
-static really_inline
-int validateMask(u64a data, u64a valid_data_mask, u64a and_mask,
- u64a cmp_mask, u64a neg_mask) {
- // skip some byte where valid_data_mask is 0x00 there.
- and_mask &= valid_data_mask;
- cmp_mask &= valid_data_mask;
- neg_mask &= valid_data_mask;
- u64a cmp_result = (data & and_mask) ^ cmp_mask;
- /* do the positive check first since it's cheaper */
- if (posValidateMask(cmp_result, ~neg_mask)
- && negValidateMask(cmp_result, neg_mask)) {
- return 1;
- } else {
- DEBUG_PRINTF("data %llx valid_data_mask(vdm) %llx\n",
- data, valid_data_mask);
- DEBUG_PRINTF("and_mask & vdm %llx cmp_mask & vdm %llx\n", and_mask,
- cmp_mask);
- DEBUG_PRINTF("cmp_result %llx neg_mask & vdm %llx\n",
- cmp_result, neg_mask);
- return 0;
- }
-}
-
-static really_inline
-int validateMask32(const m256 data, const u32 valid_data_mask,
- const m256 and_mask, const m256 cmp_mask,
- const u32 neg_mask) {
- m256 cmp_result_256 = eq256(and256(data, and_mask), cmp_mask);
- u32 cmp_result = ~movemask256(cmp_result_256);
-#ifdef DEBUG
- DEBUG_PRINTF("data\n");
- validateMask32Print((const u8 *)&data);
- DEBUG_PRINTF("cmp_result\n");
- validateMask32Print((const u8 *)&cmp_result_256);
-#endif
- DEBUG_PRINTF("cmp_result %08x neg_mask %08x\n", cmp_result, neg_mask);
- DEBUG_PRINTF("valid_data_mask %08x\n", valid_data_mask);
-
- if ((cmp_result & valid_data_mask) == (neg_mask & valid_data_mask)) {
- DEBUG_PRINTF("checkCompareResult32 passed\n");
- return 1;
- } else {
- DEBUG_PRINTF("checkCompareResult32 failed\n");
- return 0;
- }
-}
-
+#endif
+
+// check positive bytes in cmp_result.
+// return one if the check passed, zero otherwise.
+static really_inline
+int posValidateMask(const u64a cmp_result, const u64a pos_mask) {
+ return !(cmp_result & pos_mask);
+}
+
+/*
+ * check negative bytes in cmp_result.
+ * return one if any byte in cmp_result is not 0, zero otherwise.
+ * check lowest 7 bits and highest bit of every byte respectively.
+ */
+static really_inline
+int negValidateMask(const u64a cmp_result, const u64a neg_mask) {
+ const u64a count_mask = 0x7f7f7f7f7f7f7f7f;
+ // check lowest 7 bits of every byte.
+ // the highest bit should be 1 if check passed.
+ u64a check_low = (cmp_result & count_mask) + count_mask;
+ // check the highest bit of every byte.
+ // combine the highest bit and 0x7f to 0xff if check passes.
+ // flip all 0xff to 0x00 and 0x7f to 0x80.
+ u64a check_all = ~(check_low | cmp_result | count_mask);
+ return !(check_all & neg_mask);
+}
+
+static really_inline
+int validateMask(u64a data, u64a valid_data_mask, u64a and_mask,
+ u64a cmp_mask, u64a neg_mask) {
+ // skip some byte where valid_data_mask is 0x00 there.
+ and_mask &= valid_data_mask;
+ cmp_mask &= valid_data_mask;
+ neg_mask &= valid_data_mask;
+ u64a cmp_result = (data & and_mask) ^ cmp_mask;
+ /* do the positive check first since it's cheaper */
+ if (posValidateMask(cmp_result, ~neg_mask)
+ && negValidateMask(cmp_result, neg_mask)) {
+ return 1;
+ } else {
+ DEBUG_PRINTF("data %llx valid_data_mask(vdm) %llx\n",
+ data, valid_data_mask);
+ DEBUG_PRINTF("and_mask & vdm %llx cmp_mask & vdm %llx\n", and_mask,
+ cmp_mask);
+ DEBUG_PRINTF("cmp_result %llx neg_mask & vdm %llx\n",
+ cmp_result, neg_mask);
+ return 0;
+ }
+}
+
+static really_inline
+int validateMask32(const m256 data, const u32 valid_data_mask,
+ const m256 and_mask, const m256 cmp_mask,
+ const u32 neg_mask) {
+ m256 cmp_result_256 = eq256(and256(data, and_mask), cmp_mask);
+ u32 cmp_result = ~movemask256(cmp_result_256);
+#ifdef DEBUG
+ DEBUG_PRINTF("data\n");
+ validateMask32Print((const u8 *)&data);
+ DEBUG_PRINTF("cmp_result\n");
+ validateMask32Print((const u8 *)&cmp_result_256);
+#endif
+ DEBUG_PRINTF("cmp_result %08x neg_mask %08x\n", cmp_result, neg_mask);
+ DEBUG_PRINTF("valid_data_mask %08x\n", valid_data_mask);
+
+ if ((cmp_result & valid_data_mask) == (neg_mask & valid_data_mask)) {
+ DEBUG_PRINTF("checkCompareResult32 passed\n");
+ return 1;
+ } else {
+ DEBUG_PRINTF("checkCompareResult32 failed\n");
+ return 0;
+ }
+}
+
#ifdef HAVE_AVX512
static really_inline
int validateMask64(const m512 data, const u64a valid_data_mask,
@@ -137,7 +137,7 @@ int validateMask64(const m512 data, const u64a valid_data_mask,
validateMask64Print((const u8 *)&data);
DEBUG_PRINTF("cmp_result\n");
validateMask64Print((const u8 *)&cmp_result);
-#endif
+#endif
DEBUG_PRINTF("cmp_result %016llx neg_mask %016llx\n", cmp_result, neg_mask);
DEBUG_PRINTF("valid_data_mask %016llx\n", valid_data_mask);
diff --git a/contrib/libs/hyperscan/src/rose/validate_shufti.h b/contrib/libs/hyperscan/src/rose/validate_shufti.h
index f936140b117..351df36a766 100644
--- a/contrib/libs/hyperscan/src/rose/validate_shufti.h
+++ b/contrib/libs/hyperscan/src/rose/validate_shufti.h
@@ -1,182 +1,182 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef VALIDATE_SHUFTI_H
-#define VALIDATE_SHUFTI_H
-
-#include "ue2common.h"
-#include "util/simd_utils.h"
-
-#if defined(DEBUG)
-static
-void dumpMask(const void *mask, int len) {
- const u8 *c = (const u8 *)mask;
- for (int i = 0; i < len; i++) {
- printf("%02x", c[i]);
- }
- printf("\n");
-}
-#endif
-
-static really_inline
-int validateShuftiMask16x16(const m256 data, const m256 hi_mask,
- const m256 lo_mask, const m256 and_mask,
- const u32 neg_mask, const u32 valid_data_mask) {
- m256 low4bits = set32x8(0xf);
- m256 c_lo = pshufb_m256(lo_mask, and256(data, low4bits));
- m256 c_hi = pshufb_m256(hi_mask,
- rshift64_m256(andnot256(low4bits, data), 4));
- m256 t = and256(c_lo, c_hi);
- u32 nresult = movemask256(eq256(and256(t, and_mask), zeroes256()));
-#ifdef DEBUG
- DEBUG_PRINTF("data\n");
- dumpMask(&data, 32);
- DEBUG_PRINTF("hi_mask\n");
- dumpMask(&hi_mask, 32);
- DEBUG_PRINTF("lo_mask\n");
- dumpMask(&lo_mask, 32);
- DEBUG_PRINTF("c_lo\n");
- dumpMask(&c_lo, 32);
- DEBUG_PRINTF("c_hi\n");
- dumpMask(&c_hi, 32);
- DEBUG_PRINTF("and_mask\n");
- dumpMask(&and_mask, 32);
- DEBUG_PRINTF("nresult %x\n", nresult);
- DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
-#endif
- u32 cmp_result = (((nresult >> 16) & nresult) ^ neg_mask) & valid_data_mask;
- return !cmp_result;
-}
-
-static really_inline
-int validateShuftiMask16x8(const m128 data, const m256 nib_mask,
- const m128 and_mask, const u32 neg_mask,
- const u32 valid_data_mask) {
- m256 data_m256 = combine2x128(rshift64_m128(data, 4), data);
- m256 low4bits = set32x8(0xf);
- m256 c_nib = pshufb_m256(nib_mask, and256(data_m256, low4bits));
- m128 t = and128(movdq_hi(c_nib), movdq_lo(c_nib));
- m128 nresult = eq128(and128(t, and_mask), zeroes128());
-#ifdef DEBUG
- DEBUG_PRINTF("data\n");
- dumpMask(&data_m256, 32);
- DEBUG_PRINTF("nib_mask\n");
- dumpMask(&nib_mask, 32);
- DEBUG_PRINTF("c_nib\n");
- dumpMask(&c_nib, 32);
- DEBUG_PRINTF("nresult\n");
- dumpMask(&nresult, 16);
- DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
-#endif
- u32 cmp_result = (movemask128(nresult) ^ neg_mask) & valid_data_mask;
- return !cmp_result;
-}
-
-static really_inline
-int validateShuftiMask32x8(const m256 data, const m256 hi_mask,
- const m256 lo_mask, const m256 and_mask,
- const u32 neg_mask, const u32 valid_data_mask) {
- m256 low4bits = set32x8(0xf);
- m256 c_lo = pshufb_m256(lo_mask, and256(data, low4bits));
- m256 c_hi = pshufb_m256(hi_mask,
- rshift64_m256(andnot256(low4bits, data), 4));
- m256 t = and256(c_lo, c_hi);
- m256 nresult = eq256(and256(t, and_mask), zeroes256());
-#ifdef DEBUG
- DEBUG_PRINTF("data\n");
- dumpMask(&data, 32);
- DEBUG_PRINTF("hi_mask\n");
- dumpMask(&hi_mask, 32);
- DEBUG_PRINTF("lo_mask\n");
- dumpMask(&lo_mask, 32);
- DEBUG_PRINTF("c_lo\n");
- dumpMask(&c_lo, 32);
- DEBUG_PRINTF("c_hi\n");
- dumpMask(&c_hi, 32);
- DEBUG_PRINTF("nresult\n");
- dumpMask(&nresult, 32);
- DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
-#endif
- u32 cmp_result = (movemask256(nresult) ^ neg_mask) & valid_data_mask;
- return !cmp_result;
-}
-
-static really_inline
-int validateShuftiMask32x16(const m256 data,
- const m256 hi_mask_1, const m256 hi_mask_2,
- const m256 lo_mask_1, const m256 lo_mask_2,
- const m256 bucket_mask_hi,
- const m256 bucket_mask_lo, const u32 neg_mask,
- const u32 valid_data_mask) {
- m256 low4bits = set32x8(0xf);
- m256 data_lo = and256(data, low4bits);
- m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
- m256 c_lo_1 = pshufb_m256(lo_mask_1, data_lo);
- m256 c_lo_2 = pshufb_m256(lo_mask_2, data_lo);
- m256 c_hi_1 = pshufb_m256(hi_mask_1, data_hi);
- m256 c_hi_2 = pshufb_m256(hi_mask_2, data_hi);
- m256 t1 = and256(c_lo_1, c_hi_1);
- m256 t2 = and256(c_lo_2, c_hi_2);
- m256 result = or256(and256(t1, bucket_mask_lo), and256(t2, bucket_mask_hi));
- u32 nresult = movemask256(eq256(result, zeroes256()));
-#ifdef DEBUG
- DEBUG_PRINTF("data\n");
- dumpMask(&data, 32);
- DEBUG_PRINTF("data_lo\n");
- dumpMask(&data_lo, 32);
- DEBUG_PRINTF("data_hi\n");
- dumpMask(&data_hi, 32);
- DEBUG_PRINTF("hi_mask_1\n");
- dumpMask(&hi_mask_1, 16);
- DEBUG_PRINTF("hi_mask_2\n");
- dumpMask(&hi_mask_2, 16);
- DEBUG_PRINTF("lo_mask_1\n");
- dumpMask(&lo_mask_1, 16);
- DEBUG_PRINTF("lo_mask_2\n");
- dumpMask(&lo_mask_2, 16);
- DEBUG_PRINTF("c_lo_1\n");
- dumpMask(&c_lo_1, 32);
- DEBUG_PRINTF("c_lo_2\n");
- dumpMask(&c_lo_2, 32);
- DEBUG_PRINTF("c_hi_1\n");
- dumpMask(&c_hi_1, 32);
- DEBUG_PRINTF("c_hi_2\n");
- dumpMask(&c_hi_2, 32);
- DEBUG_PRINTF("result\n");
- dumpMask(&result, 32);
- DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
-#endif
- u32 cmp_result = (nresult ^ neg_mask) & valid_data_mask;
- return !cmp_result;
-}
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef VALIDATE_SHUFTI_H
+#define VALIDATE_SHUFTI_H
+
+#include "ue2common.h"
+#include "util/simd_utils.h"
+
+#if defined(DEBUG)
+static
+void dumpMask(const void *mask, int len) {
+ const u8 *c = (const u8 *)mask;
+ for (int i = 0; i < len; i++) {
+ printf("%02x", c[i]);
+ }
+ printf("\n");
+}
+#endif
+
+static really_inline
+int validateShuftiMask16x16(const m256 data, const m256 hi_mask,
+ const m256 lo_mask, const m256 and_mask,
+ const u32 neg_mask, const u32 valid_data_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 c_lo = pshufb_m256(lo_mask, and256(data, low4bits));
+ m256 c_hi = pshufb_m256(hi_mask,
+ rshift64_m256(andnot256(low4bits, data), 4));
+ m256 t = and256(c_lo, c_hi);
+ u32 nresult = movemask256(eq256(and256(t, and_mask), zeroes256()));
+#ifdef DEBUG
+ DEBUG_PRINTF("data\n");
+ dumpMask(&data, 32);
+ DEBUG_PRINTF("hi_mask\n");
+ dumpMask(&hi_mask, 32);
+ DEBUG_PRINTF("lo_mask\n");
+ dumpMask(&lo_mask, 32);
+ DEBUG_PRINTF("c_lo\n");
+ dumpMask(&c_lo, 32);
+ DEBUG_PRINTF("c_hi\n");
+ dumpMask(&c_hi, 32);
+ DEBUG_PRINTF("and_mask\n");
+ dumpMask(&and_mask, 32);
+ DEBUG_PRINTF("nresult %x\n", nresult);
+ DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
+#endif
+ u32 cmp_result = (((nresult >> 16) & nresult) ^ neg_mask) & valid_data_mask;
+ return !cmp_result;
+}
+
+static really_inline
+int validateShuftiMask16x8(const m128 data, const m256 nib_mask,
+ const m128 and_mask, const u32 neg_mask,
+ const u32 valid_data_mask) {
+ m256 data_m256 = combine2x128(rshift64_m128(data, 4), data);
+ m256 low4bits = set32x8(0xf);
+ m256 c_nib = pshufb_m256(nib_mask, and256(data_m256, low4bits));
+ m128 t = and128(movdq_hi(c_nib), movdq_lo(c_nib));
+ m128 nresult = eq128(and128(t, and_mask), zeroes128());
+#ifdef DEBUG
+ DEBUG_PRINTF("data\n");
+ dumpMask(&data_m256, 32);
+ DEBUG_PRINTF("nib_mask\n");
+ dumpMask(&nib_mask, 32);
+ DEBUG_PRINTF("c_nib\n");
+ dumpMask(&c_nib, 32);
+ DEBUG_PRINTF("nresult\n");
+ dumpMask(&nresult, 16);
+ DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
+#endif
+ u32 cmp_result = (movemask128(nresult) ^ neg_mask) & valid_data_mask;
+ return !cmp_result;
+}
+
+static really_inline
+int validateShuftiMask32x8(const m256 data, const m256 hi_mask,
+ const m256 lo_mask, const m256 and_mask,
+ const u32 neg_mask, const u32 valid_data_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 c_lo = pshufb_m256(lo_mask, and256(data, low4bits));
+ m256 c_hi = pshufb_m256(hi_mask,
+ rshift64_m256(andnot256(low4bits, data), 4));
+ m256 t = and256(c_lo, c_hi);
+ m256 nresult = eq256(and256(t, and_mask), zeroes256());
+#ifdef DEBUG
+ DEBUG_PRINTF("data\n");
+ dumpMask(&data, 32);
+ DEBUG_PRINTF("hi_mask\n");
+ dumpMask(&hi_mask, 32);
+ DEBUG_PRINTF("lo_mask\n");
+ dumpMask(&lo_mask, 32);
+ DEBUG_PRINTF("c_lo\n");
+ dumpMask(&c_lo, 32);
+ DEBUG_PRINTF("c_hi\n");
+ dumpMask(&c_hi, 32);
+ DEBUG_PRINTF("nresult\n");
+ dumpMask(&nresult, 32);
+ DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
+#endif
+ u32 cmp_result = (movemask256(nresult) ^ neg_mask) & valid_data_mask;
+ return !cmp_result;
+}
+
+static really_inline
+int validateShuftiMask32x16(const m256 data,
+ const m256 hi_mask_1, const m256 hi_mask_2,
+ const m256 lo_mask_1, const m256 lo_mask_2,
+ const m256 bucket_mask_hi,
+ const m256 bucket_mask_lo, const u32 neg_mask,
+ const u32 valid_data_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 data_lo = and256(data, low4bits);
+ m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
+ m256 c_lo_1 = pshufb_m256(lo_mask_1, data_lo);
+ m256 c_lo_2 = pshufb_m256(lo_mask_2, data_lo);
+ m256 c_hi_1 = pshufb_m256(hi_mask_1, data_hi);
+ m256 c_hi_2 = pshufb_m256(hi_mask_2, data_hi);
+ m256 t1 = and256(c_lo_1, c_hi_1);
+ m256 t2 = and256(c_lo_2, c_hi_2);
+ m256 result = or256(and256(t1, bucket_mask_lo), and256(t2, bucket_mask_hi));
+ u32 nresult = movemask256(eq256(result, zeroes256()));
+#ifdef DEBUG
+ DEBUG_PRINTF("data\n");
+ dumpMask(&data, 32);
+ DEBUG_PRINTF("data_lo\n");
+ dumpMask(&data_lo, 32);
+ DEBUG_PRINTF("data_hi\n");
+ dumpMask(&data_hi, 32);
+ DEBUG_PRINTF("hi_mask_1\n");
+ dumpMask(&hi_mask_1, 16);
+ DEBUG_PRINTF("hi_mask_2\n");
+ dumpMask(&hi_mask_2, 16);
+ DEBUG_PRINTF("lo_mask_1\n");
+ dumpMask(&lo_mask_1, 16);
+ DEBUG_PRINTF("lo_mask_2\n");
+ dumpMask(&lo_mask_2, 16);
+ DEBUG_PRINTF("c_lo_1\n");
+ dumpMask(&c_lo_1, 32);
+ DEBUG_PRINTF("c_lo_2\n");
+ dumpMask(&c_lo_2, 32);
+ DEBUG_PRINTF("c_hi_1\n");
+ dumpMask(&c_hi_1, 32);
+ DEBUG_PRINTF("c_hi_2\n");
+ dumpMask(&c_hi_2, 32);
+ DEBUG_PRINTF("result\n");
+ dumpMask(&result, 32);
+ DEBUG_PRINTF("valid_data_mask %x\n", valid_data_mask);
+#endif
+ u32 cmp_result = (nresult ^ neg_mask) & valid_data_mask;
+ return !cmp_result;
+}
+
#ifdef HAVE_AVX512
-static really_inline
+static really_inline
int validateShuftiMask64x8(const m512 data, const m512 hi_mask,
const m512 lo_mask, const m512 and_mask,
const u64a neg_mask, const u64a valid_data_mask) {
@@ -254,119 +254,119 @@ int validateShuftiMask64x16(const m512 data,
#endif
static really_inline
-int checkMultipath32(u32 data, u32 hi_bits, u32 lo_bits) {
- u32 t = ~(data | hi_bits);
- t += lo_bits;
- t &= (~data) & hi_bits;
- DEBUG_PRINTF("t %x\n", t);
- return !!t;
-}
-
-static really_inline
-int checkMultipath64(u64a data, u64a hi_bits, u64a lo_bits) {
- u64a t = ~(data | hi_bits);
- t += lo_bits;
- t &= (~data) & hi_bits;
- DEBUG_PRINTF("t %llx\n", t);
- return !!t;
-}
-
-static really_inline
-int validateMultipathShuftiMask16x8(const m128 data,
- const m256 nib_mask,
- const m128 bucket_select_mask,
- const u32 hi_bits, const u32 lo_bits,
- const u32 neg_mask,
- const u32 valid_path_mask) {
- m256 data_256 = combine2x128(rshift64_m128(data, 4), data);
- m256 low4bits = set32x8(0xf);
- m256 c_nib = pshufb_m256(nib_mask, and256(data_256, low4bits));
- m128 t = and128(movdq_hi(c_nib), movdq_lo(c_nib));
- m128 result = and128(t, bucket_select_mask);
- u32 nresult = movemask128(eq128(result, zeroes128()));
- u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
-
- DEBUG_PRINTF("cmp_result %x\n", cmp_result);
-
- return checkMultipath32(cmp_result, hi_bits, lo_bits);
-}
-
-static really_inline
-int validateMultipathShuftiMask32x8(const m256 data,
- const m256 hi_mask, const m256 lo_mask,
- const m256 bucket_select_mask,
- const u32 hi_bits, const u32 lo_bits,
- const u32 neg_mask,
- const u32 valid_path_mask) {
- m256 low4bits = set32x8(0xf);
- m256 data_lo = and256(data, low4bits);
- m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
- m256 c_lo = pshufb_m256(lo_mask, data_lo);
- m256 c_hi = pshufb_m256(hi_mask, data_hi);
- m256 c = and256(c_lo, c_hi);
- m256 result = and256(c, bucket_select_mask);
- u32 nresult = movemask256(eq256(result, zeroes256()));
- u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
-
- DEBUG_PRINTF("cmp_result %x\n", cmp_result);
-
- return checkMultipath32(cmp_result, hi_bits, lo_bits);
-}
-
-static really_inline
-int validateMultipathShuftiMask32x16(const m256 data,
- const m256 hi_mask_1, const m256 hi_mask_2,
- const m256 lo_mask_1, const m256 lo_mask_2,
- const m256 bucket_select_mask_hi,
- const m256 bucket_select_mask_lo,
- const u32 hi_bits, const u32 lo_bits,
- const u32 neg_mask,
- const u32 valid_path_mask) {
- m256 low4bits = set32x8(0xf);
- m256 data_lo = and256(data, low4bits);
- m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
- m256 c_lo_1 = pshufb_m256(lo_mask_1, data_lo);
- m256 c_lo_2 = pshufb_m256(lo_mask_2, data_lo);
- m256 c_hi_1 = pshufb_m256(hi_mask_1, data_hi);
- m256 c_hi_2 = pshufb_m256(hi_mask_2, data_hi);
- m256 t1 = and256(c_lo_1, c_hi_1);
- m256 t2 = and256(c_lo_2, c_hi_2);
- m256 result = or256(and256(t1, bucket_select_mask_lo),
- and256(t2, bucket_select_mask_hi));
- u32 nresult = movemask256(eq256(result, zeroes256()));
- u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
-
- DEBUG_PRINTF("cmp_result %x\n", cmp_result);
-
- return checkMultipath32(cmp_result, hi_bits, lo_bits);
-}
-
-static really_inline
-int validateMultipathShuftiMask64(const m256 data_1, const m256 data_2,
- const m256 hi_mask, const m256 lo_mask,
- const m256 bucket_select_mask_1,
- const m256 bucket_select_mask_2,
- const u64a hi_bits, const u64a lo_bits,
- const u64a neg_mask,
- const u64a valid_path_mask) {
- m256 low4bits = set32x8(0xf);
- m256 c_lo_1 = pshufb_m256(lo_mask, and256(data_1, low4bits));
- m256 c_lo_2 = pshufb_m256(lo_mask, and256(data_2, low4bits));
- m256 c_hi_1 = pshufb_m256(hi_mask,
- rshift64_m256(andnot256(low4bits, data_1), 4));
- m256 c_hi_2 = pshufb_m256(hi_mask,
- rshift64_m256(andnot256(low4bits, data_2), 4));
- m256 t1 = and256(c_lo_1, c_hi_1);
- m256 t2 = and256(c_lo_2, c_hi_2);
- m256 nresult_1 = eq256(and256(t1, bucket_select_mask_1), zeroes256());
- m256 nresult_2 = eq256(and256(t2, bucket_select_mask_2), zeroes256());
- u64a nresult = (u64a)movemask256(nresult_1) |
- (u64a)movemask256(nresult_2) << 32;
- u64a cmp_result = (nresult ^ neg_mask) | valid_path_mask;
-
- DEBUG_PRINTF("cmp_result %llx\n", cmp_result);
-
- return checkMultipath64(cmp_result, hi_bits, lo_bits);
-}
-
-#endif
+int checkMultipath32(u32 data, u32 hi_bits, u32 lo_bits) {
+ u32 t = ~(data | hi_bits);
+ t += lo_bits;
+ t &= (~data) & hi_bits;
+ DEBUG_PRINTF("t %x\n", t);
+ return !!t;
+}
+
+static really_inline
+int checkMultipath64(u64a data, u64a hi_bits, u64a lo_bits) {
+ u64a t = ~(data | hi_bits);
+ t += lo_bits;
+ t &= (~data) & hi_bits;
+ DEBUG_PRINTF("t %llx\n", t);
+ return !!t;
+}
+
+static really_inline
+int validateMultipathShuftiMask16x8(const m128 data,
+ const m256 nib_mask,
+ const m128 bucket_select_mask,
+ const u32 hi_bits, const u32 lo_bits,
+ const u32 neg_mask,
+ const u32 valid_path_mask) {
+ m256 data_256 = combine2x128(rshift64_m128(data, 4), data);
+ m256 low4bits = set32x8(0xf);
+ m256 c_nib = pshufb_m256(nib_mask, and256(data_256, low4bits));
+ m128 t = and128(movdq_hi(c_nib), movdq_lo(c_nib));
+ m128 result = and128(t, bucket_select_mask);
+ u32 nresult = movemask128(eq128(result, zeroes128()));
+ u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
+
+ DEBUG_PRINTF("cmp_result %x\n", cmp_result);
+
+ return checkMultipath32(cmp_result, hi_bits, lo_bits);
+}
+
+static really_inline
+int validateMultipathShuftiMask32x8(const m256 data,
+ const m256 hi_mask, const m256 lo_mask,
+ const m256 bucket_select_mask,
+ const u32 hi_bits, const u32 lo_bits,
+ const u32 neg_mask,
+ const u32 valid_path_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 data_lo = and256(data, low4bits);
+ m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
+ m256 c_lo = pshufb_m256(lo_mask, data_lo);
+ m256 c_hi = pshufb_m256(hi_mask, data_hi);
+ m256 c = and256(c_lo, c_hi);
+ m256 result = and256(c, bucket_select_mask);
+ u32 nresult = movemask256(eq256(result, zeroes256()));
+ u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
+
+ DEBUG_PRINTF("cmp_result %x\n", cmp_result);
+
+ return checkMultipath32(cmp_result, hi_bits, lo_bits);
+}
+
+static really_inline
+int validateMultipathShuftiMask32x16(const m256 data,
+ const m256 hi_mask_1, const m256 hi_mask_2,
+ const m256 lo_mask_1, const m256 lo_mask_2,
+ const m256 bucket_select_mask_hi,
+ const m256 bucket_select_mask_lo,
+ const u32 hi_bits, const u32 lo_bits,
+ const u32 neg_mask,
+ const u32 valid_path_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 data_lo = and256(data, low4bits);
+ m256 data_hi = and256(rshift64_m256(data, 4), low4bits);
+ m256 c_lo_1 = pshufb_m256(lo_mask_1, data_lo);
+ m256 c_lo_2 = pshufb_m256(lo_mask_2, data_lo);
+ m256 c_hi_1 = pshufb_m256(hi_mask_1, data_hi);
+ m256 c_hi_2 = pshufb_m256(hi_mask_2, data_hi);
+ m256 t1 = and256(c_lo_1, c_hi_1);
+ m256 t2 = and256(c_lo_2, c_hi_2);
+ m256 result = or256(and256(t1, bucket_select_mask_lo),
+ and256(t2, bucket_select_mask_hi));
+ u32 nresult = movemask256(eq256(result, zeroes256()));
+ u32 cmp_result = (nresult ^ neg_mask) | valid_path_mask;
+
+ DEBUG_PRINTF("cmp_result %x\n", cmp_result);
+
+ return checkMultipath32(cmp_result, hi_bits, lo_bits);
+}
+
+static really_inline
+int validateMultipathShuftiMask64(const m256 data_1, const m256 data_2,
+ const m256 hi_mask, const m256 lo_mask,
+ const m256 bucket_select_mask_1,
+ const m256 bucket_select_mask_2,
+ const u64a hi_bits, const u64a lo_bits,
+ const u64a neg_mask,
+ const u64a valid_path_mask) {
+ m256 low4bits = set32x8(0xf);
+ m256 c_lo_1 = pshufb_m256(lo_mask, and256(data_1, low4bits));
+ m256 c_lo_2 = pshufb_m256(lo_mask, and256(data_2, low4bits));
+ m256 c_hi_1 = pshufb_m256(hi_mask,
+ rshift64_m256(andnot256(low4bits, data_1), 4));
+ m256 c_hi_2 = pshufb_m256(hi_mask,
+ rshift64_m256(andnot256(low4bits, data_2), 4));
+ m256 t1 = and256(c_lo_1, c_hi_1);
+ m256 t2 = and256(c_lo_2, c_hi_2);
+ m256 nresult_1 = eq256(and256(t1, bucket_select_mask_1), zeroes256());
+ m256 nresult_2 = eq256(and256(t2, bucket_select_mask_2), zeroes256());
+ u64a nresult = (u64a)movemask256(nresult_1) |
+ (u64a)movemask256(nresult_2) << 32;
+ u64a cmp_result = (nresult ^ neg_mask) | valid_path_mask;
+
+ DEBUG_PRINTF("cmp_result %llx\n", cmp_result);
+
+ return checkMultipath64(cmp_result, hi_bits, lo_bits);
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/runtime.c b/contrib/libs/hyperscan/src/runtime.c
index 9d0492173a2..a3659348c52 100644
--- a/contrib/libs/hyperscan/src/runtime.c
+++ b/contrib/libs/hyperscan/src/runtime.c
@@ -43,17 +43,17 @@
#include "nfa/nfa_api_util.h"
#include "nfa/nfa_internal.h"
#include "nfa/nfa_rev_api.h"
-#include "nfa/sheng.h"
+#include "nfa/sheng.h"
#include "smallwrite/smallwrite_internal.h"
#include "rose/rose.h"
#include "rose/runtime.h"
#include "database.h"
-#include "report.h"
+#include "report.h"
#include "scratch.h"
#include "som/som_runtime.h"
#include "som/som_stream.h"
#include "state.h"
-#include "stream_compress.h"
+#include "stream_compress.h"
#include "ue2common.h"
#include "util/exhaust.h"
#include "util/multibit.h"
@@ -120,8 +120,8 @@ static really_inline
void populateCoreInfo(struct hs_scratch *s, const struct RoseEngine *rose,
char *state, match_event_handler onEvent, void *userCtx,
const char *data, size_t length, const u8 *history,
- size_t hlen, u64a offset, u8 status,
- UNUSED unsigned int flags) {
+ size_t hlen, u64a offset, u8 status,
+ UNUSED unsigned int flags) {
assert(rose);
s->core_info.userContext = userCtx;
s->core_info.userCallback = onEvent ? onEvent : null_onEvent;
@@ -129,7 +129,7 @@ void populateCoreInfo(struct hs_scratch *s, const struct RoseEngine *rose,
s->core_info.state = state; /* required for chained queues + evec */
s->core_info.exhaustionVector = state + rose->stateOffsets.exhausted;
- s->core_info.status = status;
+ s->core_info.status = status;
s->core_info.buf = (const u8 *)data;
s->core_info.len = length;
s->core_info.hbuf = history;
@@ -140,40 +140,40 @@ void populateCoreInfo(struct hs_scratch *s, const struct RoseEngine *rose,
s->som_set_now_offset = ~0ULL;
s->deduper.current_report_offset = ~0ULL;
s->deduper.som_log_dirty = 1; /* som logs have not been cleared */
- s->fdr_conf = NULL;
+ s->fdr_conf = NULL;
- // Rose program execution (used for some report paths) depends on these
- // values being initialised.
- s->tctxt.lastMatchOffset = 0;
- s->tctxt.minMatchOffset = offset;
- s->tctxt.minNonMpvMatchOffset = offset;
+ // Rose program execution (used for some report paths) depends on these
+ // values being initialised.
+ s->tctxt.lastMatchOffset = 0;
+ s->tctxt.minMatchOffset = offset;
+ s->tctxt.minNonMpvMatchOffset = offset;
}
-#define STATUS_VALID_BITS \
+#define STATUS_VALID_BITS \
(STATUS_TERMINATED | STATUS_EXHAUSTED | STATUS_DELAY_DIRTY | STATUS_ERROR)
-/** \brief Retrieve status bitmask from stream state. */
+/** \brief Retrieve status bitmask from stream state. */
static really_inline
-u8 getStreamStatus(const char *state) {
- u8 status = *(const u8 *)(state + ROSE_STATE_OFFSET_STATUS_FLAGS);
- assert((status & ~STATUS_VALID_BITS) == 0);
- return status;
+u8 getStreamStatus(const char *state) {
+ u8 status = *(const u8 *)(state + ROSE_STATE_OFFSET_STATUS_FLAGS);
+ assert((status & ~STATUS_VALID_BITS) == 0);
+ return status;
}
-/** \brief Store status bitmask to stream state. */
+/** \brief Store status bitmask to stream state. */
static really_inline
-void setStreamStatus(char *state, u8 status) {
- assert((status & ~STATUS_VALID_BITS) == 0);
- *(u8 *)(state + ROSE_STATE_OFFSET_STATUS_FLAGS) = status;
+void setStreamStatus(char *state, u8 status) {
+ assert((status & ~STATUS_VALID_BITS) == 0);
+ *(u8 *)(state + ROSE_STATE_OFFSET_STATUS_FLAGS) = status;
}
/** \brief Initialise SOM state. Used in both block and streaming mode. */
static really_inline
-void initSomState(const struct RoseEngine *rose, char *state) {
+void initSomState(const struct RoseEngine *rose, char *state) {
assert(rose && state);
const u32 somCount = rose->somLocationCount;
- mmbit_clear((u8 *)state + rose->stateOffsets.somValid, somCount);
- mmbit_clear((u8 *)state + rose->stateOffsets.somWritable, somCount);
+ mmbit_clear((u8 *)state + rose->stateOffsets.somValid, somCount);
+ mmbit_clear((u8 *)state + rose->stateOffsets.somWritable, somCount);
}
static really_inline
@@ -181,47 +181,47 @@ void rawBlockExec(const struct RoseEngine *rose, struct hs_scratch *scratch) {
assert(rose);
assert(scratch);
- initSomState(rose, scratch->core_info.state);
+ initSomState(rose, scratch->core_info.state);
DEBUG_PRINTF("blockmode scan len=%zu\n", scratch->core_info.len);
- roseBlockExec(rose, scratch);
+ roseBlockExec(rose, scratch);
+}
+
+static really_inline
+void pureLiteralInitScratch(struct hs_scratch *scratch, u64a offset) {
+ // Some init has already been done.
+ assert(offset == scratch->core_info.buf_offset);
+
+ scratch->tctxt.lit_offset_adjust = offset + 1;
+ scratch->tctxt.lastEndOffset = offset;
+ scratch->tctxt.delayLastEndOffset = offset;
+ scratch->tctxt.filledDelayedSlots = 0;
+ scratch->al_log_sum = 0;
}
static really_inline
-void pureLiteralInitScratch(struct hs_scratch *scratch, u64a offset) {
- // Some init has already been done.
- assert(offset == scratch->core_info.buf_offset);
-
- scratch->tctxt.lit_offset_adjust = offset + 1;
- scratch->tctxt.lastEndOffset = offset;
- scratch->tctxt.delayLastEndOffset = offset;
- scratch->tctxt.filledDelayedSlots = 0;
- scratch->al_log_sum = 0;
-}
-
-static really_inline
void pureLiteralBlockExec(const struct RoseEngine *rose,
struct hs_scratch *scratch) {
assert(rose);
assert(scratch);
const struct HWLM *ftable = getFLiteralMatcher(rose);
- initSomState(rose, scratch->core_info.state);
+ initSomState(rose, scratch->core_info.state);
const u8 *buffer = scratch->core_info.buf;
size_t length = scratch->core_info.len;
DEBUG_PRINTF("rose engine %d\n", rose->runtimeImpl);
- pureLiteralInitScratch(scratch, 0);
- scratch->tctxt.groups = rose->initialGroups;
-
- hwlmExec(ftable, buffer, length, 0, roseCallback, scratch,
- rose->initialGroups & rose->floating_group_mask);
+ pureLiteralInitScratch(scratch, 0);
+ scratch->tctxt.groups = rose->initialGroups;
+
+ hwlmExec(ftable, buffer, length, 0, roseCallback, scratch,
+ rose->initialGroups & rose->floating_group_mask);
}
static really_inline
-void initOutfixQueue(struct mq *q, u32 qi, const struct RoseEngine *t,
- struct hs_scratch *scratch) {
+void initOutfixQueue(struct mq *q, u32 qi, const struct RoseEngine *t,
+ struct hs_scratch *scratch) {
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
q->nfa = getNfaByInfo(t, info);
q->end = 0;
@@ -233,7 +233,7 @@ void initOutfixQueue(struct mq *q, u32 qi, const struct RoseEngine *t,
q->length = scratch->core_info.len;
q->history = scratch->core_info.hbuf;
q->hlength = scratch->core_info.hlen;
- q->cb = roseReportAdaptor;
+ q->cb = roseReportAdaptor;
q->context = scratch;
q->report_current = 0;
@@ -248,7 +248,7 @@ void soleOutfixBlockExec(const struct RoseEngine *t,
assert(t);
assert(scratch);
- initSomState(t, scratch->core_info.state);
+ initSomState(t, scratch->core_info.state);
assert(t->outfixEndQueue == 1);
assert(!t->amatcherOffset);
assert(!t->ematcherOffset);
@@ -263,7 +263,7 @@ void soleOutfixBlockExec(const struct RoseEngine *t,
}
struct mq *q = scratch->queues;
- initOutfixQueue(q, 0, t, scratch);
+ initOutfixQueue(q, 0, t, scratch);
q->length = len; /* adjust for rev_accel */
nfaQueueInitState(nfa, q);
pushQueueAt(q, 0, MQE_START, 0);
@@ -273,8 +273,8 @@ void soleOutfixBlockExec(const struct RoseEngine *t,
char rv = nfaQueueExec(q->nfa, q, scratch->core_info.len);
if (rv && nfaAcceptsEod(nfa) && len == scratch->core_info.len) {
- nfaCheckFinalState(nfa, q->state, q->streamState, q->length, q->cb,
- scratch);
+ nfaCheckFinalState(nfa, q->state, q->streamState, q->length, q->cb,
+ scratch);
}
}
@@ -299,24 +299,24 @@ void runSmallWriteEngine(const struct SmallWriteEngine *smwr,
size_t local_alen = length - smwr->start_offset;
const u8 *local_buffer = buffer + smwr->start_offset;
- assert(isDfaType(nfa->type));
+ assert(isDfaType(nfa->type));
if (nfa->type == MCCLELLAN_NFA_8) {
nfaExecMcClellan8_B(nfa, smwr->start_offset, local_buffer,
- local_alen, roseReportAdaptor, scratch);
- } else if (nfa->type == MCCLELLAN_NFA_16) {
- nfaExecMcClellan16_B(nfa, smwr->start_offset, local_buffer,
- local_alen, roseReportAdaptor, scratch);
+ local_alen, roseReportAdaptor, scratch);
+ } else if (nfa->type == MCCLELLAN_NFA_16) {
+ nfaExecMcClellan16_B(nfa, smwr->start_offset, local_buffer,
+ local_alen, roseReportAdaptor, scratch);
} else {
- nfaExecSheng_B(nfa, smwr->start_offset, local_buffer,
- local_alen, roseReportAdaptor, scratch);
+ nfaExecSheng_B(nfa, smwr->start_offset, local_buffer,
+ local_alen, roseReportAdaptor, scratch);
}
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
- unsigned length, unsigned flags,
- hs_scratch_t *scratch, match_event_handler onEvent,
- void *userCtx) {
+hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
+ unsigned length, unsigned flags,
+ hs_scratch_t *scratch, match_event_handler onEvent,
+ void *userCtx) {
if (unlikely(!scratch || !data)) {
return HS_INVALID;
}
@@ -339,13 +339,13 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
return HS_INVALID;
}
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
-
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
+
if (rose->minWidth > length) {
DEBUG_PRINTF("minwidth=%u > length=%u\n", rose->minWidth, length);
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
return HS_SUCCESS;
}
@@ -353,9 +353,9 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
/* populate core info in scratch */
populateCoreInfo(scratch, rose, scratch->bstate, onEvent, userCtx, data,
- length, NULL, 0, 0, 0, flags);
+ length, NULL, 0, 0, 0, flags);
- clearEvec(rose, scratch->core_info.exhaustionVector);
+ clearEvec(rose, scratch->core_info.exhaustionVector);
if (rose->ckeyCount) {
scratch->core_info.logicalVector = scratch->bstate +
rose->stateOffsets.logicalVec;
@@ -368,18 +368,18 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
if (!length) {
if (rose->boundary.reportZeroEodOffset) {
- roseRunBoundaryProgram(rose, rose->boundary.reportZeroEodOffset, 0,
- scratch);
+ roseRunBoundaryProgram(rose, rose->boundary.reportZeroEodOffset, 0,
+ scratch);
}
goto set_retval;
}
if (rose->boundary.reportZeroOffset) {
- int rv = roseRunBoundaryProgram(rose, rose->boundary.reportZeroOffset,
- 0, scratch);
- if (rv == MO_HALT_MATCHING) {
- goto set_retval;
- }
+ int rv = roseRunBoundaryProgram(rose, rose->boundary.reportZeroOffset,
+ 0, scratch);
+ if (rv == MO_HALT_MATCHING) {
+ goto set_retval;
+ }
}
if (rose->minWidthExcludingBoundaries > length) {
@@ -428,7 +428,7 @@ hs_error_t HS_CDECL hs_scan(const hs_database_t *db, const char *data,
done_scan:
if (unlikely(internal_matching_error(scratch))) {
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
} else if (told_to_stop_matching(scratch)) {
unmarkScratchInUse(scratch);
@@ -438,14 +438,14 @@ done_scan:
if (rose->hasSom) {
int halt = flushStoredSomMatches(scratch, ~0ULL);
if (halt) {
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
return HS_SCAN_TERMINATED;
}
}
if (rose->boundary.reportEodOffset) {
- roseRunBoundaryProgram(rose, rose->boundary.reportEodOffset, length,
- scratch);
+ roseRunBoundaryProgram(rose, rose->boundary.reportEodOffset, length,
+ scratch);
}
set_retval:
@@ -468,10 +468,10 @@ set_retval:
DEBUG_PRINTF("done. told_to_stop_matching=%d\n",
told_to_stop_matching(scratch));
- hs_error_t rv = told_to_stop_matching(scratch) ? HS_SCAN_TERMINATED
- : HS_SUCCESS;
- unmarkScratchInUse(scratch);
- return rv;
+ hs_error_t rv = told_to_stop_matching(scratch) ? HS_SCAN_TERMINATED
+ : HS_SUCCESS;
+ unmarkScratchInUse(scratch);
+ return rv;
}
static really_inline
@@ -508,27 +508,27 @@ void maintainHistoryBuffer(const struct RoseEngine *rose, char *state,
}
static really_inline
-void init_stream(struct hs_stream *s, const struct RoseEngine *rose,
- char init_history) {
- char *state = getMultiState(s);
-
- if (init_history) {
- // Make absolutely sure that the 16 bytes leading up to the end of the
- // history buffer are initialised, as we rely on this (regardless of the
- // actual values used) in FDR.
- char *hist_end =
- state + rose->stateOffsets.history + rose->historyRequired;
- assert(hist_end - 16 >= (const char *)s);
- memset(hist_end - 16, 0x5a, 16);
- }
-
+void init_stream(struct hs_stream *s, const struct RoseEngine *rose,
+ char init_history) {
+ char *state = getMultiState(s);
+
+ if (init_history) {
+ // Make absolutely sure that the 16 bytes leading up to the end of the
+ // history buffer are initialised, as we rely on this (regardless of the
+ // actual values used) in FDR.
+ char *hist_end =
+ state + rose->stateOffsets.history + rose->historyRequired;
+ assert(hist_end - 16 >= (const char *)s);
+ memset(hist_end - 16, 0x5a, 16);
+ }
+
s->rose = rose;
s->offset = 0;
- setStreamStatus(state, 0);
+ setStreamStatus(state, 0);
roseInitState(rose, state);
- clearEvec(rose, state + rose->stateOffsets.exhausted);
+ clearEvec(rose, state + rose->stateOffsets.exhausted);
if (rose->ckeyCount) {
clearLvec(rose, state + rose->stateOffsets.logicalVec,
state + rose->stateOffsets.combVec);
@@ -539,9 +539,9 @@ void init_stream(struct hs_stream *s, const struct RoseEngine *rose,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db,
- UNUSED unsigned flags,
- hs_stream_t **stream) {
+hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db,
+ UNUSED unsigned flags,
+ hs_stream_t **stream) {
if (unlikely(!stream)) {
return HS_INVALID;
}
@@ -568,7 +568,7 @@ hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db,
return HS_NOMEM;
}
- init_stream(s, rose, 1);
+ init_stream(s, rose, 1);
*stream = s;
return HS_SUCCESS;
@@ -579,7 +579,7 @@ static really_inline
void rawEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct RoseEngine *rose = id->rose;
- if (can_stop_matching(scratch)) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("stream already broken\n");
return;
}
@@ -589,14 +589,14 @@ void rawEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
return;
}
- roseStreamEodExec(rose, id->offset, scratch);
+ roseStreamEodExec(rose, id->offset, scratch);
}
static never_inline
void soleOutfixEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct RoseEngine *t = id->rose;
- if (can_stop_matching(scratch)) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("stream already broken\n");
return;
}
@@ -614,7 +614,7 @@ void soleOutfixEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct NFA *nfa = getNfaByQueue(t, 0);
struct mq *q = scratch->queues;
- initOutfixQueue(q, 0, t, scratch);
+ initOutfixQueue(q, 0, t, scratch);
if (!scratch->core_info.buf_offset) {
DEBUG_PRINTF("buf_offset is zero\n");
return; /* no vacuous engines */
@@ -625,7 +625,7 @@ void soleOutfixEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
assert(nfaAcceptsEod(nfa));
nfaCheckFinalState(nfa, q->state, q->streamState, q->offset, q->cb,
- scratch);
+ scratch);
}
static really_inline
@@ -636,7 +636,7 @@ void report_eod_matches(hs_stream_t *id, hs_scratch_t *scratch,
const struct RoseEngine *rose = id->rose;
char *state = getMultiState(id);
- u8 status = getStreamStatus(state);
+ u8 status = getStreamStatus(state);
if (status & (STATUS_TERMINATED | STATUS_EXHAUSTED | STATUS_ERROR)) {
DEBUG_PRINTF("stream is broken, just freeing storage\n");
@@ -645,7 +645,7 @@ void report_eod_matches(hs_stream_t *id, hs_scratch_t *scratch,
populateCoreInfo(scratch, rose, state, onEvent, context, NULL, 0,
getHistory(state, rose, id->offset),
- getHistoryAmount(rose, id->offset), id->offset, status, 0);
+ getHistoryAmount(rose, id->offset), id->offset, status, 0);
if (rose->ckeyCount) {
scratch->core_info.logicalVector = state +
@@ -662,19 +662,19 @@ void report_eod_matches(hs_stream_t *id, hs_scratch_t *scratch,
if (!id->offset) {
if (rose->boundary.reportZeroEodOffset) {
- int rv = roseRunBoundaryProgram(
- rose, rose->boundary.reportZeroEodOffset, 0, scratch);
- if (rv == MO_HALT_MATCHING) {
- return;
- }
+ int rv = roseRunBoundaryProgram(
+ rose, rose->boundary.reportZeroEodOffset, 0, scratch);
+ if (rv == MO_HALT_MATCHING) {
+ return;
+ }
}
} else {
if (rose->boundary.reportEodOffset) {
- int rv = roseRunBoundaryProgram(
- rose, rose->boundary.reportEodOffset, id->offset, scratch);
- if (rv == MO_HALT_MATCHING) {
- return;
- }
+ int rv = roseRunBoundaryProgram(
+ rose, rose->boundary.reportEodOffset, id->offset, scratch);
+ if (rv == MO_HALT_MATCHING) {
+ return;
+ }
}
if (rose->requiresEodCheck) {
@@ -696,7 +696,7 @@ void report_eod_matches(hs_stream_t *id, hs_scratch_t *scratch,
int halt = flushStoredSomMatches(scratch, ~0ULL);
if (halt) {
DEBUG_PRINTF("told to stop matching\n");
- scratch->core_info.status |= STATUS_TERMINATED;
+ scratch->core_info.status |= STATUS_TERMINATED;
}
}
@@ -710,8 +710,8 @@ void report_eod_matches(hs_stream_t *id, hs_scratch_t *scratch,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
- const hs_stream_t *from_id) {
+hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
+ const hs_stream_t *from_id) {
if (!to_id) {
return HS_INVALID;
}
@@ -738,11 +738,11 @@ hs_error_t HS_CDECL hs_copy_stream(hs_stream_t **to_id,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_reset_and_copy_stream(hs_stream_t *to_id,
- const hs_stream_t *from_id,
- hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context) {
+hs_error_t HS_CDECL hs_reset_and_copy_stream(hs_stream_t *to_id,
+ const hs_stream_t *from_id,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context) {
if (!from_id || !from_id->rose) {
return HS_INVALID;
}
@@ -759,15 +759,15 @@ hs_error_t HS_CDECL hs_reset_and_copy_stream(hs_stream_t *to_id,
if (!scratch || !validScratch(to_id->rose, scratch)) {
return HS_INVALID;
}
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
report_eod_matches(to_id, scratch, onEvent, context);
if (unlikely(internal_matching_error(scratch))) {
unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
}
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
}
size_t stateSize
@@ -782,19 +782,19 @@ static really_inline
void rawStreamExec(struct hs_stream *stream_state, struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
- assert(!can_stop_matching(scratch));
+ assert(!can_stop_matching(scratch));
DEBUG_PRINTF("::: streaming rose ::: offset = %llu len = %zu\n",
stream_state->offset, scratch->core_info.len);
const struct RoseEngine *rose = stream_state->rose;
assert(rose);
- roseStreamExec(rose, scratch);
+ roseStreamExec(rose, scratch);
if (!told_to_stop_matching(scratch) &&
isAllExhausted(rose, scratch->core_info.exhaustionVector)) {
DEBUG_PRINTF("stream exhausted\n");
- scratch->core_info.status |= STATUS_EXHAUSTED;
+ scratch->core_info.status |= STATUS_EXHAUSTED;
}
}
@@ -803,7 +803,7 @@ void pureLiteralStreamExec(struct hs_stream *stream_state,
struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
- assert(!can_stop_matching(scratch));
+ assert(!can_stop_matching(scratch));
const struct RoseEngine *rose = stream_state->rose;
const struct HWLM *ftable = getFLiteralMatcher(rose);
@@ -813,20 +813,20 @@ void pureLiteralStreamExec(struct hs_stream *stream_state,
DEBUG_PRINTF("::: streaming rose ::: offset = %llu len = %zu\n",
stream_state->offset, scratch->core_info.len);
- pureLiteralInitScratch(scratch, stream_state->offset);
- scratch->tctxt.groups = loadGroups(rose, scratch->core_info.state);
-
+ pureLiteralInitScratch(scratch, stream_state->offset);
+ scratch->tctxt.groups = loadGroups(rose, scratch->core_info.state);
+
// Pure literal cases don't have floatingMinDistance set, so we always
// start the match region at zero.
const size_t start = 0;
- hwlmExecStreaming(ftable, len2, start, roseCallback, scratch,
- rose->initialGroups & rose->floating_group_mask);
+ hwlmExecStreaming(ftable, len2, start, roseCallback, scratch,
+ rose->initialGroups & rose->floating_group_mask);
if (!told_to_stop_matching(scratch) &&
isAllExhausted(rose, scratch->core_info.exhaustionVector)) {
DEBUG_PRINTF("stream exhausted\n");
- scratch->core_info.status |= STATUS_EXHAUSTED;
+ scratch->core_info.status |= STATUS_EXHAUSTED;
}
}
@@ -835,7 +835,7 @@ void soleOutfixStreamExec(struct hs_stream *stream_state,
struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
- assert(!can_stop_matching(scratch));
+ assert(!can_stop_matching(scratch));
const struct RoseEngine *t = stream_state->rose;
assert(t->outfixEndQueue == 1);
@@ -846,7 +846,7 @@ void soleOutfixStreamExec(struct hs_stream *stream_state,
const struct NFA *nfa = getNfaByQueue(t, 0);
struct mq *q = scratch->queues;
- initOutfixQueue(q, 0, t, scratch);
+ initOutfixQueue(q, 0, t, scratch);
if (!scratch->core_info.buf_offset) {
nfaQueueInitState(nfa, q);
pushQueueAt(q, 0, MQE_START, 0);
@@ -862,7 +862,7 @@ void soleOutfixStreamExec(struct hs_stream *stream_state,
if (nfaQueueExec(q->nfa, q, scratch->core_info.len)) {
nfaQueueCompressState(nfa, q, scratch->core_info.len);
} else if (!told_to_stop_matching(scratch)) {
- scratch->core_info.status |= STATUS_EXHAUSTED;
+ scratch->core_info.status |= STATUS_EXHAUSTED;
}
}
@@ -871,17 +871,17 @@ hs_error_t hs_scan_stream_internal(hs_stream_t *id, const char *data,
unsigned length, UNUSED unsigned flags,
hs_scratch_t *scratch,
match_event_handler onEvent, void *context) {
- assert(id);
- assert(scratch);
-
- if (unlikely(!data)) {
+ assert(id);
+ assert(scratch);
+
+ if (unlikely(!data)) {
return HS_INVALID;
}
const struct RoseEngine *rose = id->rose;
char *state = getMultiState(id);
- u8 status = getStreamStatus(state);
+ u8 status = getStreamStatus(state);
if (status & (STATUS_TERMINATED | STATUS_EXHAUSTED | STATUS_ERROR)) {
DEBUG_PRINTF("stream is broken, halting scan\n");
if (status & STATUS_ERROR) {
@@ -904,7 +904,7 @@ hs_error_t hs_scan_stream_internal(hs_stream_t *id, const char *data,
u32 historyAmount = getHistoryAmount(rose, id->offset);
populateCoreInfo(scratch, rose, state, onEvent, context, data, length,
getHistory(state, rose, id->offset), historyAmount,
- id->offset, status, flags);
+ id->offset, status, flags);
if (rose->ckeyCount) {
scratch->core_info.logicalVector = state +
rose->stateOffsets.logicalVec;
@@ -924,18 +924,18 @@ hs_error_t hs_scan_stream_internal(hs_stream_t *id, const char *data,
if (!id->offset && rose->boundary.reportZeroOffset) {
DEBUG_PRINTF("zero reports\n");
- int rv = roseRunBoundaryProgram(rose, rose->boundary.reportZeroOffset,
- 0, scratch);
- if (rv == MO_HALT_MATCHING) {
- DEBUG_PRINTF("halting scan\n");
- setStreamStatus(state, scratch->core_info.status);
- if (told_to_stop_matching(scratch)) {
- return HS_SCAN_TERMINATED;
- } else {
- assert(scratch->core_info.status & STATUS_EXHAUSTED);
- return HS_SUCCESS;
- }
- }
+ int rv = roseRunBoundaryProgram(rose, rose->boundary.reportZeroOffset,
+ 0, scratch);
+ if (rv == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("halting scan\n");
+ setStreamStatus(state, scratch->core_info.status);
+ if (told_to_stop_matching(scratch)) {
+ return HS_SCAN_TERMINATED;
+ } else {
+ assert(scratch->core_info.status & STATUS_EXHAUSTED);
+ return HS_SUCCESS;
+ }
+ }
}
switch (rose->runtimeImpl) {
@@ -954,16 +954,16 @@ hs_error_t hs_scan_stream_internal(hs_stream_t *id, const char *data,
if (rose->hasSom && !told_to_stop_matching(scratch)) {
int halt = flushStoredSomMatches(scratch, ~0ULL);
if (halt) {
- scratch->core_info.status |= STATUS_TERMINATED;
+ scratch->core_info.status |= STATUS_TERMINATED;
}
}
- setStreamStatus(state, scratch->core_info.status);
-
+ setStreamStatus(state, scratch->core_info.status);
+
if (unlikely(internal_matching_error(scratch))) {
return HS_UNKNOWN_ERROR;
} else if (likely(!can_stop_matching(scratch))) {
- maintainHistoryBuffer(rose, state, data, length);
+ maintainHistoryBuffer(rose, state, data, length);
id->offset += length; /* maintain offset */
if (rose->somLocationCount) {
@@ -977,28 +977,28 @@ hs_error_t hs_scan_stream_internal(hs_stream_t *id, const char *data,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
- unsigned length, unsigned flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent, void *context) {
- if (unlikely(!id || !scratch || !data ||
- !validScratch(id->rose, scratch))) {
- return HS_INVALID;
- }
-
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
- hs_error_t rv = hs_scan_stream_internal(id, data, length, flags, scratch,
- onEvent, context);
- unmarkScratchInUse(scratch);
- return rv;
+hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
+ unsigned length, unsigned flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent, void *context) {
+ if (unlikely(!id || !scratch || !data ||
+ !validScratch(id->rose, scratch))) {
+ return HS_INVALID;
+ }
+
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
+ hs_error_t rv = hs_scan_stream_internal(id, data, length, flags, scratch,
+ onEvent, context);
+ unmarkScratchInUse(scratch);
+ return rv;
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context) {
+hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context) {
if (!id) {
return HS_INVALID;
}
@@ -1007,15 +1007,15 @@ hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
if (!scratch || !validScratch(id->rose, scratch)) {
return HS_INVALID;
}
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
report_eod_matches(id, scratch, onEvent, context);
if (unlikely(internal_matching_error(scratch))) {
unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
}
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
}
hs_stream_free(id);
@@ -1024,10 +1024,10 @@ hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context) {
+hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context) {
if (!id) {
return HS_INVALID;
}
@@ -1036,26 +1036,26 @@ hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags,
if (!scratch || !validScratch(id->rose, scratch)) {
return HS_INVALID;
}
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
report_eod_matches(id, scratch, onEvent, context);
if (unlikely(internal_matching_error(scratch))) {
unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
}
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
}
- // history already initialised
- init_stream(id, id->rose, 0);
+ // history already initialised
+ init_stream(id, id->rose, 0);
return HS_SUCCESS;
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_stream_size(const hs_database_t *db,
- size_t *stream_size) {
+hs_error_t HS_CDECL hs_stream_size(const hs_database_t *db,
+ size_t *stream_size) {
if (!stream_size) {
return HS_INVALID;
}
@@ -1102,13 +1102,13 @@ void dumpData(const char *data, size_t len) {
#endif
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
- const char * const * data,
- const unsigned int *length,
- unsigned int count,
- UNUSED unsigned int flags,
- hs_scratch_t *scratch,
- match_event_handler onEvent, void *context) {
+hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
+ const char * const * data,
+ const unsigned int *length,
+ unsigned int count,
+ UNUSED unsigned int flags,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent, void *context) {
if (unlikely(!scratch || !data || !length)) {
return HS_INVALID;
}
@@ -1131,13 +1131,13 @@ hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
return HS_INVALID;
}
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
-
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
+
hs_stream_t *id = (hs_stream_t *)(scratch->bstate);
- init_stream(id, rose, 1); /* open stream */
+ init_stream(id, rose, 1); /* open stream */
for (u32 i = 0; i < count; i++) {
DEBUG_PRINTF("block %u/%u offset=%llu len=%u\n", i, count, id->offset,
@@ -1149,7 +1149,7 @@ hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
= hs_scan_stream_internal(id, data[i], length[i], 0, scratch,
onEvent, context);
if (ret != HS_SUCCESS) {
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
return ret;
}
}
@@ -1159,7 +1159,7 @@ hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
report_eod_matches(id, scratch, onEvent, context);
if (unlikely(internal_matching_error(scratch))) {
- unmarkScratchInUse(scratch);
+ unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
} else if (told_to_stop_matching(scratch)) {
unmarkScratchInUse(scratch);
@@ -1167,108 +1167,108 @@ hs_error_t HS_CDECL hs_scan_vector(const hs_database_t *db,
}
}
- unmarkScratchInUse(scratch);
-
+ unmarkScratchInUse(scratch);
+
return HS_SUCCESS;
}
-
-HS_PUBLIC_API
-hs_error_t HS_CDECL hs_compress_stream(const hs_stream_t *stream, char *buf,
- size_t buf_space, size_t *used_space) {
- if (unlikely(!stream || !used_space)) {
- return HS_INVALID;
- }
-
- if (unlikely(buf_space && !buf)) {
- return HS_INVALID;
- }
-
- const struct RoseEngine *rose = stream->rose;
-
- size_t stream_size = size_compress_stream(rose, stream);
-
- DEBUG_PRINTF("require %zu [orig %zu]\n", stream_size,
- rose->stateOffsets.end + sizeof(struct hs_stream));
- *used_space = stream_size;
-
- if (buf_space < stream_size) {
- return HS_INSUFFICIENT_SPACE;
- }
- compress_stream(buf, stream_size, rose, stream);
-
- return HS_SUCCESS;
-}
-
-HS_PUBLIC_API
-hs_error_t HS_CDECL hs_expand_stream(const hs_database_t *db,
- hs_stream_t **stream,
- const char *buf, size_t buf_size) {
- if (unlikely(!stream || !buf)) {
- return HS_INVALID;
- }
-
- *stream = NULL;
-
- hs_error_t err = validDatabase(db);
- if (unlikely(err != HS_SUCCESS)) {
- return err;
- }
-
- const struct RoseEngine *rose = hs_get_bytecode(db);
- if (unlikely(!ISALIGNED_16(rose))) {
- return HS_INVALID;
- }
-
- if (unlikely(rose->mode != HS_MODE_STREAM)) {
- return HS_DB_MODE_ERROR;
- }
-
- size_t stream_size = rose->stateOffsets.end + sizeof(struct hs_stream);
-
- struct hs_stream *s = hs_stream_alloc(stream_size);
- if (unlikely(!s)) {
- return HS_NOMEM;
- }
-
- if (!expand_stream(s, rose, buf, buf_size)) {
- hs_stream_free(s);
- return HS_INVALID;
- }
-
- *stream = s;
- return HS_SUCCESS;
-}
-
-HS_PUBLIC_API
-hs_error_t HS_CDECL hs_reset_and_expand_stream(hs_stream_t *to_stream,
- const char *buf, size_t buf_size,
- hs_scratch_t *scratch,
- match_event_handler onEvent,
- void *context) {
- if (unlikely(!to_stream || !buf)) {
- return HS_INVALID;
- }
-
- const struct RoseEngine *rose = to_stream->rose;
-
- if (onEvent) {
- if (!scratch || !validScratch(to_stream->rose, scratch)) {
- return HS_INVALID;
- }
- if (unlikely(markScratchInUse(scratch))) {
- return HS_SCRATCH_IN_USE;
- }
- report_eod_matches(to_stream, scratch, onEvent, context);
+
+HS_PUBLIC_API
+hs_error_t HS_CDECL hs_compress_stream(const hs_stream_t *stream, char *buf,
+ size_t buf_space, size_t *used_space) {
+ if (unlikely(!stream || !used_space)) {
+ return HS_INVALID;
+ }
+
+ if (unlikely(buf_space && !buf)) {
+ return HS_INVALID;
+ }
+
+ const struct RoseEngine *rose = stream->rose;
+
+ size_t stream_size = size_compress_stream(rose, stream);
+
+ DEBUG_PRINTF("require %zu [orig %zu]\n", stream_size,
+ rose->stateOffsets.end + sizeof(struct hs_stream));
+ *used_space = stream_size;
+
+ if (buf_space < stream_size) {
+ return HS_INSUFFICIENT_SPACE;
+ }
+ compress_stream(buf, stream_size, rose, stream);
+
+ return HS_SUCCESS;
+}
+
+HS_PUBLIC_API
+hs_error_t HS_CDECL hs_expand_stream(const hs_database_t *db,
+ hs_stream_t **stream,
+ const char *buf, size_t buf_size) {
+ if (unlikely(!stream || !buf)) {
+ return HS_INVALID;
+ }
+
+ *stream = NULL;
+
+ hs_error_t err = validDatabase(db);
+ if (unlikely(err != HS_SUCCESS)) {
+ return err;
+ }
+
+ const struct RoseEngine *rose = hs_get_bytecode(db);
+ if (unlikely(!ISALIGNED_16(rose))) {
+ return HS_INVALID;
+ }
+
+ if (unlikely(rose->mode != HS_MODE_STREAM)) {
+ return HS_DB_MODE_ERROR;
+ }
+
+ size_t stream_size = rose->stateOffsets.end + sizeof(struct hs_stream);
+
+ struct hs_stream *s = hs_stream_alloc(stream_size);
+ if (unlikely(!s)) {
+ return HS_NOMEM;
+ }
+
+ if (!expand_stream(s, rose, buf, buf_size)) {
+ hs_stream_free(s);
+ return HS_INVALID;
+ }
+
+ *stream = s;
+ return HS_SUCCESS;
+}
+
+HS_PUBLIC_API
+hs_error_t HS_CDECL hs_reset_and_expand_stream(hs_stream_t *to_stream,
+ const char *buf, size_t buf_size,
+ hs_scratch_t *scratch,
+ match_event_handler onEvent,
+ void *context) {
+ if (unlikely(!to_stream || !buf)) {
+ return HS_INVALID;
+ }
+
+ const struct RoseEngine *rose = to_stream->rose;
+
+ if (onEvent) {
+ if (!scratch || !validScratch(to_stream->rose, scratch)) {
+ return HS_INVALID;
+ }
+ if (unlikely(markScratchInUse(scratch))) {
+ return HS_SCRATCH_IN_USE;
+ }
+ report_eod_matches(to_stream, scratch, onEvent, context);
if (unlikely(internal_matching_error(scratch))) {
unmarkScratchInUse(scratch);
return HS_UNKNOWN_ERROR;
}
- unmarkScratchInUse(scratch);
- }
-
- if (expand_stream(to_stream, rose, buf, buf_size)) {
- return HS_SUCCESS;
- } else {
- return HS_INVALID;
- }
-}
+ unmarkScratchInUse(scratch);
+ }
+
+ if (expand_stream(to_stream, rose, buf, buf_size)) {
+ return HS_SUCCESS;
+ } else {
+ return HS_INVALID;
+ }
+}
diff --git a/contrib/libs/hyperscan/src/scratch.c b/contrib/libs/hyperscan/src/scratch.c
index c59a9afa064..25991e2bbad 100644
--- a/contrib/libs/hyperscan/src/scratch.c
+++ b/contrib/libs/hyperscan/src/scratch.c
@@ -44,76 +44,76 @@
#include "rose/rose_internal.h"
#include "util/fatbit.h"
-/**
- * Determine the space required for a correctly aligned array of fatbit
- * structure, laid out as:
- *
- * - an array of num_entries pointers, each to a fatbit.
- * - an array of fatbit structures, each of size fatbit_len.
- *
- * fatbit_len should have been determined at compile time, via the
- * fatbit_size() call.
- */
-static
-size_t fatbit_array_size(u32 num_entries, u32 fatbit_len) {
- size_t len = 0;
-
- // Array of pointers to each fatbit entry.
- len += sizeof(struct fatbit *) * num_entries;
-
- // Fatbit entries themselves.
- len = ROUNDUP_N(len, alignof(struct fatbit));
- len += (size_t)fatbit_len * num_entries;
-
- return ROUNDUP_N(len, 8); // Round up for potential padding.
-}
-
+/**
+ * Determine the space required for a correctly aligned array of fatbit
+ * structure, laid out as:
+ *
+ * - an array of num_entries pointers, each to a fatbit.
+ * - an array of fatbit structures, each of size fatbit_len.
+ *
+ * fatbit_len should have been determined at compile time, via the
+ * fatbit_size() call.
+ */
+static
+size_t fatbit_array_size(u32 num_entries, u32 fatbit_len) {
+ size_t len = 0;
+
+ // Array of pointers to each fatbit entry.
+ len += sizeof(struct fatbit *) * num_entries;
+
+ // Fatbit entries themselves.
+ len = ROUNDUP_N(len, alignof(struct fatbit));
+ len += (size_t)fatbit_len * num_entries;
+
+ return ROUNDUP_N(len, 8); // Round up for potential padding.
+}
+
/** Used by hs_alloc_scratch and hs_clone_scratch to allocate a complete
* scratch region from a prototype structure. */
static
hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
u32 queueCount = proto->queueCount;
- u32 activeQueueArraySize = proto->activeQueueArraySize;
- u32 deduperCount = proto->deduper.dkey_count;
- u32 deduperLogSize = proto->deduper.log_size;
+ u32 activeQueueArraySize = proto->activeQueueArraySize;
+ u32 deduperCount = proto->deduper.dkey_count;
+ u32 deduperLogSize = proto->deduper.log_size;
u32 bStateSize = proto->bStateSize;
u32 tStateSize = proto->tStateSize;
u32 fullStateSize = proto->fullStateSize;
u32 anchored_literal_region_len = proto->anchored_literal_region_len;
- u32 anchored_literal_fatbit_size = proto->anchored_literal_fatbit_size;
+ u32 anchored_literal_fatbit_size = proto->anchored_literal_fatbit_size;
u32 som_store_size = proto->som_store_count * sizeof(u64a);
u32 som_attempted_store_size = proto->som_store_count * sizeof(u64a);
- u32 som_now_size = proto->som_fatbit_size;
- u32 som_attempted_size = proto->som_fatbit_size;
+ u32 som_now_size = proto->som_fatbit_size;
+ u32 som_attempted_size = proto->som_fatbit_size;
struct hs_scratch *s;
struct hs_scratch *s_tmp;
size_t queue_size = queueCount * sizeof(struct mq);
size_t qmpq_size = queueCount * sizeof(struct queue_match);
- assert(anchored_literal_region_len < 8 * sizeof(s->al_log_sum));
+ assert(anchored_literal_region_len < 8 * sizeof(s->al_log_sum));
- size_t anchored_literal_region_size = fatbit_array_size(
- anchored_literal_region_len, proto->anchored_literal_fatbit_size);
- size_t delay_region_size =
- fatbit_array_size(DELAY_SLOT_COUNT, proto->delay_fatbit_size);
+ size_t anchored_literal_region_size = fatbit_array_size(
+ anchored_literal_region_len, proto->anchored_literal_fatbit_size);
+ size_t delay_region_size =
+ fatbit_array_size(DELAY_SLOT_COUNT, proto->delay_fatbit_size);
// the size is all the allocated stuff, not including the struct itself
size_t size = queue_size + 63
+ bStateSize + tStateSize
+ fullStateSize + 63 /* cacheline padding */
- + proto->handledKeyFatbitSize /* handled roles */
- + activeQueueArraySize /* active queue array */
- + 2 * deduperLogSize /* need odd and even logs */
- + 2 * deduperLogSize /* ditto som logs */
+ + proto->handledKeyFatbitSize /* handled roles */
+ + activeQueueArraySize /* active queue array */
+ + 2 * deduperLogSize /* need odd and even logs */
+ + 2 * deduperLogSize /* ditto som logs */
+ 2 * sizeof(u64a) * deduperCount /* start offsets for som */
- + anchored_literal_region_size + qmpq_size
- + delay_region_size
+ + anchored_literal_region_size + qmpq_size
+ + delay_region_size
+ som_store_size
+ som_now_size
+ som_attempted_size
- + som_attempted_store_size + 15;
+ + som_attempted_store_size + 15;
/* the struct plus the allocated stuff plus padding for cacheline
* alignment */
@@ -133,10 +133,10 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
*s = *proto;
s->magic = SCRATCH_MAGIC;
- s->in_use = 0;
+ s->in_use = 0;
s->scratchSize = alloc_size;
s->scratch_alloc = (char *)s_tmp;
- s->fdr_conf = NULL;
+ s->fdr_conf = NULL;
// each of these is at an offset from the previous
char *current = (char *)s + sizeof(*s);
@@ -155,24 +155,24 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
s->som_attempted_store = (u64a *)current;
current += som_attempted_store_size;
- current = ROUNDUP_PTR(current, alignof(struct fatbit *));
- s->delay_slots = (struct fatbit **)current;
- current += sizeof(struct fatbit *) * DELAY_SLOT_COUNT;
- current = ROUNDUP_PTR(current, alignof(struct fatbit));
- for (u32 i = 0; i < DELAY_SLOT_COUNT; i++) {
- s->delay_slots[i] = (struct fatbit *)current;
- assert(ISALIGNED(s->delay_slots[i]));
- current += proto->delay_fatbit_size;
+ current = ROUNDUP_PTR(current, alignof(struct fatbit *));
+ s->delay_slots = (struct fatbit **)current;
+ current += sizeof(struct fatbit *) * DELAY_SLOT_COUNT;
+ current = ROUNDUP_PTR(current, alignof(struct fatbit));
+ for (u32 i = 0; i < DELAY_SLOT_COUNT; i++) {
+ s->delay_slots[i] = (struct fatbit *)current;
+ assert(ISALIGNED(s->delay_slots[i]));
+ current += proto->delay_fatbit_size;
}
- current = ROUNDUP_PTR(current, alignof(struct fatbit *));
- s->al_log = (struct fatbit **)current;
- current += sizeof(struct fatbit *) * anchored_literal_region_len;
- current = ROUNDUP_PTR(current, alignof(struct fatbit));
+ current = ROUNDUP_PTR(current, alignof(struct fatbit *));
+ s->al_log = (struct fatbit **)current;
+ current += sizeof(struct fatbit *) * anchored_literal_region_len;
+ current = ROUNDUP_PTR(current, alignof(struct fatbit));
for (u32 i = 0; i < anchored_literal_region_len; i++) {
- s->al_log[i] = (struct fatbit *)current;
- assert(ISALIGNED(s->al_log[i]));
- current += anchored_literal_fatbit_size;
+ s->al_log[i] = (struct fatbit *)current;
+ assert(ISALIGNED(s->al_log[i]));
+ current += anchored_literal_fatbit_size;
}
current = ROUNDUP_PTR(current, 8);
@@ -198,22 +198,22 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
assert(ISALIGNED_N(current, 8));
s->aqa = (struct fatbit *)current;
- current += activeQueueArraySize;
+ current += activeQueueArraySize;
s->handled_roles = (struct fatbit *)current;
- current += proto->handledKeyFatbitSize;
+ current += proto->handledKeyFatbitSize;
s->deduper.log[0] = (struct fatbit *)current;
- current += deduperLogSize;
+ current += deduperLogSize;
s->deduper.log[1] = (struct fatbit *)current;
- current += deduperLogSize;
+ current += deduperLogSize;
s->deduper.som_log[0] = (struct fatbit *)current;
- current += deduperLogSize;
+ current += deduperLogSize;
s->deduper.som_log[1] = (struct fatbit *)current;
- current += deduperLogSize;
+ current += deduperLogSize;
s->som_set_now = (struct fatbit *)current;
current += som_now_size;
@@ -241,8 +241,8 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
- hs_scratch_t **scratch) {
+hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
+ hs_scratch_t **scratch) {
if (!db || !scratch) {
return HS_INVALID;
}
@@ -266,9 +266,9 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
if ((*scratch)->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
- if (markScratchInUse(*scratch)) {
- return HS_SCRATCH_IN_USE;
- }
+ if (markScratchInUse(*scratch)) {
+ return HS_SCRATCH_IN_USE;
+ }
}
const struct RoseEngine *rose = hs_get_bytecode(db);
@@ -301,19 +301,19 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
proto->anchored_literal_region_len = rose->anchoredDistance;
}
- if (rose->anchored_fatbit_size > proto->anchored_literal_fatbit_size) {
+ if (rose->anchored_fatbit_size > proto->anchored_literal_fatbit_size) {
resize = 1;
- proto->anchored_literal_fatbit_size = rose->anchored_fatbit_size;
+ proto->anchored_literal_fatbit_size = rose->anchored_fatbit_size;
}
- if (rose->delay_fatbit_size > proto->delay_fatbit_size) {
+ if (rose->delay_fatbit_size > proto->delay_fatbit_size) {
resize = 1;
- proto->delay_fatbit_size = rose->delay_fatbit_size;
+ proto->delay_fatbit_size = rose->delay_fatbit_size;
}
- if (rose->handledKeyFatbitSize > proto->handledKeyFatbitSize) {
+ if (rose->handledKeyFatbitSize > proto->handledKeyFatbitSize) {
resize = 1;
- proto->handledKeyFatbitSize = rose->handledKeyFatbitSize;
+ proto->handledKeyFatbitSize = rose->handledKeyFatbitSize;
}
if (rose->tStateSize > proto->tStateSize) {
@@ -327,22 +327,22 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
proto->som_store_count = som_store_count;
}
- if (rose->somLocationFatbitSize > proto->som_fatbit_size) {
- resize = 1;
- proto->som_fatbit_size = rose->somLocationFatbitSize;
- }
-
+ if (rose->somLocationFatbitSize > proto->som_fatbit_size) {
+ resize = 1;
+ proto->som_fatbit_size = rose->somLocationFatbitSize;
+ }
+
u32 queueCount = rose->queueCount;
if (queueCount > proto->queueCount) {
resize = 1;
proto->queueCount = queueCount;
}
- if (rose->activeQueueArraySize > proto->activeQueueArraySize) {
- resize = 1;
- proto->activeQueueArraySize = rose->activeQueueArraySize;
- }
-
+ if (rose->activeQueueArraySize > proto->activeQueueArraySize) {
+ resize = 1;
+ proto->activeQueueArraySize = rose->activeQueueArraySize;
+ }
+
u32 bStateSize = 0;
if (rose->mode == HS_MODE_BLOCK) {
bStateSize = rose->stateOffsets.end;
@@ -362,10 +362,10 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
proto->fullStateSize = fullStateSize;
}
- if (rose->dkeyCount > proto->deduper.dkey_count) {
+ if (rose->dkeyCount > proto->deduper.dkey_count) {
resize = 1;
- proto->deduper.dkey_count = rose->dkeyCount;
- proto->deduper.log_size = rose->dkeyLogSize;
+ proto->deduper.dkey_count = rose->dkeyCount;
+ proto->deduper.log_size = rose->dkeyLogSize;
}
if (resize) {
@@ -381,16 +381,16 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
}
} else {
hs_scratch_free(proto_tmp); /* kill off temp used for sizing */
- unmarkScratchInUse(*scratch);
+ unmarkScratchInUse(*scratch);
}
- assert(!(*scratch)->in_use);
+ assert(!(*scratch)->in_use);
return HS_SUCCESS;
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
- hs_scratch_t **dest) {
+hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
+ hs_scratch_t **dest) {
if (!dest || !src || !ISALIGNED_CL(src) || src->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
@@ -402,12 +402,12 @@ hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
return ret;
}
- assert(!(*dest)->in_use);
+ assert(!(*dest)->in_use);
return HS_SUCCESS;
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
+hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
if (scratch) {
/* has to be aligned before we can do anything with it */
if (!ISALIGNED_CL(scratch)) {
@@ -416,10 +416,10 @@ hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
if (scratch->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
- if (markScratchInUse(scratch)) {
- return HS_SCRATCH_IN_USE;
- }
-
+ if (markScratchInUse(scratch)) {
+ return HS_SCRATCH_IN_USE;
+ }
+
scratch->magic = 0;
assert(scratch->scratch_alloc);
DEBUG_PRINTF("scratch %p is really at %p : freeing\n", scratch,
@@ -431,7 +431,7 @@ hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
}
HS_PUBLIC_API
-hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch, size_t *size) {
+hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch, size_t *size) {
if (!size || !scratch || !ISALIGNED_CL(scratch) ||
scratch->magic != SCRATCH_MAGIC) {
return HS_INVALID;
diff --git a/contrib/libs/hyperscan/src/scratch.h b/contrib/libs/hyperscan/src/scratch.h
index c8e0abd0615..1256f7aba82 100644
--- a/contrib/libs/hyperscan/src/scratch.h
+++ b/contrib/libs/hyperscan/src/scratch.h
@@ -70,19 +70,19 @@ struct catchup_pq {
u32 qm_size; /**< current size of the priority queue */
};
-/** \brief Status flag: user requested termination. */
-#define STATUS_TERMINATED (1U << 0)
+/** \brief Status flag: user requested termination. */
+#define STATUS_TERMINATED (1U << 0)
-/** \brief Status flag: it has been determined that it is not possible for this
- * stream to raise any more matches.
- *
- * This may be because all its exhaustion keys are on or for other reasons
- * (anchored sections not matching). */
-#define STATUS_EXHAUSTED (1U << 1)
+/** \brief Status flag: it has been determined that it is not possible for this
+ * stream to raise any more matches.
+ *
+ * This may be because all its exhaustion keys are on or for other reasons
+ * (anchored sections not matching). */
+#define STATUS_EXHAUSTED (1U << 1)
-/** \brief Status flag: Rose requires rebuild as delay literal matched in
- * history. */
-#define STATUS_DELAY_DIRTY (1U << 2)
+/** \brief Status flag: Rose requires rebuild as delay literal matched in
+ * history. */
+#define STATUS_DELAY_DIRTY (1U << 2)
/** \brief Status flag: Unexpected Rose program error. */
#define STATUS_ERROR (1U << 3)
@@ -106,7 +106,7 @@ struct core_info {
const u8 *hbuf; /**< history buffer */
size_t hlen; /**< length of history buffer in bytes. */
u64a buf_offset; /**< stream offset, for the base of the buffer */
- u8 status; /**< stream status bitmask, using STATUS_ flags above */
+ u8 status; /**< stream status bitmask, using STATUS_ flags above */
};
/** \brief Rose state information. */
@@ -132,33 +132,33 @@ struct RoseContext {
u32 filledDelayedSlots;
u32 curr_qi; /**< currently executing main queue index during
* \ref nfaQueueExec */
-
- /**
- * \brief Buffer for caseful long literal support, used in streaming mode
- * only.
- *
- * If a long literal prefix was at the end of the buffer at the end of a
- * stream write, then the long lit table hashes it and stores the result in
- * stream state. At the start of the next write, this value is used to set
- * this buffer to the matching prefix string (stored in the bytecode.
- */
- const u8 *ll_buf;
-
- /** \brief Length in bytes of the string pointed to by ll_buf. */
- size_t ll_len;
-
- /** \brief Caseless version of ll_buf. */
- const u8 *ll_buf_nocase;
-
- /** \brief Length in bytes of the string pointed to by ll_buf_nocase. */
- size_t ll_len_nocase;
+
+ /**
+ * \brief Buffer for caseful long literal support, used in streaming mode
+ * only.
+ *
+ * If a long literal prefix was at the end of the buffer at the end of a
+ * stream write, then the long lit table hashes it and stores the result in
+ * stream state. At the start of the next write, this value is used to set
+ * this buffer to the matching prefix string (stored in the bytecode.
+ */
+ const u8 *ll_buf;
+
+ /** \brief Length in bytes of the string pointed to by ll_buf. */
+ size_t ll_len;
+
+ /** \brief Caseless version of ll_buf. */
+ const u8 *ll_buf_nocase;
+
+ /** \brief Length in bytes of the string pointed to by ll_buf_nocase. */
+ size_t ll_len_nocase;
};
struct match_deduper {
struct fatbit *log[2]; /**< even, odd logs */
- struct fatbit *som_log[2]; /**< even, odd fatbit logs for som */
+ struct fatbit *som_log[2]; /**< even, odd fatbit logs for som */
u64a *som_start_log[2]; /**< even, odd start offset logs for som */
- u32 dkey_count;
+ u32 dkey_count;
u32 log_size;
u64a current_report_offset;
u8 som_log_dirty;
@@ -171,9 +171,9 @@ struct match_deduper {
*/
struct ALIGN_CL_DIRECTIVE hs_scratch {
u32 magic;
- u8 in_use; /**< non-zero when being used by an API call. */
+ u8 in_use; /**< non-zero when being used by an API call. */
u32 queueCount;
- u32 activeQueueArraySize; /**< size of active queue array fatbit in bytes */
+ u32 activeQueueArraySize; /**< size of active queue array fatbit in bytes */
u32 bStateSize; /**< sizeof block mode states */
u32 tStateSize; /**< sizeof transient rose states */
u32 fullStateSize; /**< size of uncompressed nfa state */
@@ -184,15 +184,15 @@ struct ALIGN_CL_DIRECTIVE hs_scratch {
struct mq *queues;
struct fatbit *aqa; /**< active queue array; fatbit of queues that are valid
* & active */
- struct fatbit **delay_slots;
- struct fatbit **al_log;
+ struct fatbit **delay_slots;
+ struct fatbit **al_log;
u64a al_log_sum;
struct catchup_pq catchup_pq;
struct core_info core_info;
struct match_deduper deduper;
u32 anchored_literal_region_len;
- u32 anchored_literal_fatbit_size; /**< size of each anch fatbit in bytes */
- struct fatbit *handled_roles; /**< fatbit of ROLES (not states) already
+ u32 anchored_literal_fatbit_size; /**< size of each anch fatbit in bytes */
+ struct fatbit *handled_roles; /**< fatbit of ROLES (not states) already
* handled by this literal */
u64a *som_store; /**< array of som locations */
u64a *som_attempted_store; /**< array of som locations for fail stores */
@@ -203,34 +203,34 @@ struct ALIGN_CL_DIRECTIVE hs_scratch {
* location had been writable */
u64a som_set_now_offset; /**< offset at which som_set_now represents */
u32 som_store_count;
- u32 som_fatbit_size; /**< size of som location fatbit structures in bytes */
- u32 handledKeyFatbitSize; /**< size of handled_keys fatbit in bytes */
- u32 delay_fatbit_size; /**< size of each delay fatbit in bytes */
- u32 scratchSize;
- char *scratch_alloc; /* user allocated scratch object */
- u64a *fdr_conf; /**< FDR confirm value */
- u8 fdr_conf_offset; /**< offset where FDR/Teddy front end matches
- * in buffer */
+ u32 som_fatbit_size; /**< size of som location fatbit structures in bytes */
+ u32 handledKeyFatbitSize; /**< size of handled_keys fatbit in bytes */
+ u32 delay_fatbit_size; /**< size of each delay fatbit in bytes */
+ u32 scratchSize;
+ char *scratch_alloc; /* user allocated scratch object */
+ u64a *fdr_conf; /**< FDR confirm value */
+ u8 fdr_conf_offset; /**< offset where FDR/Teddy front end matches
+ * in buffer */
};
-/* array of fatbit ptr; TODO: why not an array of fatbits? */
+/* array of fatbit ptr; TODO: why not an array of fatbits? */
static really_inline
-struct fatbit **getAnchoredLiteralLog(struct hs_scratch *scratch) {
- return scratch->al_log;
+struct fatbit **getAnchoredLiteralLog(struct hs_scratch *scratch) {
+ return scratch->al_log;
}
static really_inline
-struct fatbit **getDelaySlots(struct hs_scratch *scratch) {
- return scratch->delay_slots;
+struct fatbit **getDelaySlots(struct hs_scratch *scratch) {
+ return scratch->delay_slots;
}
static really_inline
-char told_to_stop_matching(const struct hs_scratch *scratch) {
- return scratch->core_info.status & STATUS_TERMINATED;
+char told_to_stop_matching(const struct hs_scratch *scratch) {
+ return scratch->core_info.status & STATUS_TERMINATED;
}
static really_inline
-char can_stop_matching(const struct hs_scratch *scratch) {
+char can_stop_matching(const struct hs_scratch *scratch) {
return scratch->core_info.status &
(STATUS_TERMINATED | STATUS_EXHAUSTED | STATUS_ERROR);
}
@@ -240,32 +240,32 @@ char internal_matching_error(const struct hs_scratch *scratch) {
return scratch->core_info.status & STATUS_ERROR;
}
-/**
- * \brief Mark scratch as in use.
- *
- * Returns non-zero if it was already in use, zero otherwise.
- */
+/**
+ * \brief Mark scratch as in use.
+ *
+ * Returns non-zero if it was already in use, zero otherwise.
+ */
static really_inline
-char markScratchInUse(struct hs_scratch *scratch) {
- DEBUG_PRINTF("marking scratch as in use\n");
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
- if (scratch->in_use) {
- DEBUG_PRINTF("scratch already in use!\n");
- return 1;
- }
- scratch->in_use = 1;
- return 0;
+char markScratchInUse(struct hs_scratch *scratch) {
+ DEBUG_PRINTF("marking scratch as in use\n");
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+ if (scratch->in_use) {
+ DEBUG_PRINTF("scratch already in use!\n");
+ return 1;
+ }
+ scratch->in_use = 1;
+ return 0;
}
-/**
- * \brief Mark scratch as no longer in use.
- */
+/**
+ * \brief Mark scratch as no longer in use.
+ */
static really_inline
-void unmarkScratchInUse(struct hs_scratch *scratch) {
- DEBUG_PRINTF("marking scratch as not in use\n");
- assert(scratch && scratch->magic == SCRATCH_MAGIC);
- assert(scratch->in_use == 1);
- scratch->in_use = 0;
+void unmarkScratchInUse(struct hs_scratch *scratch) {
+ DEBUG_PRINTF("marking scratch as not in use\n");
+ assert(scratch && scratch->magic == SCRATCH_MAGIC);
+ assert(scratch->in_use == 1);
+ scratch->in_use = 0;
}
#ifdef __cplusplus
diff --git a/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.cpp b/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.cpp
index 7dc4d6e8832..d9931376328 100644
--- a/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.cpp
+++ b/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.cpp
@@ -26,38 +26,38 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
- * \brief Small-write engine build code.
- */
-
+/**
+ * \file
+ * \brief Small-write engine build code.
+ */
+
#include "smallwrite/smallwrite_build.h"
#include "grey.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
-#include "nfa/dfa_min.h"
+#include "compiler/compiler.h"
+#include "nfa/dfa_min.h"
#include "nfa/mcclellancompile.h"
#include "nfa/mcclellancompile_util.h"
#include "nfa/nfa_internal.h"
#include "nfa/rdfa_merge.h"
-#include "nfa/shengcompile.h"
+#include "nfa/shengcompile.h"
#include "nfagraph/ng.h"
-#include "nfagraph/ng_depth.h"
+#include "nfagraph/ng_depth.h"
#include "nfagraph/ng_holder.h"
#include "nfagraph/ng_mcclellan.h"
-#include "nfagraph/ng_reports.h"
-#include "nfagraph/ng_prune.h"
+#include "nfagraph/ng_reports.h"
+#include "nfagraph/ng_prune.h"
#include "nfagraph/ng_util.h"
#include "smallwrite/smallwrite_internal.h"
#include "util/alloc.h"
-#include "util/bytecode_ptr.h"
+#include "util/bytecode_ptr.h"
#include "util/charreach.h"
-#include "util/compare.h"
+#include "util/compare.h"
#include "util/compile_context.h"
#include "util/container.h"
#include "util/make_unique.h"
-#include "util/ue2_graph.h"
+#include "util/ue2_graph.h"
#include "util/ue2string.h"
#include "util/verify_types.h"
@@ -66,236 +66,236 @@
#include <vector>
#include <utility>
-#include <boost/graph/breadth_first_search.hpp>
-
+#include <boost/graph/breadth_first_search.hpp>
+
using namespace std;
namespace ue2 {
#define DFA_MERGE_MAX_STATES 8000
-#define MAX_TRIE_VERTICES 8000
-
-struct LitTrieVertexProps {
- LitTrieVertexProps() = default;
- explicit LitTrieVertexProps(u8 c_in) : c(c_in) {}
- size_t index; // managed by ue2_graph
- u8 c = 0; //!< character reached on this vertex
- flat_set<ReportID> reports; //!< managed reports fired on this vertex
-};
-
-struct LitTrieEdgeProps {
- size_t index; // managed by ue2_graph
-};
-
-/**
- * \brief BGL graph used to store a trie of literals (for later AC construction
- * into a DFA).
- */
-struct LitTrie
- : public ue2_graph<LitTrie, LitTrieVertexProps, LitTrieEdgeProps> {
-
- LitTrie() : root(add_vertex(*this)) {}
-
- const vertex_descriptor root; //!< Root vertex for the trie.
-};
-
-static
-bool is_empty(const LitTrie &trie) {
- return num_vertices(trie) <= 1;
-}
-
-static
-std::set<ReportID> all_reports(const LitTrie &trie) {
- std::set<ReportID> reports;
- for (auto v : vertices_range(trie)) {
- insert(&reports, trie[v].reports);
- }
- return reports;
-}
-
-using LitTrieVertex = LitTrie::vertex_descriptor;
-using LitTrieEdge = LitTrie::edge_descriptor;
-
+#define MAX_TRIE_VERTICES 8000
+
+struct LitTrieVertexProps {
+ LitTrieVertexProps() = default;
+ explicit LitTrieVertexProps(u8 c_in) : c(c_in) {}
+ size_t index; // managed by ue2_graph
+ u8 c = 0; //!< character reached on this vertex
+ flat_set<ReportID> reports; //!< managed reports fired on this vertex
+};
+
+struct LitTrieEdgeProps {
+ size_t index; // managed by ue2_graph
+};
+
+/**
+ * \brief BGL graph used to store a trie of literals (for later AC construction
+ * into a DFA).
+ */
+struct LitTrie
+ : public ue2_graph<LitTrie, LitTrieVertexProps, LitTrieEdgeProps> {
+
+ LitTrie() : root(add_vertex(*this)) {}
+
+ const vertex_descriptor root; //!< Root vertex for the trie.
+};
+
+static
+bool is_empty(const LitTrie &trie) {
+ return num_vertices(trie) <= 1;
+}
+
+static
+std::set<ReportID> all_reports(const LitTrie &trie) {
+ std::set<ReportID> reports;
+ for (auto v : vertices_range(trie)) {
+ insert(&reports, trie[v].reports);
+ }
+ return reports;
+}
+
+using LitTrieVertex = LitTrie::vertex_descriptor;
+using LitTrieEdge = LitTrie::edge_descriptor;
+
namespace { // unnamed
// Concrete impl class
class SmallWriteBuildImpl : public SmallWriteBuild {
public:
- SmallWriteBuildImpl(size_t num_patterns, const ReportManager &rm,
- const CompileContext &cc);
+ SmallWriteBuildImpl(size_t num_patterns, const ReportManager &rm,
+ const CompileContext &cc);
// Construct a runtime implementation.
- bytecode_ptr<SmallWriteEngine> build(u32 roseQuality) override;
+ bytecode_ptr<SmallWriteEngine> build(u32 roseQuality) override;
- void add(const NGHolder &g, const ExpressionInfo &expr) override;
+ void add(const NGHolder &g, const ExpressionInfo &expr) override;
void add(const ue2_literal &literal, ReportID r) override;
- set<ReportID> all_reports() const override;
+ set<ReportID> all_reports() const override;
const ReportManager &rm;
const CompileContext &cc;
- vector<unique_ptr<raw_dfa>> dfas;
- LitTrie lit_trie;
- LitTrie lit_trie_nocase;
- size_t num_literals = 0;
+ vector<unique_ptr<raw_dfa>> dfas;
+ LitTrie lit_trie;
+ LitTrie lit_trie_nocase;
+ size_t num_literals = 0;
bool poisoned;
};
} // namespace
-SmallWriteBuild::~SmallWriteBuild() = default;
+SmallWriteBuild::~SmallWriteBuild() = default;
-SmallWriteBuildImpl::SmallWriteBuildImpl(size_t num_patterns,
- const ReportManager &rm_in,
+SmallWriteBuildImpl::SmallWriteBuildImpl(size_t num_patterns,
+ const ReportManager &rm_in,
const CompileContext &cc_in)
: rm(rm_in), cc(cc_in),
/* small write is block mode only */
- poisoned(!cc.grey.allowSmallWrite
- || cc.streaming
- || num_patterns > cc.grey.smallWriteMaxPatterns) {
+ poisoned(!cc.grey.allowSmallWrite
+ || cc.streaming
+ || num_patterns > cc.grey.smallWriteMaxPatterns) {
+}
+
+/**
+ * \brief Remove any reports from the given vertex that cannot match within
+ * max_depth due to their constraints.
+ */
+static
+bool pruneOverlongReports(NFAVertex v, NGHolder &g, const depth &max_depth,
+ const ReportManager &rm) {
+ assert(!g[v].reports.empty());
+
+ vector<ReportID> bad_reports;
+
+ for (ReportID id : g[v].reports) {
+ const auto &report = rm.getReport(id);
+ if (report.minOffset > max_depth) {
+ bad_reports.push_back(id);
+ }
+ }
+
+ for (ReportID id : bad_reports) {
+ g[v].reports.erase(id);
+ }
+
+ if (g[v].reports.empty()) {
+ DEBUG_PRINTF("none of vertex %zu's reports can match, cut accepts\n",
+ g[v].index);
+ remove_edge(v, g.accept, g);
+ remove_edge(v, g.acceptEod, g);
+ }
+
+ return !bad_reports.empty();
+}
+
+/**
+ * \brief Prune vertices and reports from the graph that cannot match within
+ * max_depth.
+ */
+static
+bool pruneOverlong(NGHolder &g, const depth &max_depth,
+ const ReportManager &rm) {
+ bool modified = false;
+ auto depths = calcBidiDepths(g);
+
+ for (auto v : vertices_range(g)) {
+ if (is_special(v, g)) {
+ continue;
+ }
+ const auto &d = depths.at(g[v].index);
+ depth min_match_offset = min(d.fromStart.min, d.fromStartDotStar.min)
+ + min(d.toAccept.min, d.toAcceptEod.min);
+ if (min_match_offset > max_depth) {
+ clear_vertex(v, g);
+ modified = true;
+ continue;
+ }
+
+ if (is_match_vertex(v, g)) {
+ modified |= pruneOverlongReports(v, g, max_depth, rm);
+ }
+ }
+
+ if (modified) {
+ pruneUseless(g);
+ DEBUG_PRINTF("pruned graph down to %zu vertices\n", num_vertices(g));
+ }
+
+ return modified;
+}
+
+/**
+ * \brief Attempt to merge the set of DFAs given down into a single raw_dfa.
+ * Returns false on failure.
+ */
+static
+bool mergeDfas(vector<unique_ptr<raw_dfa>> &dfas, const ReportManager &rm,
+ const CompileContext &cc) {
+ assert(!dfas.empty());
+
+ if (dfas.size() == 1) {
+ return true;
+ }
+
+ DEBUG_PRINTF("attempting to merge %zu DFAs\n", dfas.size());
+
+ vector<const raw_dfa *> dfa_ptrs;
+ dfa_ptrs.reserve(dfas.size());
+ for (auto &d : dfas) {
+ dfa_ptrs.push_back(d.get());
+ }
+
+ auto merged = mergeAllDfas(dfa_ptrs, DFA_MERGE_MAX_STATES, &rm, cc.grey);
+ if (!merged) {
+ DEBUG_PRINTF("merge failed\n");
+ return false;
+ }
+
+ DEBUG_PRINTF("merge succeeded, result has %zu states\n",
+ merged->states.size());
+ dfas.clear();
+ dfas.push_back(std::move(merged));
+ return true;
}
-/**
- * \brief Remove any reports from the given vertex that cannot match within
- * max_depth due to their constraints.
- */
-static
-bool pruneOverlongReports(NFAVertex v, NGHolder &g, const depth &max_depth,
- const ReportManager &rm) {
- assert(!g[v].reports.empty());
-
- vector<ReportID> bad_reports;
-
- for (ReportID id : g[v].reports) {
- const auto &report = rm.getReport(id);
- if (report.minOffset > max_depth) {
- bad_reports.push_back(id);
- }
- }
-
- for (ReportID id : bad_reports) {
- g[v].reports.erase(id);
- }
-
- if (g[v].reports.empty()) {
- DEBUG_PRINTF("none of vertex %zu's reports can match, cut accepts\n",
- g[v].index);
- remove_edge(v, g.accept, g);
- remove_edge(v, g.acceptEod, g);
- }
-
- return !bad_reports.empty();
-}
-
-/**
- * \brief Prune vertices and reports from the graph that cannot match within
- * max_depth.
- */
-static
-bool pruneOverlong(NGHolder &g, const depth &max_depth,
- const ReportManager &rm) {
- bool modified = false;
- auto depths = calcBidiDepths(g);
-
- for (auto v : vertices_range(g)) {
- if (is_special(v, g)) {
- continue;
- }
- const auto &d = depths.at(g[v].index);
- depth min_match_offset = min(d.fromStart.min, d.fromStartDotStar.min)
- + min(d.toAccept.min, d.toAcceptEod.min);
- if (min_match_offset > max_depth) {
- clear_vertex(v, g);
- modified = true;
- continue;
- }
-
- if (is_match_vertex(v, g)) {
- modified |= pruneOverlongReports(v, g, max_depth, rm);
- }
- }
-
- if (modified) {
- pruneUseless(g);
- DEBUG_PRINTF("pruned graph down to %zu vertices\n", num_vertices(g));
- }
-
- return modified;
-}
-
-/**
- * \brief Attempt to merge the set of DFAs given down into a single raw_dfa.
- * Returns false on failure.
- */
-static
-bool mergeDfas(vector<unique_ptr<raw_dfa>> &dfas, const ReportManager &rm,
- const CompileContext &cc) {
- assert(!dfas.empty());
-
- if (dfas.size() == 1) {
- return true;
- }
-
- DEBUG_PRINTF("attempting to merge %zu DFAs\n", dfas.size());
-
- vector<const raw_dfa *> dfa_ptrs;
- dfa_ptrs.reserve(dfas.size());
- for (auto &d : dfas) {
- dfa_ptrs.push_back(d.get());
- }
-
- auto merged = mergeAllDfas(dfa_ptrs, DFA_MERGE_MAX_STATES, &rm, cc.grey);
- if (!merged) {
- DEBUG_PRINTF("merge failed\n");
- return false;
- }
-
- DEBUG_PRINTF("merge succeeded, result has %zu states\n",
- merged->states.size());
- dfas.clear();
- dfas.push_back(std::move(merged));
- return true;
-}
-
-void SmallWriteBuildImpl::add(const NGHolder &g, const ExpressionInfo &expr) {
+void SmallWriteBuildImpl::add(const NGHolder &g, const ExpressionInfo &expr) {
// If the graph is poisoned (i.e. we can't build a SmallWrite version),
// we don't even try.
if (poisoned) {
return;
}
- if (expr.som) {
- DEBUG_PRINTF("no SOM support in small-write engine\n");
+ if (expr.som) {
+ DEBUG_PRINTF("no SOM support in small-write engine\n");
+ poisoned = true;
+ return;
+ }
+
+ if (isVacuous(g)) {
+ DEBUG_PRINTF("no vacuous graph support in small-write engine\n");
+ poisoned = true;
+ return;
+ }
+
+ if (any_of_in(::ue2::all_reports(g), [&](ReportID id) {
+ return rm.getReport(id).minLength > 0;
+ })) {
+ DEBUG_PRINTF("no min_length extparam support in small-write engine\n");
poisoned = true;
return;
}
- if (isVacuous(g)) {
- DEBUG_PRINTF("no vacuous graph support in small-write engine\n");
- poisoned = true;
- return;
- }
-
- if (any_of_in(::ue2::all_reports(g), [&](ReportID id) {
- return rm.getReport(id).minLength > 0;
- })) {
- DEBUG_PRINTF("no min_length extparam support in small-write engine\n");
- poisoned = true;
- return;
- }
-
- DEBUG_PRINTF("g=%p\n", &g);
-
+ DEBUG_PRINTF("g=%p\n", &g);
+
// make a copy of the graph so that we can modify it for our purposes
- unique_ptr<NGHolder> h = cloneHolder(g);
+ unique_ptr<NGHolder> h = cloneHolder(g);
- pruneOverlong(*h, depth(cc.grey.smallWriteLargestBuffer), rm);
+ pruneOverlong(*h, depth(cc.grey.smallWriteLargestBuffer), rm);
- reduceGraph(*h, SOM_NONE, expr.utf8, cc);
-
- if (can_never_match(*h)) {
- DEBUG_PRINTF("graph can never match in small block\n");
+ reduceGraph(*h, SOM_NONE, expr.utf8, cc);
+
+ if (can_never_match(*h)) {
+ DEBUG_PRINTF("graph can never match in small block\n");
return;
}
@@ -311,434 +311,434 @@ void SmallWriteBuildImpl::add(const NGHolder &g, const ExpressionInfo &expr) {
return;
}
- if (clear_deeper_reports(*r, cc.grey.smallWriteLargestBuffer)) {
- minimize_hopcroft(*r, cc.grey);
- }
+ if (clear_deeper_reports(*r, cc.grey.smallWriteLargestBuffer)) {
+ minimize_hopcroft(*r, cc.grey);
+ }
+
+ dfas.push_back(std::move(r));
- dfas.push_back(std::move(r));
-
- if (dfas.size() >= cc.grey.smallWriteMergeBatchSize) {
- if (!mergeDfas(dfas, rm, cc)) {
- dfas.clear();
+ if (dfas.size() >= cc.grey.smallWriteMergeBatchSize) {
+ if (!mergeDfas(dfas, rm, cc)) {
+ dfas.clear();
poisoned = true;
return;
}
}
}
-static
-bool add_to_trie(const ue2_literal &literal, ReportID report, LitTrie &trie) {
- auto u = trie.root;
- for (const auto &c : literal) {
- auto next = LitTrie::null_vertex();
- for (auto v : adjacent_vertices_range(u, trie)) {
- if (trie[v].c == (u8)c.c) {
- next = v;
- break;
- }
- }
- if (!next) {
- next = add_vertex(LitTrieVertexProps((u8)c.c), trie);
- add_edge(u, next, trie);
- }
- u = next;
- }
-
- trie[u].reports.insert(report);
-
- DEBUG_PRINTF("added '%s' (report %u) to trie, now %zu vertices\n",
- escapeString(literal).c_str(), report, num_vertices(trie));
- return num_vertices(trie) <= MAX_TRIE_VERTICES;
-}
-
+static
+bool add_to_trie(const ue2_literal &literal, ReportID report, LitTrie &trie) {
+ auto u = trie.root;
+ for (const auto &c : literal) {
+ auto next = LitTrie::null_vertex();
+ for (auto v : adjacent_vertices_range(u, trie)) {
+ if (trie[v].c == (u8)c.c) {
+ next = v;
+ break;
+ }
+ }
+ if (!next) {
+ next = add_vertex(LitTrieVertexProps((u8)c.c), trie);
+ add_edge(u, next, trie);
+ }
+ u = next;
+ }
+
+ trie[u].reports.insert(report);
+
+ DEBUG_PRINTF("added '%s' (report %u) to trie, now %zu vertices\n",
+ escapeString(literal).c_str(), report, num_vertices(trie));
+ return num_vertices(trie) <= MAX_TRIE_VERTICES;
+}
+
void SmallWriteBuildImpl::add(const ue2_literal &literal, ReportID r) {
// If the graph is poisoned (i.e. we can't build a SmallWrite version),
// we don't even try.
if (poisoned) {
- DEBUG_PRINTF("poisoned\n");
+ DEBUG_PRINTF("poisoned\n");
return;
}
if (literal.length() > cc.grey.smallWriteLargestBuffer) {
- DEBUG_PRINTF("exceeded length limit\n");
+ DEBUG_PRINTF("exceeded length limit\n");
return; /* too long */
}
- if (++num_literals > cc.grey.smallWriteMaxLiterals) {
- DEBUG_PRINTF("exceeded literal limit\n");
- poisoned = true;
- return;
- }
-
- auto &trie = literal.any_nocase() ? lit_trie_nocase : lit_trie;
- if (!add_to_trie(literal, r, trie)) {
- DEBUG_PRINTF("trie add failed\n");
- poisoned = true;
- }
+ if (++num_literals > cc.grey.smallWriteMaxLiterals) {
+ DEBUG_PRINTF("exceeded literal limit\n");
+ poisoned = true;
+ return;
+ }
+
+ auto &trie = literal.any_nocase() ? lit_trie_nocase : lit_trie;
+ if (!add_to_trie(literal, r, trie)) {
+ DEBUG_PRINTF("trie add failed\n");
+ poisoned = true;
+ }
}
-namespace {
-
-/**
- * \brief BFS visitor for Aho-Corasick automaton construction.
- *
- * This is doing two things:
- *
- * - Computing the failure edges (also called fall or supply edges) for each
- * vertex, giving the longest suffix of the path to that point that is also
- * a prefix in the trie reached on the same character. The BFS traversal
- * makes it possible to build these from earlier failure paths.
- *
- * - Computing the output function for each vertex, which is done by
- * propagating the reports from failure paths as well. This ensures that
- * substrings of the current path also report correctly.
- */
-struct ACVisitor : public boost::default_bfs_visitor {
- ACVisitor(LitTrie &trie_in,
- unordered_map<LitTrieVertex, LitTrieVertex> &failure_map_in,
- vector<LitTrieVertex> &ordering_in)
- : mutable_trie(trie_in), failure_map(failure_map_in),
- ordering(ordering_in) {}
-
- LitTrieVertex find_failure_target(LitTrieVertex u, LitTrieVertex v,
- const LitTrie &trie) {
- assert(u == trie.root || contains(failure_map, u));
- assert(!contains(failure_map, v));
-
- const auto &c = trie[v].c;
-
- while (u != trie.root) {
- auto f = failure_map.at(u);
- for (auto w : adjacent_vertices_range(f, trie)) {
- if (trie[w].c == c) {
- return w;
- }
- }
- u = f;
- }
-
- DEBUG_PRINTF("no failure edge\n");
- return LitTrie::null_vertex();
- }
-
- void tree_edge(LitTrieEdge e, const LitTrie &trie) {
- auto u = source(e, trie);
- auto v = target(e, trie);
- DEBUG_PRINTF("bfs (%zu, %zu) on '%c'\n", trie[u].index, trie[v].index,
- trie[v].c);
- ordering.push_back(v);
-
- auto f = find_failure_target(u, v, trie);
-
- if (f) {
- DEBUG_PRINTF("final failure vertex %zu\n", trie[f].index);
- failure_map.emplace(v, f);
-
- // Propagate reports from failure path to ensure we correctly
- // report substrings.
- insert(&mutable_trie[v].reports, mutable_trie[f].reports);
- } else {
- DEBUG_PRINTF("final failure vertex root\n");
- failure_map.emplace(v, trie.root);
- }
- }
-
-private:
- LitTrie &mutable_trie; //!< For setting reports property.
- unordered_map<LitTrieVertex, LitTrieVertex> &failure_map;
- vector<LitTrieVertex> &ordering; //!< BFS ordering for vertices.
-};
+namespace {
+
+/**
+ * \brief BFS visitor for Aho-Corasick automaton construction.
+ *
+ * This is doing two things:
+ *
+ * - Computing the failure edges (also called fall or supply edges) for each
+ * vertex, giving the longest suffix of the path to that point that is also
+ * a prefix in the trie reached on the same character. The BFS traversal
+ * makes it possible to build these from earlier failure paths.
+ *
+ * - Computing the output function for each vertex, which is done by
+ * propagating the reports from failure paths as well. This ensures that
+ * substrings of the current path also report correctly.
+ */
+struct ACVisitor : public boost::default_bfs_visitor {
+ ACVisitor(LitTrie &trie_in,
+ unordered_map<LitTrieVertex, LitTrieVertex> &failure_map_in,
+ vector<LitTrieVertex> &ordering_in)
+ : mutable_trie(trie_in), failure_map(failure_map_in),
+ ordering(ordering_in) {}
+
+ LitTrieVertex find_failure_target(LitTrieVertex u, LitTrieVertex v,
+ const LitTrie &trie) {
+ assert(u == trie.root || contains(failure_map, u));
+ assert(!contains(failure_map, v));
+
+ const auto &c = trie[v].c;
+
+ while (u != trie.root) {
+ auto f = failure_map.at(u);
+ for (auto w : adjacent_vertices_range(f, trie)) {
+ if (trie[w].c == c) {
+ return w;
+ }
+ }
+ u = f;
+ }
+
+ DEBUG_PRINTF("no failure edge\n");
+ return LitTrie::null_vertex();
+ }
+
+ void tree_edge(LitTrieEdge e, const LitTrie &trie) {
+ auto u = source(e, trie);
+ auto v = target(e, trie);
+ DEBUG_PRINTF("bfs (%zu, %zu) on '%c'\n", trie[u].index, trie[v].index,
+ trie[v].c);
+ ordering.push_back(v);
+
+ auto f = find_failure_target(u, v, trie);
+
+ if (f) {
+ DEBUG_PRINTF("final failure vertex %zu\n", trie[f].index);
+ failure_map.emplace(v, f);
+
+ // Propagate reports from failure path to ensure we correctly
+ // report substrings.
+ insert(&mutable_trie[v].reports, mutable_trie[f].reports);
+ } else {
+ DEBUG_PRINTF("final failure vertex root\n");
+ failure_map.emplace(v, trie.root);
+ }
+ }
+
+private:
+ LitTrie &mutable_trie; //!< For setting reports property.
+ unordered_map<LitTrieVertex, LitTrieVertex> &failure_map;
+ vector<LitTrieVertex> &ordering; //!< BFS ordering for vertices.
+};
}
-static UNUSED
-bool isSaneTrie(const LitTrie &trie) {
- CharReach seen;
- for (auto u : vertices_range(trie)) {
- seen.clear();
- for (auto v : adjacent_vertices_range(u, trie)) {
- if (seen.test(trie[v].c)) {
- return false;
- }
- seen.set(trie[v].c);
- }
- }
- return true;
-}
-
-/**
- * \brief Turn the given literal trie into an AC automaton by adding additional
- * edges and reports.
- */
-static
-void buildAutomaton(LitTrie &trie,
- unordered_map<LitTrieVertex, LitTrieVertex> &failure_map,
- vector<LitTrieVertex> &ordering) {
- assert(isSaneTrie(trie));
-
- // Find our failure transitions and reports.
- failure_map.reserve(num_vertices(trie));
- ordering.reserve(num_vertices(trie));
- ACVisitor ac_vis(trie, failure_map, ordering);
- boost::breadth_first_search(trie, trie.root, visitor(ac_vis));
-
- // Compute missing edges from failure map.
- for (auto v : ordering) {
- DEBUG_PRINTF("vertex %zu\n", trie[v].index);
- CharReach seen;
- for (auto w : adjacent_vertices_range(v, trie)) {
- DEBUG_PRINTF("edge to %zu with reach 0x%02x\n", trie[w].index,
- trie[w].c);
- assert(!seen.test(trie[w].c));
- seen.set(trie[w].c);
- }
- auto parent = failure_map.at(v);
- for (auto w : adjacent_vertices_range(parent, trie)) {
- if (!seen.test(trie[w].c)) {
- add_edge(v, w, trie);
- }
- }
- }
-}
-
-static
-vector<u32> findDistFromRoot(const LitTrie &trie) {
- vector<u32> dist(num_vertices(trie), UINT32_MAX);
- dist[trie[trie.root].index] = 0;
-
- // BFS to find dist from root.
- breadth_first_search(
- trie, trie.root,
- visitor(make_bfs_visitor(record_distances(
- make_iterator_property_map(dist.begin(),
- get(&LitTrieVertexProps::index, trie)),
- boost::on_tree_edge()))));
-
- return dist;
-}
-
-static
-vector<u32> findDistToAccept(const LitTrie &trie) {
- vector<u32> dist(num_vertices(trie), UINT32_MAX);
-
- // Start with all reporting vertices.
- deque<LitTrieVertex> q;
- for (auto v : vertices_range(trie)) {
- if (!trie[v].reports.empty()) {
- q.push_back(v);
- dist[trie[v].index] = 0;
+static UNUSED
+bool isSaneTrie(const LitTrie &trie) {
+ CharReach seen;
+ for (auto u : vertices_range(trie)) {
+ seen.clear();
+ for (auto v : adjacent_vertices_range(u, trie)) {
+ if (seen.test(trie[v].c)) {
+ return false;
+ }
+ seen.set(trie[v].c);
}
}
+ return true;
+}
+
+/**
+ * \brief Turn the given literal trie into an AC automaton by adding additional
+ * edges and reports.
+ */
+static
+void buildAutomaton(LitTrie &trie,
+ unordered_map<LitTrieVertex, LitTrieVertex> &failure_map,
+ vector<LitTrieVertex> &ordering) {
+ assert(isSaneTrie(trie));
+
+ // Find our failure transitions and reports.
+ failure_map.reserve(num_vertices(trie));
+ ordering.reserve(num_vertices(trie));
+ ACVisitor ac_vis(trie, failure_map, ordering);
+ boost::breadth_first_search(trie, trie.root, visitor(ac_vis));
+
+ // Compute missing edges from failure map.
+ for (auto v : ordering) {
+ DEBUG_PRINTF("vertex %zu\n", trie[v].index);
+ CharReach seen;
+ for (auto w : adjacent_vertices_range(v, trie)) {
+ DEBUG_PRINTF("edge to %zu with reach 0x%02x\n", trie[w].index,
+ trie[w].c);
+ assert(!seen.test(trie[w].c));
+ seen.set(trie[w].c);
+ }
+ auto parent = failure_map.at(v);
+ for (auto w : adjacent_vertices_range(parent, trie)) {
+ if (!seen.test(trie[w].c)) {
+ add_edge(v, w, trie);
+ }
+ }
+ }
+}
+
+static
+vector<u32> findDistFromRoot(const LitTrie &trie) {
+ vector<u32> dist(num_vertices(trie), UINT32_MAX);
+ dist[trie[trie.root].index] = 0;
+
+ // BFS to find dist from root.
+ breadth_first_search(
+ trie, trie.root,
+ visitor(make_bfs_visitor(record_distances(
+ make_iterator_property_map(dist.begin(),
+ get(&LitTrieVertexProps::index, trie)),
+ boost::on_tree_edge()))));
+
+ return dist;
+}
- // Custom BFS, since we have a pile of sources.
- while (!q.empty()) {
- auto v = q.front();
- q.pop_front();
- u32 d = dist[trie[v].index];
-
- for (auto u : inv_adjacent_vertices_range(v, trie)) {
- auto &u_dist = dist[trie[u].index];
- if (u_dist == UINT32_MAX) {
- q.push_back(u);
- u_dist = d + 1;
- }
- }
- }
-
- return dist;
-}
-
-/**
- * \brief Prune all vertices from the trie that do not lie on a path from root
- * to accept of length <= max_depth.
- */
-static
-void pruneTrie(LitTrie &trie, u32 max_depth) {
- DEBUG_PRINTF("pruning trie to %u\n", max_depth);
-
- auto dist_from_root = findDistFromRoot(trie);
- auto dist_to_accept = findDistToAccept(trie);
-
- vector<LitTrieVertex> dead;
- for (auto v : vertices_range(trie)) {
- if (v == trie.root) {
- continue;
- }
- auto v_index = trie[v].index;
- DEBUG_PRINTF("vertex %zu: from_start=%u, to_accept=%u\n", trie[v].index,
- dist_from_root[v_index], dist_to_accept[v_index]);
- assert(dist_from_root[v_index] != UINT32_MAX);
- assert(dist_to_accept[v_index] != UINT32_MAX);
- u32 min_path_len = dist_from_root[v_index] + dist_to_accept[v_index];
- if (min_path_len > max_depth) {
- DEBUG_PRINTF("pruning vertex %zu (min path len %u)\n",
- trie[v].index, min_path_len);
- clear_vertex(v, trie);
- dead.push_back(v);
- }
- }
-
- if (dead.empty()) {
- return;
- }
-
- for (auto v : dead) {
- remove_vertex(v, trie);
- }
-
- DEBUG_PRINTF("%zu vertices remain\n", num_vertices(trie));
-
- renumber_edges(trie);
- renumber_vertices(trie);
-}
-
-static
-vector<CharReach> getAlphabet(const LitTrie &trie, bool nocase) {
- vector<CharReach> esets = {CharReach::dot()};
- for (auto v : vertices_range(trie)) {
- if (v == trie.root) {
- continue;
+static
+vector<u32> findDistToAccept(const LitTrie &trie) {
+ vector<u32> dist(num_vertices(trie), UINT32_MAX);
+
+ // Start with all reporting vertices.
+ deque<LitTrieVertex> q;
+ for (auto v : vertices_range(trie)) {
+ if (!trie[v].reports.empty()) {
+ q.push_back(v);
+ dist[trie[v].index] = 0;
}
+ }
- CharReach cr;
- if (nocase) {
- cr.set(mytoupper(trie[v].c));
- cr.set(mytolower(trie[v].c));
- } else {
- cr.set(trie[v].c);
- }
-
- for (size_t i = 0; i < esets.size(); i++) {
- if (esets[i].count() == 1) {
- continue;
- }
-
- CharReach t = cr & esets[i];
- if (t.any() && t != esets[i]) {
- esets[i] &= ~t;
- esets.push_back(t);
- }
- }
- }
-
- // For deterministic compiles.
- sort(esets.begin(), esets.end());
- return esets;
-}
-
-static
-u16 buildAlphabet(const LitTrie &trie, bool nocase,
- array<u16, ALPHABET_SIZE> &alpha,
- array<u16, ALPHABET_SIZE> &unalpha) {
- const auto &esets = getAlphabet(trie, nocase);
-
- u16 i = 0;
- for (const auto &cr : esets) {
- u16 leader = cr.find_first();
- for (size_t s = cr.find_first(); s != cr.npos; s = cr.find_next(s)) {
- alpha[s] = i;
- }
- unalpha[i] = leader;
- i++;
- }
-
- for (u16 j = N_CHARS; j < ALPHABET_SIZE; j++, i++) {
- alpha[j] = i;
- unalpha[i] = j;
- }
-
- DEBUG_PRINTF("alphabet size %u\n", i);
- return i;
-}
-
-/**
- * \brief Calculate state mapping, from vertex in trie to state index in BFS
- * ordering.
- */
-static
-unordered_map<LitTrieVertex, u32>
-makeStateMap(const LitTrie &trie, const vector<LitTrieVertex> &ordering) {
- unordered_map<LitTrieVertex, u32> state_ids;
- state_ids.reserve(num_vertices(trie));
- u32 idx = DEAD_STATE + 1;
- state_ids.emplace(trie.root, idx++);
- for (auto v : ordering) {
- state_ids.emplace(v, idx++);
- }
- assert(state_ids.size() == num_vertices(trie));
- return state_ids;
+ // Custom BFS, since we have a pile of sources.
+ while (!q.empty()) {
+ auto v = q.front();
+ q.pop_front();
+ u32 d = dist[trie[v].index];
+
+ for (auto u : inv_adjacent_vertices_range(v, trie)) {
+ auto &u_dist = dist[trie[u].index];
+ if (u_dist == UINT32_MAX) {
+ q.push_back(u);
+ u_dist = d + 1;
+ }
+ }
+ }
+
+ return dist;
+}
+
+/**
+ * \brief Prune all vertices from the trie that do not lie on a path from root
+ * to accept of length <= max_depth.
+ */
+static
+void pruneTrie(LitTrie &trie, u32 max_depth) {
+ DEBUG_PRINTF("pruning trie to %u\n", max_depth);
+
+ auto dist_from_root = findDistFromRoot(trie);
+ auto dist_to_accept = findDistToAccept(trie);
+
+ vector<LitTrieVertex> dead;
+ for (auto v : vertices_range(trie)) {
+ if (v == trie.root) {
+ continue;
+ }
+ auto v_index = trie[v].index;
+ DEBUG_PRINTF("vertex %zu: from_start=%u, to_accept=%u\n", trie[v].index,
+ dist_from_root[v_index], dist_to_accept[v_index]);
+ assert(dist_from_root[v_index] != UINT32_MAX);
+ assert(dist_to_accept[v_index] != UINT32_MAX);
+ u32 min_path_len = dist_from_root[v_index] + dist_to_accept[v_index];
+ if (min_path_len > max_depth) {
+ DEBUG_PRINTF("pruning vertex %zu (min path len %u)\n",
+ trie[v].index, min_path_len);
+ clear_vertex(v, trie);
+ dead.push_back(v);
+ }
+ }
+
+ if (dead.empty()) {
+ return;
+ }
+
+ for (auto v : dead) {
+ remove_vertex(v, trie);
+ }
+
+ DEBUG_PRINTF("%zu vertices remain\n", num_vertices(trie));
+
+ renumber_edges(trie);
+ renumber_vertices(trie);
+}
+
+static
+vector<CharReach> getAlphabet(const LitTrie &trie, bool nocase) {
+ vector<CharReach> esets = {CharReach::dot()};
+ for (auto v : vertices_range(trie)) {
+ if (v == trie.root) {
+ continue;
+ }
+
+ CharReach cr;
+ if (nocase) {
+ cr.set(mytoupper(trie[v].c));
+ cr.set(mytolower(trie[v].c));
+ } else {
+ cr.set(trie[v].c);
+ }
+
+ for (size_t i = 0; i < esets.size(); i++) {
+ if (esets[i].count() == 1) {
+ continue;
+ }
+
+ CharReach t = cr & esets[i];
+ if (t.any() && t != esets[i]) {
+ esets[i] &= ~t;
+ esets.push_back(t);
+ }
+ }
+ }
+
+ // For deterministic compiles.
+ sort(esets.begin(), esets.end());
+ return esets;
+}
+
+static
+u16 buildAlphabet(const LitTrie &trie, bool nocase,
+ array<u16, ALPHABET_SIZE> &alpha,
+ array<u16, ALPHABET_SIZE> &unalpha) {
+ const auto &esets = getAlphabet(trie, nocase);
+
+ u16 i = 0;
+ for (const auto &cr : esets) {
+ u16 leader = cr.find_first();
+ for (size_t s = cr.find_first(); s != cr.npos; s = cr.find_next(s)) {
+ alpha[s] = i;
+ }
+ unalpha[i] = leader;
+ i++;
+ }
+
+ for (u16 j = N_CHARS; j < ALPHABET_SIZE; j++, i++) {
+ alpha[j] = i;
+ unalpha[i] = j;
+ }
+
+ DEBUG_PRINTF("alphabet size %u\n", i);
+ return i;
+}
+
+/**
+ * \brief Calculate state mapping, from vertex in trie to state index in BFS
+ * ordering.
+ */
+static
+unordered_map<LitTrieVertex, u32>
+makeStateMap(const LitTrie &trie, const vector<LitTrieVertex> &ordering) {
+ unordered_map<LitTrieVertex, u32> state_ids;
+ state_ids.reserve(num_vertices(trie));
+ u32 idx = DEAD_STATE + 1;
+ state_ids.emplace(trie.root, idx++);
+ for (auto v : ordering) {
+ state_ids.emplace(v, idx++);
+ }
+ assert(state_ids.size() == num_vertices(trie));
+ return state_ids;
+}
+
+/** \brief Construct a raw_dfa from a literal trie. */
+static
+unique_ptr<raw_dfa> buildDfa(LitTrie &trie, bool nocase) {
+ DEBUG_PRINTF("trie has %zu states\n", num_vertices(trie));
+
+ vector<LitTrieVertex> ordering;
+ unordered_map<LitTrieVertex, LitTrieVertex> failure_map;
+ buildAutomaton(trie, failure_map, ordering);
+
+ // Construct DFA states in BFS order.
+ const auto state_ids = makeStateMap(trie, ordering);
+
+ auto rdfa = std::make_unique<raw_dfa>(NFA_OUTFIX);
+
+ // Calculate alphabet.
+ array<u16, ALPHABET_SIZE> unalpha;
+ auto &alpha = rdfa->alpha_remap;
+ rdfa->alpha_size = buildAlphabet(trie, nocase, alpha, unalpha);
+
+ // Construct states and transitions.
+ const u16 root_state = state_ids.at(trie.root);
+ assert(root_state == DEAD_STATE + 1);
+ rdfa->start_anchored = root_state;
+ rdfa->start_floating = root_state;
+ rdfa->states.resize(num_vertices(trie) + 1, dstate(rdfa->alpha_size));
+
+ // Dead state.
+ fill(rdfa->states[DEAD_STATE].next.begin(),
+ rdfa->states[DEAD_STATE].next.end(), DEAD_STATE);
+
+ for (auto u : vertices_range(trie)) {
+ auto u_state = state_ids.at(u);
+ DEBUG_PRINTF("state %u\n", u_state);
+ assert(u_state < rdfa->states.size());
+ auto &ds = rdfa->states[u_state];
+ ds.reports = trie[u].reports;
+ if (!ds.reports.empty()) {
+ DEBUG_PRINTF("reports: %s\n", as_string_list(ds.reports).c_str());
+ }
+
+ // Set daddy state from failure map.
+ if (u == trie.root) {
+ ds.daddy = DEAD_STATE;
+ } else {
+ assert(contains(failure_map, u));
+ ds.daddy = state_ids.at(failure_map.at(u));
+ }
+
+ // By default, transition back to the root.
+ fill(ds.next.begin(), ds.next.end(), root_state);
+ // TOP should be a self-loop.
+ ds.next[alpha[TOP]] = u_state;
+
+ // Add in the real transitions.
+ for (auto v : adjacent_vertices_range(u, trie)) {
+ if (v == trie.root) {
+ continue;
+ }
+ auto v_state = state_ids.at(v);
+ u16 sym = alpha[trie[v].c];
+ DEBUG_PRINTF("edge to %u on 0x%02x (sym %u)\n", v_state,
+ trie[v].c, sym);
+ assert(sym < ds.next.size());
+ assert(ds.next[sym] == root_state);
+ ds.next[sym] = v_state;
+ }
+ }
+
+ return rdfa;
}
-/** \brief Construct a raw_dfa from a literal trie. */
-static
-unique_ptr<raw_dfa> buildDfa(LitTrie &trie, bool nocase) {
- DEBUG_PRINTF("trie has %zu states\n", num_vertices(trie));
-
- vector<LitTrieVertex> ordering;
- unordered_map<LitTrieVertex, LitTrieVertex> failure_map;
- buildAutomaton(trie, failure_map, ordering);
-
- // Construct DFA states in BFS order.
- const auto state_ids = makeStateMap(trie, ordering);
-
- auto rdfa = std::make_unique<raw_dfa>(NFA_OUTFIX);
-
- // Calculate alphabet.
- array<u16, ALPHABET_SIZE> unalpha;
- auto &alpha = rdfa->alpha_remap;
- rdfa->alpha_size = buildAlphabet(trie, nocase, alpha, unalpha);
-
- // Construct states and transitions.
- const u16 root_state = state_ids.at(trie.root);
- assert(root_state == DEAD_STATE + 1);
- rdfa->start_anchored = root_state;
- rdfa->start_floating = root_state;
- rdfa->states.resize(num_vertices(trie) + 1, dstate(rdfa->alpha_size));
-
- // Dead state.
- fill(rdfa->states[DEAD_STATE].next.begin(),
- rdfa->states[DEAD_STATE].next.end(), DEAD_STATE);
-
- for (auto u : vertices_range(trie)) {
- auto u_state = state_ids.at(u);
- DEBUG_PRINTF("state %u\n", u_state);
- assert(u_state < rdfa->states.size());
- auto &ds = rdfa->states[u_state];
- ds.reports = trie[u].reports;
- if (!ds.reports.empty()) {
- DEBUG_PRINTF("reports: %s\n", as_string_list(ds.reports).c_str());
- }
-
- // Set daddy state from failure map.
- if (u == trie.root) {
- ds.daddy = DEAD_STATE;
- } else {
- assert(contains(failure_map, u));
- ds.daddy = state_ids.at(failure_map.at(u));
- }
-
- // By default, transition back to the root.
- fill(ds.next.begin(), ds.next.end(), root_state);
- // TOP should be a self-loop.
- ds.next[alpha[TOP]] = u_state;
-
- // Add in the real transitions.
- for (auto v : adjacent_vertices_range(u, trie)) {
- if (v == trie.root) {
- continue;
- }
- auto v_state = state_ids.at(v);
- u16 sym = alpha[trie[v].c];
- DEBUG_PRINTF("edge to %u on 0x%02x (sym %u)\n", v_state,
- trie[v].c, sym);
- assert(sym < ds.next.size());
- assert(ds.next[sym] == root_state);
- ds.next[sym] = v_state;
- }
- }
-
- return rdfa;
-}
-
#define MAX_GOOD_ACCEL_DEPTH 4
static
@@ -782,72 +782,72 @@ bool is_slow(const raw_dfa &rdfa, const set<dstate_id_t> &accel,
}
static
-bytecode_ptr<NFA> getDfa(raw_dfa &rdfa, const CompileContext &cc,
- const ReportManager &rm, bool has_non_literals,
- set<dstate_id_t> &accel_states) {
- // If we determinised only literals, then we only need to consider the init
- // states for acceleration.
- bool only_accel_init = !has_non_literals;
- bool trust_daddy_states = !has_non_literals;
-
- bytecode_ptr<NFA> dfa = nullptr;
- if (cc.grey.allowSmallWriteSheng) {
- dfa = shengCompile(rdfa, cc, rm, only_accel_init, &accel_states);
+bytecode_ptr<NFA> getDfa(raw_dfa &rdfa, const CompileContext &cc,
+ const ReportManager &rm, bool has_non_literals,
+ set<dstate_id_t> &accel_states) {
+ // If we determinised only literals, then we only need to consider the init
+ // states for acceleration.
+ bool only_accel_init = !has_non_literals;
+ bool trust_daddy_states = !has_non_literals;
+
+ bytecode_ptr<NFA> dfa = nullptr;
+ if (cc.grey.allowSmallWriteSheng) {
+ dfa = shengCompile(rdfa, cc, rm, only_accel_init, &accel_states);
if (!dfa) {
dfa = sheng32Compile(rdfa, cc, rm, only_accel_init, &accel_states);
}
if (!dfa) {
dfa = sheng64Compile(rdfa, cc, rm, only_accel_init, &accel_states);
}
- }
- if (!dfa) {
- dfa = mcclellanCompile(rdfa, cc, rm, only_accel_init,
- trust_daddy_states, &accel_states);
- }
- return dfa;
-}
-
-static
-bytecode_ptr<NFA> prepEngine(raw_dfa &rdfa, u32 roseQuality,
- const CompileContext &cc, const ReportManager &rm,
- bool has_non_literals, u32 *start_offset,
- u32 *small_region) {
+ }
+ if (!dfa) {
+ dfa = mcclellanCompile(rdfa, cc, rm, only_accel_init,
+ trust_daddy_states, &accel_states);
+ }
+ return dfa;
+}
+
+static
+bytecode_ptr<NFA> prepEngine(raw_dfa &rdfa, u32 roseQuality,
+ const CompileContext &cc, const ReportManager &rm,
+ bool has_non_literals, u32 *start_offset,
+ u32 *small_region) {
*start_offset = remove_leading_dots(rdfa);
// Unleash the McClellan!
set<dstate_id_t> accel_states;
- auto nfa = getDfa(rdfa, cc, rm, has_non_literals, accel_states);
+ auto nfa = getDfa(rdfa, cc, rm, has_non_literals, accel_states);
if (!nfa) {
- DEBUG_PRINTF("DFA compile failed for smallwrite NFA\n");
+ DEBUG_PRINTF("DFA compile failed for smallwrite NFA\n");
return nullptr;
}
if (is_slow(rdfa, accel_states, roseQuality)) {
- DEBUG_PRINTF("is slow\n");
+ DEBUG_PRINTF("is slow\n");
*small_region = cc.grey.smallWriteLargestBufferBad;
if (*small_region <= *start_offset) {
return nullptr;
}
- if (clear_deeper_reports(rdfa, *small_region - *start_offset)) {
- minimize_hopcroft(rdfa, cc.grey);
- if (rdfa.start_anchored == DEAD_STATE) {
- DEBUG_PRINTF("all patterns pruned out\n");
- return nullptr;
- }
-
- nfa = getDfa(rdfa, cc, rm, has_non_literals, accel_states);
- if (!nfa) {
- DEBUG_PRINTF("DFA compile failed for smallwrite NFA\n");
- assert(0); /* able to build orig dfa but not the trimmed? */
- return nullptr;
- }
+ if (clear_deeper_reports(rdfa, *small_region - *start_offset)) {
+ minimize_hopcroft(rdfa, cc.grey);
+ if (rdfa.start_anchored == DEAD_STATE) {
+ DEBUG_PRINTF("all patterns pruned out\n");
+ return nullptr;
+ }
+
+ nfa = getDfa(rdfa, cc, rm, has_non_literals, accel_states);
+ if (!nfa) {
+ DEBUG_PRINTF("DFA compile failed for smallwrite NFA\n");
+ assert(0); /* able to build orig dfa but not the trimmed? */
+ return nullptr;
+ }
}
} else {
*small_region = cc.grey.smallWriteLargestBuffer;
}
- assert(isDfaType(nfa->type));
+ assert(isDfaType(nfa->type));
if (nfa->length > cc.grey.limitSmallWriteOutfixSize
|| nfa->length > cc.grey.limitDFASize) {
DEBUG_PRINTF("smallwrite outfix size too large\n");
@@ -859,16 +859,16 @@ bytecode_ptr<NFA> prepEngine(raw_dfa &rdfa, u32 roseQuality,
}
// SmallWriteBuild factory
-unique_ptr<SmallWriteBuild> makeSmallWriteBuilder(size_t num_patterns,
- const ReportManager &rm,
+unique_ptr<SmallWriteBuild> makeSmallWriteBuilder(size_t num_patterns,
+ const ReportManager &rm,
const CompileContext &cc) {
- return ue2::make_unique<SmallWriteBuildImpl>(num_patterns, rm, cc);
+ return ue2::make_unique<SmallWriteBuildImpl>(num_patterns, rm, cc);
}
-bytecode_ptr<SmallWriteEngine> SmallWriteBuildImpl::build(u32 roseQuality) {
- const bool has_literals = !is_empty(lit_trie) || !is_empty(lit_trie_nocase);
- const bool has_non_literals = !dfas.empty();
- if (dfas.empty() && !has_literals) {
+bytecode_ptr<SmallWriteEngine> SmallWriteBuildImpl::build(u32 roseQuality) {
+ const bool has_literals = !is_empty(lit_trie) || !is_empty(lit_trie_nocase);
+ const bool has_non_literals = !dfas.empty();
+ if (dfas.empty() && !has_literals) {
DEBUG_PRINTF("no smallwrite engine\n");
poisoned = true;
return nullptr;
@@ -879,49 +879,49 @@ bytecode_ptr<SmallWriteEngine> SmallWriteBuildImpl::build(u32 roseQuality) {
return nullptr;
}
- // We happen to know that if the rose is high quality, we're going to limit
- // depth further.
- if (roseQuality) {
- u32 max_depth = cc.grey.smallWriteLargestBufferBad;
- if (!is_empty(lit_trie)) {
- pruneTrie(lit_trie, max_depth);
- }
- if (!is_empty(lit_trie_nocase)) {
- pruneTrie(lit_trie_nocase, max_depth);
- }
- }
-
- if (!is_empty(lit_trie)) {
- dfas.push_back(buildDfa(lit_trie, false));
- DEBUG_PRINTF("caseful literal dfa with %zu states\n",
- dfas.back()->states.size());
- }
- if (!is_empty(lit_trie_nocase)) {
- dfas.push_back(buildDfa(lit_trie_nocase, true));
- DEBUG_PRINTF("nocase literal dfa with %zu states\n",
- dfas.back()->states.size());
- }
-
- if (dfas.empty()) {
- DEBUG_PRINTF("no dfa, pruned everything away\n");
+ // We happen to know that if the rose is high quality, we're going to limit
+ // depth further.
+ if (roseQuality) {
+ u32 max_depth = cc.grey.smallWriteLargestBufferBad;
+ if (!is_empty(lit_trie)) {
+ pruneTrie(lit_trie, max_depth);
+ }
+ if (!is_empty(lit_trie_nocase)) {
+ pruneTrie(lit_trie_nocase, max_depth);
+ }
+ }
+
+ if (!is_empty(lit_trie)) {
+ dfas.push_back(buildDfa(lit_trie, false));
+ DEBUG_PRINTF("caseful literal dfa with %zu states\n",
+ dfas.back()->states.size());
+ }
+ if (!is_empty(lit_trie_nocase)) {
+ dfas.push_back(buildDfa(lit_trie_nocase, true));
+ DEBUG_PRINTF("nocase literal dfa with %zu states\n",
+ dfas.back()->states.size());
+ }
+
+ if (dfas.empty()) {
+ DEBUG_PRINTF("no dfa, pruned everything away\n");
+ return nullptr;
+ }
+
+ if (!mergeDfas(dfas, rm, cc)) {
+ dfas.clear();
return nullptr;
}
- if (!mergeDfas(dfas, rm, cc)) {
- dfas.clear();
- return nullptr;
- }
-
- assert(dfas.size() == 1);
- auto rdfa = std::move(dfas.front());
- dfas.clear();
-
+ assert(dfas.size() == 1);
+ auto rdfa = std::move(dfas.front());
+ dfas.clear();
+
DEBUG_PRINTF("building rdfa %p\n", rdfa.get());
u32 start_offset;
u32 small_region;
- auto nfa = prepEngine(*rdfa, roseQuality, cc, rm, has_non_literals,
- &start_offset, &small_region);
+ auto nfa = prepEngine(*rdfa, roseQuality, cc, rm, has_non_literals,
+ &start_offset, &small_region);
if (!nfa) {
DEBUG_PRINTF("some smallwrite outfix could not be prepped\n");
/* just skip the smallwrite optimization */
@@ -930,7 +930,7 @@ bytecode_ptr<SmallWriteEngine> SmallWriteBuildImpl::build(u32 roseQuality) {
}
u32 size = sizeof(SmallWriteEngine) + nfa->length;
- auto smwr = make_zeroed_bytecode_ptr<SmallWriteEngine>(size);
+ auto smwr = make_zeroed_bytecode_ptr<SmallWriteEngine>(size);
smwr->size = size;
smwr->start_offset = start_offset;
@@ -944,20 +944,20 @@ bytecode_ptr<SmallWriteEngine> SmallWriteBuildImpl::build(u32 roseQuality) {
return smwr;
}
-set<ReportID> SmallWriteBuildImpl::all_reports() const {
- set<ReportID> reports;
- if (poisoned) {
- return reports;
- }
-
- for (const auto &rdfa : dfas) {
- insert(&reports, ::ue2::all_reports(*rdfa));
- }
-
- insert(&reports, ::ue2::all_reports(lit_trie));
- insert(&reports, ::ue2::all_reports(lit_trie_nocase));
-
- return reports;
+set<ReportID> SmallWriteBuildImpl::all_reports() const {
+ set<ReportID> reports;
+ if (poisoned) {
+ return reports;
+ }
+
+ for (const auto &rdfa : dfas) {
+ insert(&reports, ::ue2::all_reports(*rdfa));
+ }
+
+ insert(&reports, ::ue2::all_reports(lit_trie));
+ insert(&reports, ::ue2::all_reports(lit_trie_nocase));
+
+ return reports;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.h b/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.h
index 436c5181c78..648b13db794 100644
--- a/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.h
+++ b/contrib/libs/hyperscan/src/smallwrite/smallwrite_build.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,19 +30,19 @@
#define SMWR_BUILD_H
/**
- * \file
- * \brief Small-write engine build interface.
- *
- * Everything you ever needed to feed literals in and get a SmallWriteEngine
- * out. This header should be everything needed by the rest of UE2.
+ * \file
+ * \brief Small-write engine build interface.
+ *
+ * Everything you ever needed to feed literals in and get a SmallWriteEngine
+ * out. This header should be everything needed by the rest of UE2.
*/
#include "ue2common.h"
-#include "util/bytecode_ptr.h"
-#include "util/noncopyable.h"
+#include "util/bytecode_ptr.h"
+#include "util/noncopyable.h"
-#include <memory>
-#include <set>
+#include <memory>
+#include <set>
struct SmallWriteEngine;
@@ -50,30 +50,30 @@ namespace ue2 {
struct CompileContext;
struct ue2_literal;
-class ExpressionInfo;
-class NGHolder;
-class ReportManager;
+class ExpressionInfo;
+class NGHolder;
+class ReportManager;
-/**
- * Abstract interface intended for callers from elsewhere in the tree, real
- * underlying implementation is SmallWriteBuildImpl in smwr_build_impl.h.
- */
-class SmallWriteBuild : noncopyable {
+/**
+ * Abstract interface intended for callers from elsewhere in the tree, real
+ * underlying implementation is SmallWriteBuildImpl in smwr_build_impl.h.
+ */
+class SmallWriteBuild : noncopyable {
public:
virtual ~SmallWriteBuild();
- virtual bytecode_ptr<SmallWriteEngine> build(u32 roseQuality) = 0;
+ virtual bytecode_ptr<SmallWriteEngine> build(u32 roseQuality) = 0;
- virtual void add(const NGHolder &g, const ExpressionInfo &expr) = 0;
+ virtual void add(const NGHolder &g, const ExpressionInfo &expr) = 0;
virtual void add(const ue2_literal &literal, ReportID r) = 0;
-
- virtual std::set<ReportID> all_reports() const = 0;
+
+ virtual std::set<ReportID> all_reports() const = 0;
};
-/** \brief Construct a usable SmallWrite builder. */
-std::unique_ptr<SmallWriteBuild>
-makeSmallWriteBuilder(size_t num_patterns, const ReportManager &rm,
- const CompileContext &cc);
+/** \brief Construct a usable SmallWrite builder. */
+std::unique_ptr<SmallWriteBuild>
+makeSmallWriteBuilder(size_t num_patterns, const ReportManager &rm,
+ const CompileContext &cc);
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/som/slot_manager.cpp b/contrib/libs/hyperscan/src/som/slot_manager.cpp
index ec7f8cbdc56..d97e8fc1d7e 100644
--- a/contrib/libs/hyperscan/src/som/slot_manager.cpp
+++ b/contrib/libs/hyperscan/src/som/slot_manager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,11 +26,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief SOM Slot Manager.
*/
-
+
#include "slot_manager.h"
#include "slot_manager_internal.h"
@@ -40,7 +40,7 @@
#include "nfagraph/ng_som_util.h"
#include "nfagraph/ng_region.h"
#include "util/charreach.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include "util/make_unique.h"
#include "util/dump_charclass.h"
#include "util/verify_types.h"
@@ -66,8 +66,8 @@ SlotCacheEntry::SlotCacheEntry(const NGHolder &prefix_in,
size_t SlotEntryHasher::operator()(const SlotCacheEntry &e) const {
assert(e.prefix);
- size_t v = hash_all(hash_holder(*e.prefix), e.parent_slot,
- e.is_reset, e.escapes);
+ size_t v = hash_all(hash_holder(*e.prefix), e.parent_slot,
+ e.is_reset, e.escapes);
DEBUG_PRINTF("%zu vertices, parent_slot=%u, escapes=%s, is_reset=%d "
"hashes to %zx\n", num_vertices(*e.prefix), e.parent_slot,
@@ -137,7 +137,7 @@ u32 SomSlotManager::getSomSlot(const NGHolder &prefix,
u32 SomSlotManager::getInitialResetSomSlot(const NGHolder &prefix,
const NGHolder &g,
- const unordered_map<NFAVertex, u32> &region_map,
+ const unordered_map<NFAVertex, u32> &region_map,
u32 last_sent_region, bool *prefix_already_implemented) {
DEBUG_PRINTF("getting initial reset; last sent region %u\n",
last_sent_region);
@@ -165,9 +165,9 @@ u32 SomSlotManager::getInitialResetSomSlot(const NGHolder &prefix,
// Clone a copy of g (and its region map) that we will be able to store
// later on.
shared_ptr<NGHolder> gg = make_shared<NGHolder>();
- unordered_map<NFAVertex, NFAVertex> orig_to_copy;
+ unordered_map<NFAVertex, NFAVertex> orig_to_copy;
cloneHolder(*gg, g, &orig_to_copy);
- unordered_map<NFAVertex, u32> gg_region_map;
+ unordered_map<NFAVertex, u32> gg_region_map;
for (const auto &m : region_map) {
assert(contains(region_map, m.first));
gg_region_map.emplace(orig_to_copy.at(m.first), m.second);
@@ -241,7 +241,7 @@ u32 SomSlotManager::numSomSlots() const {
return nextSomSlot;
}
-u32 SomSlotManager::addRevNfa(bytecode_ptr<NFA> nfa, u32 maxWidth) {
+u32 SomSlotManager::addRevNfa(bytecode_ptr<NFA> nfa, u32 maxWidth) {
u32 rv = verify_u32(rev_nfas.size());
rev_nfas.push_back(move(nfa));
diff --git a/contrib/libs/hyperscan/src/som/slot_manager.h b/contrib/libs/hyperscan/src/som/slot_manager.h
index 84e2632feab..e5b2d794c07 100644
--- a/contrib/libs/hyperscan/src/som/slot_manager.h
+++ b/contrib/libs/hyperscan/src/som/slot_manager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief SOM Slot Manager.
*/
@@ -35,13 +35,13 @@
#define SLOT_MANAGER_H
#include "ue2common.h"
-#include "nfagraph/ng_holder.h"
-#include "util/bytecode_ptr.h"
-#include "util/noncopyable.h"
+#include "nfagraph/ng_holder.h"
+#include "util/bytecode_ptr.h"
+#include "util/noncopyable.h"
#include <deque>
#include <memory>
-#include <unordered_map>
+#include <unordered_map>
struct NFA;
@@ -55,7 +55,7 @@ struct SlotCache;
/** \brief SOM slot manager. Used to hand out SOM slots and track their
* relationships during SOM construction. Also stores reverse NFAs used for
* SOM. */
-class SomSlotManager : noncopyable {
+class SomSlotManager : noncopyable {
public:
explicit SomSlotManager(u8 precision);
~SomSlotManager();
@@ -69,7 +69,7 @@ public:
/** prefix must be acting as a resetting sentinel and should be a dag (if
* not how are we establish som?) */
u32 getInitialResetSomSlot(const NGHolder &prefix, const NGHolder &g,
- const std::unordered_map<NFAVertex, u32> &region_map,
+ const std::unordered_map<NFAVertex, u32> &region_map,
u32 last_sent_region,
bool *prefix_already_implemented);
@@ -79,11 +79,11 @@ public:
u32 numSomSlots() const;
- const std::deque<bytecode_ptr<NFA>> &getRevNfas() const {
+ const std::deque<bytecode_ptr<NFA>> &getRevNfas() const {
return rev_nfas;
}
- u32 addRevNfa(bytecode_ptr<NFA> nfa, u32 maxWidth);
+ u32 addRevNfa(bytecode_ptr<NFA> nfa, u32 maxWidth);
u32 somHistoryRequired() const { return historyRequired; }
@@ -98,7 +98,7 @@ private:
std::unique_ptr<SlotCache> cache;
/** \brief Reverse NFAs used for SOM support. */
- std::deque<bytecode_ptr<NFA>> rev_nfas;
+ std::deque<bytecode_ptr<NFA>> rev_nfas;
/** \brief In streaming mode, the amount of history we've committed to
* using for SOM rev NFAs. */
diff --git a/contrib/libs/hyperscan/src/som/slot_manager_internal.h b/contrib/libs/hyperscan/src/som/slot_manager_internal.h
index 358ed630c90..7e1fecc7e65 100644
--- a/contrib/libs/hyperscan/src/som/slot_manager_internal.h
+++ b/contrib/libs/hyperscan/src/som/slot_manager_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,8 +35,8 @@
#include "ue2common.h"
#include <memory>
-#include <unordered_map>
-#include <unordered_set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
namespace ue2 {
@@ -44,14 +44,14 @@ namespace ue2 {
struct InitialResetEntry {
InitialResetEntry(std::shared_ptr<const NGHolder> sent_in,
std::shared_ptr<const NGHolder> body_in,
- const std::unordered_map<NFAVertex, u32> &body_regions_in,
+ const std::unordered_map<NFAVertex, u32> &body_regions_in,
u32 sent_region_in, u32 first_bad_region_in)
: sent(sent_in), body(body_in), body_regions(body_regions_in),
sent_region(sent_region_in), first_bad_region(first_bad_region_in) {}
std::shared_ptr<const NGHolder> sent;
std::shared_ptr<const NGHolder> body;
- std::unordered_map<NFAVertex, u32> body_regions;
+ std::unordered_map<NFAVertex, u32> body_regions;
u32 sent_region;
u32 first_bad_region; /* ~0U if it must cover the whole g */
};
@@ -86,7 +86,7 @@ struct SlotEntryEqual {
};
struct SlotCache {
- typedef std::unordered_set<SlotCacheEntry, SlotEntryHasher,
+ typedef std::unordered_set<SlotCacheEntry, SlotEntryHasher,
SlotEntryEqual> CacheStore;
void insert(const NGHolder &prefix, const CharReach &escapes,
@@ -98,7 +98,7 @@ struct SlotCache {
CacheStore store;
std::unordered_set<std::shared_ptr<const NGHolder>, NGHolderHasher,
- NGHolderEqual> initial_prefixes;
+ NGHolderEqual> initial_prefixes;
std::vector<InitialResetInfo> initial_resets;
};
diff --git a/contrib/libs/hyperscan/src/som/som.h b/contrib/libs/hyperscan/src/som/som.h
index e3953311d2d..e759cf0a256 100644
--- a/contrib/libs/hyperscan/src/som/som.h
+++ b/contrib/libs/hyperscan/src/som/som.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,22 +26,22 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Common SOM definitions.
*/
#ifndef UE2_SOM_H
#define UE2_SOM_H
-namespace ue2 {
-
+namespace ue2 {
+
/** \brief Enumeration specifying a start of match behaviour. */
enum som_type {
SOM_NONE, //!< No SOM required
SOM_LEFT //!< Exact leftmost SOM
};
-} // namespace ue2
-
+} // namespace ue2
+
#endif // UE2_SOM_H
diff --git a/contrib/libs/hyperscan/src/som/som_operation.h b/contrib/libs/hyperscan/src/som/som_operation.h
index 72341adf85f..d85ad2268ea 100644
--- a/contrib/libs/hyperscan/src/som/som_operation.h
+++ b/contrib/libs/hyperscan/src/som/som_operation.h
@@ -1,84 +1,84 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief SOM runtime: data structures.
- *
- * Data structures used for SOM operations.
- */
-
-#ifndef SOM_OPERATION_H
-#define SOM_OPERATION_H
-
-#include "ue2common.h"
-
-#define SOM_EXTERNAL_CALLBACK_REL 1
-#define SOM_INTERNAL_LOC_SET 2
-#define SOM_INTERNAL_LOC_SET_IF_UNSET 3
-#define SOM_INTERNAL_LOC_SET_IF_WRITABLE 4
-#define SOM_INTERNAL_LOC_SET_REV_NFA 5
-#define SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET 6
-#define SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE 7
-#define SOM_INTERNAL_LOC_COPY 8
-#define SOM_INTERNAL_LOC_COPY_IF_WRITABLE 9
-#define SOM_INTERNAL_LOC_MAKE_WRITABLE 10
-#define SOM_EXTERNAL_CALLBACK_STORED 11
-#define SOM_EXTERNAL_CALLBACK_ABS 12
-#define SOM_EXTERNAL_CALLBACK_REV_NFA 13
-#define SOM_INTERNAL_LOC_SET_FROM 14
-#define SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE 15
-
-struct som_operation {
- /** \brief Report type, from the definitions above. */
- u8 type;
-
- /* \brief SOM loc to modify. */
- u32 onmatch;
-
- union {
- /** \brief SOM distance value, use varies according to type.
- *
- * - for SOM_EXTERNAL_CALLBACK_REL, from-offset is this many bytes
- * before the to-offset.
- * - for SOM_EXTERNAL_CALLBACK_ABS, set from-offset to this value.
- * - for SOM_INTERNAL_LOC_COPY*, som location read_from.
- */
- u64a somDistance;
-
- /** \brief Index of the reverse nfa.
- *
- * Used by SOM_EXTERNAL_CALLBACK_REV_NFA and
- * SOM_INTERNAL_LOC_SET_REV_NFA*.
- */
- u64a revNfaIndex;
- } aux;
-};
-
-#endif // SOM_OPERATION_H
-
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief SOM runtime: data structures.
+ *
+ * Data structures used for SOM operations.
+ */
+
+#ifndef SOM_OPERATION_H
+#define SOM_OPERATION_H
+
+#include "ue2common.h"
+
+#define SOM_EXTERNAL_CALLBACK_REL 1
+#define SOM_INTERNAL_LOC_SET 2
+#define SOM_INTERNAL_LOC_SET_IF_UNSET 3
+#define SOM_INTERNAL_LOC_SET_IF_WRITABLE 4
+#define SOM_INTERNAL_LOC_SET_REV_NFA 5
+#define SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET 6
+#define SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE 7
+#define SOM_INTERNAL_LOC_COPY 8
+#define SOM_INTERNAL_LOC_COPY_IF_WRITABLE 9
+#define SOM_INTERNAL_LOC_MAKE_WRITABLE 10
+#define SOM_EXTERNAL_CALLBACK_STORED 11
+#define SOM_EXTERNAL_CALLBACK_ABS 12
+#define SOM_EXTERNAL_CALLBACK_REV_NFA 13
+#define SOM_INTERNAL_LOC_SET_FROM 14
+#define SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE 15
+
+struct som_operation {
+ /** \brief Report type, from the definitions above. */
+ u8 type;
+
+ /* \brief SOM loc to modify. */
+ u32 onmatch;
+
+ union {
+ /** \brief SOM distance value, use varies according to type.
+ *
+ * - for SOM_EXTERNAL_CALLBACK_REL, from-offset is this many bytes
+ * before the to-offset.
+ * - for SOM_EXTERNAL_CALLBACK_ABS, set from-offset to this value.
+ * - for SOM_INTERNAL_LOC_COPY*, som location read_from.
+ */
+ u64a somDistance;
+
+ /** \brief Index of the reverse nfa.
+ *
+ * Used by SOM_EXTERNAL_CALLBACK_REV_NFA and
+ * SOM_INTERNAL_LOC_SET_REV_NFA*.
+ */
+ u64a revNfaIndex;
+ } aux;
+};
+
+#endif // SOM_OPERATION_H
+
diff --git a/contrib/libs/hyperscan/src/som/som_runtime.c b/contrib/libs/hyperscan/src/som/som_runtime.c
index 68fb96dfc9e..1a868efc974 100644
--- a/contrib/libs/hyperscan/src/som/som_runtime.c
+++ b/contrib/libs/hyperscan/src/som/som_runtime.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,7 +39,7 @@
*/
#include "hs_internal.h"
-#include "som_operation.h"
+#include "som_operation.h"
#include "som_runtime.h"
#include "scratch.h"
#include "ue2common.h"
@@ -51,7 +51,7 @@
static really_inline
void setSomLoc(struct fatbit *som_set_now, u64a *som_store, u32 som_store_count,
- const struct som_operation *ri, u64a to_offset) {
+ const struct som_operation *ri, u64a to_offset) {
/* validity handled by callers */
assert(to_offset >= ri->aux.somDistance);
u64a start_offset = to_offset - ri->aux.somDistance;
@@ -87,14 +87,14 @@ char ok_and_mark_if_unset(u8 *som_store_valid, struct fatbit *som_set_now,
}
static
-int somRevCallback(UNUSED u64a start, u64a end, ReportID id, void *ctx) {
- DEBUG_PRINTF("offset=%llu, id=%u\n", end, id);
+int somRevCallback(UNUSED u64a start, u64a end, ReportID id, void *ctx) {
+ DEBUG_PRINTF("offset=%llu, id=%u\n", end, id);
// We use the id to store the offset adjustment (for assertions like a
// leading \b or multiline mode).
assert(id <= 1);
u64a *from_offset = ctx;
- LIMIT_TO_AT_MOST(from_offset, end + id);
+ LIMIT_TO_AT_MOST(from_offset, end + id);
return 1; // continue matching.
}
@@ -112,7 +112,7 @@ const struct NFA *getSomRevNFA(const struct RoseEngine *t, u32 i) {
}
static
-void runRevNfa(struct hs_scratch *scratch, const struct som_operation *ri,
+void runRevNfa(struct hs_scratch *scratch, const struct som_operation *ri,
const u64a to_offset, u64a *from_offset) {
struct core_info *ci = &scratch->core_info;
@@ -151,7 +151,7 @@ void runRevNfa(struct hs_scratch *scratch, const struct som_operation *ri,
*from_offset = to_offset;
nfaBlockExecReverse(nfa, to_offset, buf, buf_bytes, hbuf, history_bytes,
- somRevCallback, from_offset);
+ somRevCallback, from_offset);
assert(*from_offset <= to_offset);
}
@@ -159,7 +159,7 @@ void runRevNfa(struct hs_scratch *scratch, const struct som_operation *ri,
static really_inline
void setSomLocRevNfa(struct hs_scratch *scratch, struct fatbit *som_set_now,
u64a *som_store, u32 som_store_count,
- const struct som_operation *ri, u64a to_offset) {
+ const struct som_operation *ri, u64a to_offset) {
/* validity handled by callers */
u64a from_offset = 0;
runRevNfa(scratch, ri, to_offset, &from_offset);
@@ -178,7 +178,7 @@ void setSomLocRevNfa(struct hs_scratch *scratch, struct fatbit *som_set_now,
}
void handleSomInternal(struct hs_scratch *scratch,
- const struct som_operation *ri, const u64a to_offset) {
+ const struct som_operation *ri, const u64a to_offset) {
assert(scratch);
assert(ri);
DEBUG_PRINTF("-->som action required at %llu\n", to_offset);
@@ -209,21 +209,21 @@ void handleSomInternal(struct hs_scratch *scratch,
}
switch (ri->type) {
- case SOM_INTERNAL_LOC_SET:
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET\n");
+ case SOM_INTERNAL_LOC_SET:
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET\n");
mmbit_set(som_store_valid, som_store_count, ri->onmatch);
setSomLoc(som_set_now, som_store, som_store_count, ri, to_offset);
return;
- case SOM_INTERNAL_LOC_SET_IF_UNSET:
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_UNSET\n");
+ case SOM_INTERNAL_LOC_SET_IF_UNSET:
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_UNSET\n");
if (ok_and_mark_if_unset(som_store_valid, som_set_now, som_store_count,
ri->onmatch)) {
setSomLoc(som_set_now, som_store, som_store_count, ri, to_offset);
}
return;
- case SOM_INTERNAL_LOC_SET_IF_WRITABLE: {
+ case SOM_INTERNAL_LOC_SET_IF_WRITABLE: {
u32 slot = ri->onmatch;
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_WRITABLE\n");
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_WRITABLE\n");
if (ok_and_mark_if_write(som_store_valid, som_set_now,
som_store_writable, som_store_count, slot)) {
setSomLoc(som_set_now, som_store, som_store_count, ri, to_offset);
@@ -245,23 +245,23 @@ void handleSomInternal(struct hs_scratch *scratch,
}
return;
}
- case SOM_INTERNAL_LOC_SET_REV_NFA:
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_REV_NFA\n");
+ case SOM_INTERNAL_LOC_SET_REV_NFA:
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_REV_NFA\n");
mmbit_set(som_store_valid, som_store_count, ri->onmatch);
setSomLocRevNfa(scratch, som_set_now, som_store, som_store_count, ri,
to_offset);
return;
- case SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET:
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET\n");
+ case SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET:
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_REV_NFA_IF_UNSET\n");
if (ok_and_mark_if_unset(som_store_valid, som_set_now, som_store_count,
ri->onmatch)) {
setSomLocRevNfa(scratch, som_set_now, som_store, som_store_count,
ri, to_offset);
}
return;
- case SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE: {
+ case SOM_INTERNAL_LOC_SET_REV_NFA_IF_WRITABLE: {
u32 slot = ri->onmatch;
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_WRITABLE\n");
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_IF_WRITABLE\n");
if (ok_and_mark_if_write(som_store_valid, som_set_now,
som_store_writable, som_store_count, slot)) {
setSomLocRevNfa(scratch, som_set_now, som_store, som_store_count,
@@ -285,10 +285,10 @@ void handleSomInternal(struct hs_scratch *scratch,
}
return;
}
- case SOM_INTERNAL_LOC_COPY: {
+ case SOM_INTERNAL_LOC_COPY: {
u32 slot_in = ri->aux.somDistance;
u32 slot_out = ri->onmatch;
- DEBUG_PRINTF("SOM_INTERNAL_LOC_COPY S[%u] = S[%u]\n", slot_out,
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_COPY S[%u] = S[%u]\n", slot_out,
slot_in);
assert(mmbit_isset(som_store_valid, som_store_count, slot_in));
mmbit_set(som_store_valid, som_store_count, slot_out);
@@ -297,10 +297,10 @@ void handleSomInternal(struct hs_scratch *scratch,
return;
}
- case SOM_INTERNAL_LOC_COPY_IF_WRITABLE: {
+ case SOM_INTERNAL_LOC_COPY_IF_WRITABLE: {
u32 slot_in = ri->aux.somDistance;
u32 slot_out = ri->onmatch;
- DEBUG_PRINTF("SOM_INTERNAL_LOC_COPY_IF_WRITABLE S[%u] = S[%u]\n",
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_COPY_IF_WRITABLE S[%u] = S[%u]\n",
slot_out, slot_in);
assert(mmbit_isset(som_store_valid, som_store_count, slot_in));
if (ok_and_mark_if_write(som_store_valid, som_set_now,
@@ -322,9 +322,9 @@ void handleSomInternal(struct hs_scratch *scratch,
}
return;
}
- case SOM_INTERNAL_LOC_MAKE_WRITABLE: {
+ case SOM_INTERNAL_LOC_MAKE_WRITABLE: {
u32 slot = ri->onmatch;
- DEBUG_PRINTF("SOM_INTERNAL_LOC_MAKE_WRITABLE\n");
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_MAKE_WRITABLE\n");
/* if just written to the loc, ignore the racing escape */
if (fatbit_isset(som_set_now, som_store_count, slot)) {
DEBUG_PRINTF("just written\n");
@@ -347,14 +347,14 @@ void handleSomInternal(struct hs_scratch *scratch,
break;
}
- // All valid som_operation types should be handled and returned above.
+ // All valid som_operation types should be handled and returned above.
assert(0);
return;
}
// Returns the SOM offset.
u64a handleSomExternal(struct hs_scratch *scratch,
- const struct som_operation *ri,
+ const struct som_operation *ri,
const u64a to_offset) {
assert(scratch);
assert(ri);
@@ -368,20 +368,20 @@ u64a handleSomExternal(struct hs_scratch *scratch,
assert(rose->hasSom);
switch (ri->type) {
- case SOM_EXTERNAL_CALLBACK_REL:
- DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_REL: som is %llu chars back\n",
+ case SOM_EXTERNAL_CALLBACK_REL:
+ DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_REL: som is %llu chars back\n",
ri->aux.somDistance);
assert(to_offset >= ri->aux.somDistance);
return to_offset - ri->aux.somDistance;
- case SOM_EXTERNAL_CALLBACK_ABS:
- DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_ABS: som is at %llu\n",
+ case SOM_EXTERNAL_CALLBACK_ABS:
+ DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_ABS: som is at %llu\n",
ri->aux.somDistance);
assert(to_offset >= ri->aux.somDistance);
return ri->aux.somDistance;
- case SOM_EXTERNAL_CALLBACK_STORED: {
+ case SOM_EXTERNAL_CALLBACK_STORED: {
const u64a *som_store = scratch->som_store;
u32 slot = ri->aux.somDistance;
- DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_STORED: <- som_store[%u]=%llu\n",
+ DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_STORED: <- som_store[%u]=%llu\n",
slot, som_store[slot]);
UNUSED const u32 som_store_count = rose->somLocationCount;
@@ -391,8 +391,8 @@ u64a handleSomExternal(struct hs_scratch *scratch,
assert(mmbit_isset(som_store_valid, som_store_count, slot));
return som_store[slot];
}
- case SOM_EXTERNAL_CALLBACK_REV_NFA: {
- DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_REV_NFA\n");
+ case SOM_EXTERNAL_CALLBACK_REV_NFA: {
+ DEBUG_PRINTF("SOM_EXTERNAL_CALLBACK_REV_NFA\n");
u64a from_offset = 0;
runRevNfa(scratch, ri, to_offset, &from_offset);
return from_offset;
@@ -402,19 +402,19 @@ u64a handleSomExternal(struct hs_scratch *scratch,
break;
}
- // All valid som_operation types should be handled and returned above.
+ // All valid som_operation types should be handled and returned above.
assert(0);
return 0;
}
void setSomFromSomAware(struct hs_scratch *scratch,
- const struct som_operation *ri, u64a from_offset,
+ const struct som_operation *ri, u64a from_offset,
u64a to_offset) {
assert(scratch);
assert(ri);
assert(to_offset);
- assert(ri->type == SOM_INTERNAL_LOC_SET_FROM
- || ri->type == SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE);
+ assert(ri->type == SOM_INTERNAL_LOC_SET_FROM
+ || ri->type == SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE);
struct core_info *ci = &scratch->core_info;
const struct RoseEngine *rose = ci->rose;
@@ -435,12 +435,12 @@ void setSomFromSomAware(struct hs_scratch *scratch,
scratch->som_set_now_offset = to_offset;
}
- if (ri->type == SOM_INTERNAL_LOC_SET_FROM) {
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_FROM\n");
+ if (ri->type == SOM_INTERNAL_LOC_SET_FROM) {
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_FROM\n");
mmbit_set(som_store_valid, som_store_count, ri->onmatch);
setSomLoc(som_set_now, som_store, som_store_count, ri, from_offset);
} else {
- DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE\n");
+ DEBUG_PRINTF("SOM_INTERNAL_LOC_SET_FROM_IF_WRITABLE\n");
if (ok_and_mark_if_write(som_store_valid, som_set_now,
som_store_writable, som_store_count,
ri->onmatch)) {
@@ -487,7 +487,7 @@ int clearSomLog(struct hs_scratch *scratch, u64a offset, struct fatbit *log,
int halt = ci->userCallback(onmatch, from_offset, offset, flags,
ci->userContext);
if (halt) {
- ci->status |= STATUS_TERMINATED;
+ ci->status |= STATUS_TERMINATED;
return 1;
}
}
diff --git a/contrib/libs/hyperscan/src/som/som_runtime.h b/contrib/libs/hyperscan/src/som/som_runtime.h
index 898c2a51d76..30c7ace8cb0 100644
--- a/contrib/libs/hyperscan/src/som/som_runtime.h
+++ b/contrib/libs/hyperscan/src/som/som_runtime.h
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief SOM runtime code.
*
* Runtime code for SOM handling called by the Rose callback adaptors.
@@ -39,17 +39,17 @@
#include "scratch.h"
#include "ue2common.h"
-struct som_operation;
+struct som_operation;
void handleSomInternal(struct hs_scratch *scratch,
- const struct som_operation *ri, const u64a to_offset);
+ const struct som_operation *ri, const u64a to_offset);
// Returns the from_offset.
u64a handleSomExternal(struct hs_scratch *scratch,
- const struct som_operation *ri, const u64a to_offset);
+ const struct som_operation *ri, const u64a to_offset);
void setSomFromSomAware(struct hs_scratch *scratch,
- const struct som_operation *ri, u64a from_offset,
+ const struct som_operation *ri, u64a from_offset,
u64a to_offset);
int flushStoredSomMatches_i(struct hs_scratch *scratch, u64a offset);
diff --git a/contrib/libs/hyperscan/src/stream_compress.c b/contrib/libs/hyperscan/src/stream_compress.c
index d35a8e69d93..0cc782daf20 100644
--- a/contrib/libs/hyperscan/src/stream_compress.c
+++ b/contrib/libs/hyperscan/src/stream_compress.c
@@ -1,130 +1,130 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "stream_compress.h"
-
-#include "state.h"
-#include "nfa/nfa_internal.h"
-#include "rose/rose_internal.h"
-#include "util/multibit.h"
-#include "util/multibit_compress.h"
-#include "util/uniform_ops.h"
-
-#include <string.h>
-
-#define COPY_IN(p, sz) do { \
- assert(currOffset + sz <= buf_size); \
- memcpy(buf + currOffset, p, sz); \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define COPY_OUT(p, sz) do { \
- if (currOffset + sz > buf_size) { \
- return 0; \
- } \
- memcpy(p, buf + currOffset, sz); \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define SIZE_COPY_IN(p, sz) do { \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define COPY_MULTIBIT_IN(p, total_bits) do { \
- size_t sz; \
- STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
- BUF_QUAL u8 *comp = (BUF_QUAL u8 *)(buf + currOffset); \
- if (!mmbit_compress(bits, total_bits, comp, &sz, \
- buf_size - currOffset)) { \
- return 0; /* error */ \
- } \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define COPY_MULTIBIT_OUT(p, total_bits) do { \
- size_t sz; \
- STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
- BUF_QUAL u8 *comp = (BUF_QUAL u8 *)(buf + currOffset); \
- if (!mmbit_decompress(bits, total_bits, comp, &sz, \
- buf_size - currOffset)) { \
- return 0; /* error */ \
- } \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define COPY_MULTIBIT_SIZE(p, total_bits) do { \
- STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
- size_t sz = mmbit_compsize(bits, total_bits); \
- currOffset += sz; \
- DEBUG_PRINTF("co = %zu\n", currOffset); \
- } while (0);
-
-#define COPY COPY_OUT
-#define COPY_MULTIBIT COPY_MULTIBIT_OUT
-#define ASSIGN(lhs, rhs) do { lhs = rhs; } while (0)
-#define FN_SUFFIX expand
-#define STREAM_QUAL
-#define BUF_QUAL const
-#include "stream_compress_impl.h"
-
-int expand_stream(struct hs_stream *stream, const struct RoseEngine *rose,
- const char *buf, size_t buf_size) {
- return sc_expand(rose, stream, buf, buf_size);
-}
-
-#define COPY COPY_IN
-#define COPY_MULTIBIT COPY_MULTIBIT_IN
-#define ASSIGN(lhs, rhs) do { } while (0)
-#define FN_SUFFIX compress
-#define STREAM_QUAL const
-#define BUF_QUAL
-#include "stream_compress_impl.h"
-
-size_t compress_stream(char *buf, size_t buf_size,
- const struct RoseEngine *rose,
- const struct hs_stream *stream) {
- return sc_compress(rose, stream, buf, buf_size);
-}
-
-#define COPY SIZE_COPY_IN
-#define COPY_MULTIBIT COPY_MULTIBIT_SIZE
-#define ASSIGN(lhs, rhs) do { } while (0)
-#define FN_SUFFIX size
-#define STREAM_QUAL const
-#define BUF_QUAL UNUSED
-#include "stream_compress_impl.h"
-
-size_t size_compress_stream(const struct RoseEngine *rose,
- const struct hs_stream *stream) {
- return sc_size(rose, stream, NULL, 0);
-}
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "stream_compress.h"
+
+#include "state.h"
+#include "nfa/nfa_internal.h"
+#include "rose/rose_internal.h"
+#include "util/multibit.h"
+#include "util/multibit_compress.h"
+#include "util/uniform_ops.h"
+
+#include <string.h>
+
+#define COPY_IN(p, sz) do { \
+ assert(currOffset + sz <= buf_size); \
+ memcpy(buf + currOffset, p, sz); \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define COPY_OUT(p, sz) do { \
+ if (currOffset + sz > buf_size) { \
+ return 0; \
+ } \
+ memcpy(p, buf + currOffset, sz); \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define SIZE_COPY_IN(p, sz) do { \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define COPY_MULTIBIT_IN(p, total_bits) do { \
+ size_t sz; \
+ STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
+ BUF_QUAL u8 *comp = (BUF_QUAL u8 *)(buf + currOffset); \
+ if (!mmbit_compress(bits, total_bits, comp, &sz, \
+ buf_size - currOffset)) { \
+ return 0; /* error */ \
+ } \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define COPY_MULTIBIT_OUT(p, total_bits) do { \
+ size_t sz; \
+ STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
+ BUF_QUAL u8 *comp = (BUF_QUAL u8 *)(buf + currOffset); \
+ if (!mmbit_decompress(bits, total_bits, comp, &sz, \
+ buf_size - currOffset)) { \
+ return 0; /* error */ \
+ } \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define COPY_MULTIBIT_SIZE(p, total_bits) do { \
+ STREAM_QUAL u8 *bits = (STREAM_QUAL u8 *)p; \
+ size_t sz = mmbit_compsize(bits, total_bits); \
+ currOffset += sz; \
+ DEBUG_PRINTF("co = %zu\n", currOffset); \
+ } while (0);
+
+#define COPY COPY_OUT
+#define COPY_MULTIBIT COPY_MULTIBIT_OUT
+#define ASSIGN(lhs, rhs) do { lhs = rhs; } while (0)
+#define FN_SUFFIX expand
+#define STREAM_QUAL
+#define BUF_QUAL const
+#include "stream_compress_impl.h"
+
+int expand_stream(struct hs_stream *stream, const struct RoseEngine *rose,
+ const char *buf, size_t buf_size) {
+ return sc_expand(rose, stream, buf, buf_size);
+}
+
+#define COPY COPY_IN
+#define COPY_MULTIBIT COPY_MULTIBIT_IN
+#define ASSIGN(lhs, rhs) do { } while (0)
+#define FN_SUFFIX compress
+#define STREAM_QUAL const
+#define BUF_QUAL
+#include "stream_compress_impl.h"
+
+size_t compress_stream(char *buf, size_t buf_size,
+ const struct RoseEngine *rose,
+ const struct hs_stream *stream) {
+ return sc_compress(rose, stream, buf, buf_size);
+}
+
+#define COPY SIZE_COPY_IN
+#define COPY_MULTIBIT COPY_MULTIBIT_SIZE
+#define ASSIGN(lhs, rhs) do { } while (0)
+#define FN_SUFFIX size
+#define STREAM_QUAL const
+#define BUF_QUAL UNUSED
+#include "stream_compress_impl.h"
+
+size_t size_compress_stream(const struct RoseEngine *rose,
+ const struct hs_stream *stream) {
+ return sc_size(rose, stream, NULL, 0);
+}
diff --git a/contrib/libs/hyperscan/src/stream_compress.h b/contrib/libs/hyperscan/src/stream_compress.h
index 6bc9f8122f6..0d06d1e0ffb 100644
--- a/contrib/libs/hyperscan/src/stream_compress.h
+++ b/contrib/libs/hyperscan/src/stream_compress.h
@@ -1,51 +1,51 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Functions for dynamic compress/expand for streams.
- */
-
-#ifndef STREAM_COMPRESS_H
-#define STREAM_COMPRESS_H
-
-#include <stdlib.h>
-
-struct hs_stream;
-struct RoseEngine;
-
-int expand_stream(struct hs_stream *out, const struct RoseEngine *rose,
- const char *buf, size_t buf_size);
-
-size_t compress_stream(char *buf, size_t buf_size,
- const struct RoseEngine *rose,
- const struct hs_stream *src);
-
-size_t size_compress_stream(const struct RoseEngine *rose,
- const struct hs_stream *stream);
-
-#endif
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Functions for dynamic compress/expand for streams.
+ */
+
+#ifndef STREAM_COMPRESS_H
+#define STREAM_COMPRESS_H
+
+#include <stdlib.h>
+
+struct hs_stream;
+struct RoseEngine;
+
+int expand_stream(struct hs_stream *out, const struct RoseEngine *rose,
+ const char *buf, size_t buf_size);
+
+size_t compress_stream(char *buf, size_t buf_size,
+ const struct RoseEngine *rose,
+ const struct hs_stream *src);
+
+size_t size_compress_stream(const struct RoseEngine *rose,
+ const struct hs_stream *stream);
+
+#endif
diff --git a/contrib/libs/hyperscan/src/stream_compress_impl.h b/contrib/libs/hyperscan/src/stream_compress_impl.h
index ca276296353..d1ccf5e6d03 100644
--- a/contrib/libs/hyperscan/src/stream_compress_impl.h
+++ b/contrib/libs/hyperscan/src/stream_compress_impl.h
@@ -1,153 +1,153 @@
-/*
+/*
* Copyright (c) 2017-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "util/join.h"
-
-#define COPY_FIELD(x) COPY(&x, sizeof(x))
-#define COPY_LEFTFIXES JOIN(sc_left_, FN_SUFFIX)
-#define COPY_SOM_INFO JOIN(sc_som_, FN_SUFFIX)
-
-static
-size_t COPY_LEFTFIXES(const struct RoseEngine *rose, size_t currOffset,
- STREAM_QUAL struct hs_stream *stream,
- BUF_QUAL char *buf, UNUSED size_t buf_size) {
- if (!rose->activeLeftIterOffset) {
- return currOffset;
- }
-
- const struct RoseStateOffsets *so = &rose->stateOffsets;
- STREAM_QUAL char *stream_body
- = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
-
- /* Note: in the expand case the active left array has already been copied
- * into the stream. */
- const u8 *ara = (const u8 *)(stream_body + so->activeLeftArray);
- const u32 arCount = rose->activeLeftCount;
- const struct LeftNfaInfo *left_table = getLeftTable(rose);
-
- /* We only want to look at non-transient leftfixes */
- const struct mmbit_sparse_iter *it = getActiveLeftIter(rose);
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
- u32 dummy;
- u32 ri = mmbit_sparse_iter_begin(ara, arCount, &dummy, it, si_state);
- for (; ri != MMB_INVALID;
- ri = mmbit_sparse_iter_next(ara, arCount, ri, &dummy, it, si_state)) {
- u32 qi = ri + rose->leftfixBeginQueue;
- UNUSED const struct LeftNfaInfo *left = left_table + ri;
- const struct NfaInfo *nfa_info = getNfaInfoByQueue(rose, qi);
- const struct NFA *nfa = getNfaByInfo(rose, nfa_info);
-
- COPY(stream_body + nfa_info->stateOffset, nfa->streamStateSize);
- /* copy the one whole byte for active leftfixes as well */
- assert(left->lagIndex != ROSE_OFFSET_INVALID);
- COPY(stream_body + so->leftfixLagTable + left->lagIndex, 1);
- }
-
- return currOffset;
-}
-
-static
-size_t COPY_SOM_INFO(const struct RoseEngine *rose, size_t currOffset,
- STREAM_QUAL struct hs_stream *stream,
- BUF_QUAL char *buf, UNUSED size_t buf_size) {
- const struct RoseStateOffsets *so = &rose->stateOffsets;
-
- if (!so->somLocation) {
- assert(!so->somValid);
- assert(!so->somWritable);
- return currOffset;
- }
-
- STREAM_QUAL char *stream_body
- = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
-
- assert(so->somValid);
- assert(so->somWritable);
-
- COPY_MULTIBIT(stream_body + so->somWritable, rose->somLocationCount);
- COPY_MULTIBIT(stream_body + so->somValid, rose->somLocationCount);
-
- /* Copy only the som slots which contain valid values. */
- /* Note: in the expand case the som valid array has been copied in. */
- const u8 *svalid = (const u8 *)(stream_body + so->somValid);
- u32 s_count = rose->somLocationCount;
- u32 s_width = rose->somHorizon;
- for (u32 slot = mmbit_iterate(svalid, s_count, MMB_INVALID);
- slot != MMB_INVALID; slot = mmbit_iterate(svalid, s_count, slot)) {
- COPY(stream_body + so->somLocation + slot * s_width, s_width);
- }
-
- return currOffset;
-}
-
-static
-size_t JOIN(sc_, FN_SUFFIX)(const struct RoseEngine *rose,
- STREAM_QUAL struct hs_stream *stream,
- BUF_QUAL char *buf, UNUSED size_t buf_size) {
- size_t currOffset = 0;
- const struct RoseStateOffsets *so = &rose->stateOffsets;
-
- STREAM_QUAL char *stream_body
- = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
-
- COPY_FIELD(stream->offset);
- ASSIGN(stream->rose, rose);
-
- COPY(stream_body + ROSE_STATE_OFFSET_STATUS_FLAGS, 1);
- COPY_MULTIBIT(stream_body + ROSE_STATE_OFFSET_ROLE_MMBIT, rose->rolesWithStateCount);
-
- /* stream is valid in compress/size, and stream->offset has been set already
- * on the expand side */
- u64a offset = stream->offset;
- u32 history = MIN((u32)offset, rose->historyRequired);
-
- /* copy the active mmbits */
- COPY_MULTIBIT(stream_body + so->activeLeafArray, rose->activeArrayCount);
- COPY_MULTIBIT(stream_body + so->activeLeftArray, rose->activeLeftCount);
-
- COPY(stream_body + so->longLitState, so->longLitState_size);
-
- /* Leftlag table will be handled later, for active leftfixes */
-
- /* anchored table state is not required once we are deep in the stream */
- if (offset <= rose->anchoredDistance) {
- COPY(stream_body + so->anchorState, rose->anchorStateSize);
- }
-
- COPY(stream_body + so->groups, so->groups_size);
-
- /* copy the real bits of history */
- UNUSED u32 hend = so->history + rose->historyRequired;
- COPY(stream_body + hend - history, history);
-
- /* copy the exhaustion multibit */
- COPY_MULTIBIT(stream_body + so->exhausted, rose->ekeyCount);
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "util/join.h"
+
+#define COPY_FIELD(x) COPY(&x, sizeof(x))
+#define COPY_LEFTFIXES JOIN(sc_left_, FN_SUFFIX)
+#define COPY_SOM_INFO JOIN(sc_som_, FN_SUFFIX)
+
+static
+size_t COPY_LEFTFIXES(const struct RoseEngine *rose, size_t currOffset,
+ STREAM_QUAL struct hs_stream *stream,
+ BUF_QUAL char *buf, UNUSED size_t buf_size) {
+ if (!rose->activeLeftIterOffset) {
+ return currOffset;
+ }
+
+ const struct RoseStateOffsets *so = &rose->stateOffsets;
+ STREAM_QUAL char *stream_body
+ = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
+
+ /* Note: in the expand case the active left array has already been copied
+ * into the stream. */
+ const u8 *ara = (const u8 *)(stream_body + so->activeLeftArray);
+ const u32 arCount = rose->activeLeftCount;
+ const struct LeftNfaInfo *left_table = getLeftTable(rose);
+
+ /* We only want to look at non-transient leftfixes */
+ const struct mmbit_sparse_iter *it = getActiveLeftIter(rose);
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+ u32 dummy;
+ u32 ri = mmbit_sparse_iter_begin(ara, arCount, &dummy, it, si_state);
+ for (; ri != MMB_INVALID;
+ ri = mmbit_sparse_iter_next(ara, arCount, ri, &dummy, it, si_state)) {
+ u32 qi = ri + rose->leftfixBeginQueue;
+ UNUSED const struct LeftNfaInfo *left = left_table + ri;
+ const struct NfaInfo *nfa_info = getNfaInfoByQueue(rose, qi);
+ const struct NFA *nfa = getNfaByInfo(rose, nfa_info);
+
+ COPY(stream_body + nfa_info->stateOffset, nfa->streamStateSize);
+ /* copy the one whole byte for active leftfixes as well */
+ assert(left->lagIndex != ROSE_OFFSET_INVALID);
+ COPY(stream_body + so->leftfixLagTable + left->lagIndex, 1);
+ }
+
+ return currOffset;
+}
+
+static
+size_t COPY_SOM_INFO(const struct RoseEngine *rose, size_t currOffset,
+ STREAM_QUAL struct hs_stream *stream,
+ BUF_QUAL char *buf, UNUSED size_t buf_size) {
+ const struct RoseStateOffsets *so = &rose->stateOffsets;
+
+ if (!so->somLocation) {
+ assert(!so->somValid);
+ assert(!so->somWritable);
+ return currOffset;
+ }
+
+ STREAM_QUAL char *stream_body
+ = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
+
+ assert(so->somValid);
+ assert(so->somWritable);
+
+ COPY_MULTIBIT(stream_body + so->somWritable, rose->somLocationCount);
+ COPY_MULTIBIT(stream_body + so->somValid, rose->somLocationCount);
+
+ /* Copy only the som slots which contain valid values. */
+ /* Note: in the expand case the som valid array has been copied in. */
+ const u8 *svalid = (const u8 *)(stream_body + so->somValid);
+ u32 s_count = rose->somLocationCount;
+ u32 s_width = rose->somHorizon;
+ for (u32 slot = mmbit_iterate(svalid, s_count, MMB_INVALID);
+ slot != MMB_INVALID; slot = mmbit_iterate(svalid, s_count, slot)) {
+ COPY(stream_body + so->somLocation + slot * s_width, s_width);
+ }
+
+ return currOffset;
+}
+
+static
+size_t JOIN(sc_, FN_SUFFIX)(const struct RoseEngine *rose,
+ STREAM_QUAL struct hs_stream *stream,
+ BUF_QUAL char *buf, UNUSED size_t buf_size) {
+ size_t currOffset = 0;
+ const struct RoseStateOffsets *so = &rose->stateOffsets;
+
+ STREAM_QUAL char *stream_body
+ = ((STREAM_QUAL char *)stream) + sizeof(struct hs_stream);
+
+ COPY_FIELD(stream->offset);
+ ASSIGN(stream->rose, rose);
+
+ COPY(stream_body + ROSE_STATE_OFFSET_STATUS_FLAGS, 1);
+ COPY_MULTIBIT(stream_body + ROSE_STATE_OFFSET_ROLE_MMBIT, rose->rolesWithStateCount);
+
+ /* stream is valid in compress/size, and stream->offset has been set already
+ * on the expand side */
+ u64a offset = stream->offset;
+ u32 history = MIN((u32)offset, rose->historyRequired);
+
+ /* copy the active mmbits */
+ COPY_MULTIBIT(stream_body + so->activeLeafArray, rose->activeArrayCount);
+ COPY_MULTIBIT(stream_body + so->activeLeftArray, rose->activeLeftCount);
+
+ COPY(stream_body + so->longLitState, so->longLitState_size);
+
+ /* Leftlag table will be handled later, for active leftfixes */
+
+ /* anchored table state is not required once we are deep in the stream */
+ if (offset <= rose->anchoredDistance) {
+ COPY(stream_body + so->anchorState, rose->anchorStateSize);
+ }
+
+ COPY(stream_body + so->groups, so->groups_size);
+
+ /* copy the real bits of history */
+ UNUSED u32 hend = so->history + rose->historyRequired;
+ COPY(stream_body + hend - history, history);
+
+ /* copy the exhaustion multibit */
+ COPY_MULTIBIT(stream_body + so->exhausted, rose->ekeyCount);
+
/* copy the logical multibit */
COPY_MULTIBIT(stream_body + so->logicalVec,
rose->lkeyCount + rose->lopCount);
@@ -155,39 +155,39 @@ size_t JOIN(sc_, FN_SUFFIX)(const struct RoseEngine *rose,
/* copy the combination multibit */
COPY_MULTIBIT(stream_body + so->combVec, rose->ckeyCount);
- /* copy nfa stream state for endfixes */
- /* Note: in the expand case the active array has already been copied into
- * the stream. */
- const u8 *aa = (const u8 *)(stream_body + so->activeLeafArray);
- u32 aaCount = rose->activeArrayCount;
- for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
- qi = mmbit_iterate(aa, aaCount, qi)) {
- DEBUG_PRINTF("saving stream state for qi=%u\n", qi);
- const struct NfaInfo *nfa_info = getNfaInfoByQueue(rose, qi);
- const struct NFA *nfa = getNfaByInfo(rose, nfa_info);
- COPY(stream_body + nfa_info->stateOffset, nfa->streamStateSize);
- }
-
- /* copy nfa stream state for leftfixes */
- currOffset = COPY_LEFTFIXES(rose, currOffset, stream, buf, buf_size);
- if (!currOffset) {
- return 0;
- }
-
- currOffset = COPY_SOM_INFO(rose, currOffset, stream, buf, buf_size);
- if (!currOffset) {
- return 0;
- }
-
- return currOffset;
-}
-
-#undef ASSIGN
-#undef COPY
-#undef COPY_FIELD
-#undef COPT_LEFTFIXES
-#undef COPY_MULTIBIT
-#undef COPY_SOM_INFO
-#undef FN_SUFFIX
-#undef BUF_QUAL
-#undef STREAM_QUAL
+ /* copy nfa stream state for endfixes */
+ /* Note: in the expand case the active array has already been copied into
+ * the stream. */
+ const u8 *aa = (const u8 *)(stream_body + so->activeLeafArray);
+ u32 aaCount = rose->activeArrayCount;
+ for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
+ qi = mmbit_iterate(aa, aaCount, qi)) {
+ DEBUG_PRINTF("saving stream state for qi=%u\n", qi);
+ const struct NfaInfo *nfa_info = getNfaInfoByQueue(rose, qi);
+ const struct NFA *nfa = getNfaByInfo(rose, nfa_info);
+ COPY(stream_body + nfa_info->stateOffset, nfa->streamStateSize);
+ }
+
+ /* copy nfa stream state for leftfixes */
+ currOffset = COPY_LEFTFIXES(rose, currOffset, stream, buf, buf_size);
+ if (!currOffset) {
+ return 0;
+ }
+
+ currOffset = COPY_SOM_INFO(rose, currOffset, stream, buf, buf_size);
+ if (!currOffset) {
+ return 0;
+ }
+
+ return currOffset;
+}
+
+#undef ASSIGN
+#undef COPY
+#undef COPY_FIELD
+#undef COPT_LEFTFIXES
+#undef COPY_MULTIBIT
+#undef COPY_SOM_INFO
+#undef FN_SUFFIX
+#undef BUF_QUAL
+#undef STREAM_QUAL
diff --git a/contrib/libs/hyperscan/src/ue2common.h b/contrib/libs/hyperscan/src/ue2common.h
index a1e79f35885..5705af7be43 100644
--- a/contrib/libs/hyperscan/src/ue2common.h
+++ b/contrib/libs/hyperscan/src/ue2common.h
@@ -52,9 +52,9 @@
#define ALIGN_ATTR(x) __attribute__((aligned((x))))
#endif
-#define ALIGN_DIRECTIVE ALIGN_ATTR(16)
-#define ALIGN_AVX_DIRECTIVE ALIGN_ATTR(32)
-#define ALIGN_CL_DIRECTIVE ALIGN_ATTR(64)
+#define ALIGN_DIRECTIVE ALIGN_ATTR(16)
+#define ALIGN_AVX_DIRECTIVE ALIGN_ATTR(32)
+#define ALIGN_CL_DIRECTIVE ALIGN_ATTR(64)
typedef signed char s8;
typedef unsigned char u8;
@@ -194,24 +194,24 @@ typedef u32 ReportID;
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#else
-#define likely(x) (x)
-#define unlikely(x) (x)
-#endif
-
-#if !defined(RELEASE_BUILD) || defined(DEBUG)
-#ifdef _WIN32
-#define PATH_SEP '\\'
-#else
-#define PATH_SEP '/'
-#endif
-#endif
-
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#if !defined(RELEASE_BUILD) || defined(DEBUG)
+#ifdef _WIN32
+#define PATH_SEP '\\'
+#else
+#define PATH_SEP '/'
+#endif
+#endif
+
#if defined(DEBUG) && !defined(DEBUG_PRINTF)
#include <string.h>
#include <stdio.h>
#define DEBUG_PRINTF(format, ...) printf("%s:%s:%d:" format, \
- strrchr(__FILE__, PATH_SEP) + 1, \
- __func__, __LINE__, ## __VA_ARGS__)
+ strrchr(__FILE__, PATH_SEP) + 1, \
+ __func__, __LINE__, ## __VA_ARGS__)
#elif !defined(DEBUG_PRINTF)
#define DEBUG_PRINTF(format, ...) do { } while(0)
#endif
@@ -220,8 +220,8 @@ typedef u32 ReportID;
#include <string.h>
#include <stdio.h>
#define ADEBUG_PRINTF(format, ...) printf("!%s:%s:%d:" format, \
- strrchr(__FILE__, PATH_SEP) + 1, \
- __func__, __LINE__, ## __VA_ARGS__)
+ strrchr(__FILE__, PATH_SEP) + 1, \
+ __func__, __LINE__, ## __VA_ARGS__)
#else
#define ADEBUG_PRINTF(format, ...) do { } while(0)
#endif
diff --git a/contrib/libs/hyperscan/src/util/accel_scheme.h b/contrib/libs/hyperscan/src/util/accel_scheme.h
index 080b77dfdad..2a067b30c6d 100644
--- a/contrib/libs/hyperscan/src/util/accel_scheme.h
+++ b/contrib/libs/hyperscan/src/util/accel_scheme.h
@@ -1,51 +1,51 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef ACCEL_SCHEME_H
-#define ACCEL_SCHEME_H
-
-#include "util/charreach.h"
-#include "util/flat_containers.h"
-
-#include <utility>
-
-namespace ue2 {
-
-#define MAX_ACCEL_DEPTH 4
-
-struct AccelScheme {
- flat_set<std::pair<u8, u8>> double_byte;
- CharReach cr = CharReach::dot();
- CharReach double_cr;
- u32 offset = MAX_ACCEL_DEPTH + 1;
- u32 double_offset = 0;
-};
-
-}
-
-#endif
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef ACCEL_SCHEME_H
+#define ACCEL_SCHEME_H
+
+#include "util/charreach.h"
+#include "util/flat_containers.h"
+
+#include <utility>
+
+namespace ue2 {
+
+#define MAX_ACCEL_DEPTH 4
+
+struct AccelScheme {
+ flat_set<std::pair<u8, u8>> double_byte;
+ CharReach cr = CharReach::dot();
+ CharReach double_cr;
+ u32 offset = MAX_ACCEL_DEPTH + 1;
+ u32 double_offset = 0;
+};
+
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/util/alloc.h b/contrib/libs/hyperscan/src/util/alloc.h
index bec3fdb24a8..de20c8d028e 100644
--- a/contrib/libs/hyperscan/src/util/alloc.h
+++ b/contrib/libs/hyperscan/src/util/alloc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/**
- * \file
+/**
+ * \file
* \brief Aligned memory alloc/free.
*/
@@ -60,41 +60,41 @@ void aligned_free_internal(void *ptr);
/** \brief Aligned allocator class for use with STL containers. Ensures that
* your objects are aligned to N bytes. */
-template <class T, std::size_t N>
-class AlignedAllocator {
+template <class T, std::size_t N>
+class AlignedAllocator {
public:
- using value_type = T;
+ using value_type = T;
- AlignedAllocator() noexcept {}
+ AlignedAllocator() noexcept {}
- template <class U, std::size_t N2>
- AlignedAllocator(const AlignedAllocator<U, N2> &) noexcept {}
+ template <class U, std::size_t N2>
+ AlignedAllocator(const AlignedAllocator<U, N2> &) noexcept {}
- template <class U> struct rebind {
- using other = AlignedAllocator<U, N>;
- };
+ template <class U> struct rebind {
+ using other = AlignedAllocator<U, N>;
+ };
- T *allocate(std::size_t size) const {
- size_t alloc_size = size * sizeof(T);
- return static_cast<T *>(aligned_malloc_internal(alloc_size, N));
+ T *allocate(std::size_t size) const {
+ size_t alloc_size = size * sizeof(T);
+ return static_cast<T *>(aligned_malloc_internal(alloc_size, N));
}
- void deallocate(T *x, std::size_t) const noexcept {
- aligned_free_internal(x);
+ void deallocate(T *x, std::size_t) const noexcept {
+ aligned_free_internal(x);
}
-};
-
-template <class T, class U, std::size_t N, std::size_t N2>
-bool operator==(const AlignedAllocator<T, N> &,
- const AlignedAllocator<U, N2> &) {
- return true;
-}
-
-template <class T, class U, std::size_t N, std::size_t N2>
-bool operator!=(const AlignedAllocator<T, N> &a,
- const AlignedAllocator<U, N2> &b) {
- return !(a == b);
-}
+};
+
+template <class T, class U, std::size_t N, std::size_t N2>
+bool operator==(const AlignedAllocator<T, N> &,
+ const AlignedAllocator<U, N2> &) {
+ return true;
+}
+
+template <class T, class U, std::size_t N, std::size_t N2>
+bool operator!=(const AlignedAllocator<T, N> &a,
+ const AlignedAllocator<U, N2> &b) {
+ return !(a == b);
+}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/util/arch.h b/contrib/libs/hyperscan/src/util/arch.h
index a38dff6e842..6220f12bc1f 100644
--- a/contrib/libs/hyperscan/src/util/arch.h
+++ b/contrib/libs/hyperscan/src/util/arch.h
@@ -1,45 +1,45 @@
-/*
+/*
* Copyright (c) 2017-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Per-platform architecture definitions
- */
-
-#ifndef UTIL_ARCH_H_
-#define UTIL_ARCH_H_
-
-#define HAVE_SSE2
+ *
+ * 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 Intel Corporation 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.
+ */
-/*
- * MSVC uses a different form of inline asm
- */
-#if defined(_WIN32) && defined(_MSC_VER)
-#define NO_ASM
-#endif
-
-#endif // UTIL_ARCH_H_
+/** \file
+ * \brief Per-platform architecture definitions
+ */
+
+#ifndef UTIL_ARCH_H_
+#define UTIL_ARCH_H_
+
+#define HAVE_SSE2
+
+/*
+ * MSVC uses a different form of inline asm
+ */
+#if defined(_WIN32) && defined(_MSC_VER)
+#define NO_ASM
+#endif
+
+#endif // UTIL_ARCH_H_
diff --git a/contrib/libs/hyperscan/src/util/bitfield.h b/contrib/libs/hyperscan/src/util/bitfield.h
index a1c735971bb..a580da7b608 100644
--- a/contrib/libs/hyperscan/src/util/bitfield.h
+++ b/contrib/libs/hyperscan/src/util/bitfield.h
@@ -36,7 +36,7 @@
#include "ue2common.h"
#include "popcount.h"
#include "util/bitutils.h"
-#include "util/hash.h"
+#include "util/hash.h"
#include <array>
#include <cassert>
@@ -187,16 +187,16 @@ public:
size_t count() const {
static_assert(block_size == 64, "adjust popcount for block_type");
size_t sum = 0;
- size_t i = 0;
- for (; i + 4 <= num_blocks; i += 4) {
- sum += popcount64(bits[i]);
- sum += popcount64(bits[i + 1]);
- sum += popcount64(bits[i + 2]);
- sum += popcount64(bits[i + 3]);
+ size_t i = 0;
+ for (; i + 4 <= num_blocks; i += 4) {
+ sum += popcount64(bits[i]);
+ sum += popcount64(bits[i + 1]);
+ sum += popcount64(bits[i + 2]);
+ sum += popcount64(bits[i + 3]);
+ }
+ for (; i < num_blocks; i++) {
+ sum += popcount64(bits[i]);
}
- for (; i < num_blocks; i++) {
- sum += popcount64(bits[i]);
- }
assert(sum <= size());
return sum;
}
@@ -313,14 +313,14 @@ public:
/// Bitwise OR-equals.
void operator|=(const bitfield &a) {
- size_t i = 0;
- for (; i + 4 <= num_blocks; i += 4) {
- bits[i] |= a.bits[i];
- bits[i + 1] |= a.bits[i + 1];
- bits[i + 2] |= a.bits[i + 2];
- bits[i + 3] |= a.bits[i + 3];
- }
- for (; i < num_blocks; i++) {
+ size_t i = 0;
+ for (; i + 4 <= num_blocks; i += 4) {
+ bits[i] |= a.bits[i];
+ bits[i + 1] |= a.bits[i + 1];
+ bits[i + 2] |= a.bits[i + 2];
+ bits[i + 3] |= a.bits[i + 3];
+ }
+ for (; i < num_blocks; i++) {
bits[i] |= a.bits[i];
}
}
@@ -334,34 +334,34 @@ public:
/// Bitwise AND-equals.
void operator&=(const bitfield &a) {
- size_t i = 0;
- for (; i + 4 <= num_blocks; i += 4) {
- bits[i] &= a.bits[i];
- bits[i + 1] &= a.bits[i + 1];
- bits[i + 2] &= a.bits[i + 2];
- bits[i + 3] &= a.bits[i + 3];
- }
- for (; i < num_blocks; i++) {
+ size_t i = 0;
+ for (; i + 4 <= num_blocks; i += 4) {
+ bits[i] &= a.bits[i];
+ bits[i + 1] &= a.bits[i + 1];
+ bits[i + 2] &= a.bits[i + 2];
+ bits[i + 3] &= a.bits[i + 3];
+ }
+ for (; i < num_blocks; i++) {
bits[i] &= a.bits[i];
}
}
/// Bitwise XOR.
- bitfield operator^(bitfield a) const {
- a ^= *this;
- return a;
+ bitfield operator^(bitfield a) const {
+ a ^= *this;
+ return a;
}
/// Bitwise XOR-equals.
- void operator^=(bitfield a) {
- size_t i = 0;
- for (; i + 4 <= num_blocks; i += 4) {
- bits[i] ^= a.bits[i];
- bits[i + 1] ^= a.bits[i + 1];
- bits[i + 2] ^= a.bits[i + 2];
- bits[i + 3] ^= a.bits[i + 3];
- }
- for (; i < num_blocks; i++) {
+ void operator^=(bitfield a) {
+ size_t i = 0;
+ for (; i + 4 <= num_blocks; i += 4) {
+ bits[i] ^= a.bits[i];
+ bits[i + 1] ^= a.bits[i + 1];
+ bits[i + 2] ^= a.bits[i + 2];
+ bits[i + 3] ^= a.bits[i + 3];
+ }
+ for (; i < num_blocks; i++) {
bits[i] ^= a.bits[i];
}
}
@@ -375,7 +375,7 @@ public:
/// Simple hash.
size_t hash() const {
- return ue2_hasher()(bits);
+ return ue2_hasher()(bits);
}
/// Sentinel value meaning "no more bits", used by find_first and
@@ -422,17 +422,17 @@ private:
std::array<block_type, num_blocks> bits;
};
-} // namespace ue2
-
-namespace std {
-
+} // namespace ue2
+
+namespace std {
+
template<size_t requested_size>
-struct hash<ue2::bitfield<requested_size>> {
- size_t operator()(const ue2::bitfield<requested_size> &b) const {
- return b.hash();
- }
-};
+struct hash<ue2::bitfield<requested_size>> {
+ size_t operator()(const ue2::bitfield<requested_size> &b) const {
+ return b.hash();
+ }
+};
-} // namespace std
+} // namespace std
#endif // BITFIELD_H
diff --git a/contrib/libs/hyperscan/src/util/bitutils.h b/contrib/libs/hyperscan/src/util/bitutils.h
index 1baa1c64b48..c545ee1872d 100644
--- a/contrib/libs/hyperscan/src/util/bitutils.h
+++ b/contrib/libs/hyperscan/src/util/bitutils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,13 +35,13 @@
#include "ue2common.h"
#include "popcount.h"
-#include "util/arch.h"
-#include "util/intrinsics.h"
+#include "util/arch.h"
+#include "util/intrinsics.h"
#define CASE_BIT 0x20
#define CASE_CLEAR 0xdf
#define DOUBLE_CASE_CLEAR 0xdfdf
-#define OCTO_CASE_CLEAR 0xdfdfdfdfdfdfdfdfULL
+#define OCTO_CASE_CLEAR 0xdfdfdfdfdfdfdfdfULL
static really_inline
u32 clz32(u32 x) {
@@ -58,20 +58,20 @@ u32 clz32(u32 x) {
static really_inline
u32 clz64(u64a x) {
assert(x); // behaviour not defined for x == 0
-#if defined(_WIN64)
+#if defined(_WIN64)
unsigned long r;
_BitScanReverse64(&r, x);
return 63 - r;
-#elif defined(_WIN32)
- unsigned long x1 = (u32)x;
- unsigned long x2 = (u32)(x >> 32);
- unsigned long r;
- if (x2) {
- _BitScanReverse(&r, x2);
- return (u32)(31 - r);
- }
- _BitScanReverse(&r, (u32)x1);
- return (u32)(63 - r);
+#elif defined(_WIN32)
+ unsigned long x1 = (u32)x;
+ unsigned long x2 = (u32)(x >> 32);
+ unsigned long r;
+ if (x2) {
+ _BitScanReverse(&r, x2);
+ return (u32)(31 - r);
+ }
+ _BitScanReverse(&r, (u32)x1);
+ return (u32)(63 - r);
#else
return (u32)__builtin_clzll(x);
#endif
@@ -93,17 +93,17 @@ u32 ctz32(u32 x) {
static really_inline
u32 ctz64(u64a x) {
assert(x); // behaviour not defined for x == 0
-#if defined(_WIN64)
+#if defined(_WIN64)
unsigned long r;
_BitScanForward64(&r, x);
return r;
-#elif defined(_WIN32)
- unsigned long r;
- if (_BitScanForward(&r, (u32)x)) {
- return (u32)r;
- }
- _BitScanForward(&r, x >> 32);
- return (u32)(r + 32);
+#elif defined(_WIN32)
+ unsigned long r;
+ if (_BitScanForward(&r, (u32)x)) {
+ return (u32)r;
+ }
+ _BitScanForward(&r, x >> 32);
+ return (u32)(r + 32);
#else
return (u32)__builtin_ctzll(x);
#endif
@@ -166,8 +166,8 @@ u32 findAndClearLSB_64(u64a *v) {
#else
// fall back to doing things with two 32-bit cases, since gcc-4.1 doesn't
// inline calls to __builtin_ctzll
- u32 v1 = (u32)*v;
- u32 v2 = (u32)(*v >> 32);
+ u32 v1 = (u32)*v;
+ u32 v2 = (u32)(*v >> 32);
u32 offset;
if (v1) {
offset = findAndClearLSB_32(&v1);
@@ -222,7 +222,7 @@ u32 findAndClearMSB_64(u64a *v) {
#else
// fall back to doing things with two 32-bit cases, since gcc-4.1 doesn't
// inline calls to __builtin_ctzll
- u32 v1 = (u32)*v;
+ u32 v1 = (u32)*v;
u32 v2 = (*v >> 32);
u32 offset;
if (v2) {
@@ -240,7 +240,7 @@ u32 findAndClearMSB_64(u64a *v) {
static really_inline
u32 compress32(u32 x, u32 m) {
-#if defined(HAVE_BMI2)
+#if defined(HAVE_BMI2)
// BMI2 has a single instruction for this operation.
return _pext_u32(x, m);
#else
@@ -275,7 +275,7 @@ u32 compress32(u32 x, u32 m) {
static really_inline
u64a compress64(u64a x, u64a m) {
-#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
+#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
// BMI2 has a single instruction for this operation.
return _pext_u64(x, m);
#else
@@ -311,7 +311,7 @@ u64a compress64(u64a x, u64a m) {
static really_inline
u32 expand32(u32 x, u32 m) {
-#if defined(HAVE_BMI2)
+#if defined(HAVE_BMI2)
// BMI2 has a single instruction for this operation.
return _pdep_u32(x, m);
#else
@@ -351,7 +351,7 @@ u32 expand32(u32 x, u32 m) {
static really_inline
u64a expand64(u64a x, u64a m) {
-#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
+#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
// BMI2 has a single instruction for this operation.
return _pdep_u64(x, m);
#else
@@ -426,67 +426,67 @@ void bf64_unset(u64a *bitfield, u32 i) {
*bitfield &= ~(1ULL << i);
}
-static really_inline
-u32 rank_in_mask32(u32 mask, u32 bit) {
- assert(bit < sizeof(u32) * 8);
- assert(mask & (u32)(1U << bit));
- mask &= (u32)(1U << bit) - 1;
- return popcount32(mask);
-}
-
-static really_inline
-u32 rank_in_mask64(u64a mask, u32 bit) {
- assert(bit < sizeof(u64a) * 8);
- assert(mask & (u64a)(1ULL << bit));
- mask &= (u64a)(1ULL << bit) - 1;
- return popcount64(mask);
-}
-
-static really_inline
-u32 pext32(u32 x, u32 mask) {
-#if defined(HAVE_BMI2)
- // Intel BMI2 can do this operation in one instruction.
- return _pext_u32(x, mask);
-#else
-
- u32 result = 0, num = 1;
- while (mask != 0) {
- u32 bit = findAndClearLSB_32(&mask);
- if (x & (1U << bit)) {
- assert(num != 0); // more than 32 bits!
- result |= num;
- }
- num <<= 1;
- }
- return result;
-#endif
-}
-
-static really_inline
-u64a pext64(u64a x, u64a mask) {
-#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
- // Intel BMI2 can do this operation in one instruction.
- return _pext_u64(x, mask);
-#else
-
- u32 result = 0, num = 1;
- while (mask != 0) {
- u32 bit = findAndClearLSB_64(&mask);
- if (x & (1ULL << bit)) {
- assert(num != 0); // more than 32 bits!
- result |= num;
- }
- num <<= 1;
- }
- return result;
-#endif
-}
-
-#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
-static really_inline
-u64a pdep64(u64a x, u64a mask) {
- return _pdep_u64(x, mask);
-}
-#endif
-
+static really_inline
+u32 rank_in_mask32(u32 mask, u32 bit) {
+ assert(bit < sizeof(u32) * 8);
+ assert(mask & (u32)(1U << bit));
+ mask &= (u32)(1U << bit) - 1;
+ return popcount32(mask);
+}
+
+static really_inline
+u32 rank_in_mask64(u64a mask, u32 bit) {
+ assert(bit < sizeof(u64a) * 8);
+ assert(mask & (u64a)(1ULL << bit));
+ mask &= (u64a)(1ULL << bit) - 1;
+ return popcount64(mask);
+}
+
+static really_inline
+u32 pext32(u32 x, u32 mask) {
+#if defined(HAVE_BMI2)
+ // Intel BMI2 can do this operation in one instruction.
+ return _pext_u32(x, mask);
+#else
+
+ u32 result = 0, num = 1;
+ while (mask != 0) {
+ u32 bit = findAndClearLSB_32(&mask);
+ if (x & (1U << bit)) {
+ assert(num != 0); // more than 32 bits!
+ result |= num;
+ }
+ num <<= 1;
+ }
+ return result;
+#endif
+}
+
+static really_inline
+u64a pext64(u64a x, u64a mask) {
+#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
+ // Intel BMI2 can do this operation in one instruction.
+ return _pext_u64(x, mask);
+#else
+
+ u32 result = 0, num = 1;
+ while (mask != 0) {
+ u32 bit = findAndClearLSB_64(&mask);
+ if (x & (1ULL << bit)) {
+ assert(num != 0); // more than 32 bits!
+ result |= num;
+ }
+ num <<= 1;
+ }
+ return result;
+#endif
+}
+
+#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
+static really_inline
+u64a pdep64(u64a x, u64a mask) {
+ return _pdep_u64(x, mask);
+}
+#endif
+
#endif // BITUTILS_H
diff --git a/contrib/libs/hyperscan/src/util/boundary_reports.h b/contrib/libs/hyperscan/src/util/boundary_reports.h
index f7c70c366aa..b2bb1c9b0a3 100644
--- a/contrib/libs/hyperscan/src/util/boundary_reports.h
+++ b/contrib/libs/hyperscan/src/util/boundary_reports.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,13 +30,13 @@
#define BOUNDARY_REPORTS_H
#include "ue2common.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include <set>
namespace ue2 {
-struct BoundaryReports : noncopyable {
+struct BoundaryReports : noncopyable {
std::set<ReportID> report_at_0; /* set of internal reports to fire
* unconditionally at offset 0 */
std::set<ReportID> report_at_0_eod; /* set of internal reports to fire
diff --git a/contrib/libs/hyperscan/src/util/bytecode_ptr.h b/contrib/libs/hyperscan/src/util/bytecode_ptr.h
index 58b0167ed4b..f1f2e5ef8ec 100644
--- a/contrib/libs/hyperscan/src/util/bytecode_ptr.h
+++ b/contrib/libs/hyperscan/src/util/bytecode_ptr.h
@@ -1,161 +1,161 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief bytecode_ptr: Smart pointer with unique ownership that knows its
- * length and alignment.
- */
-
-#ifndef UTIL_BYTECODE_PTR_H
-#define UTIL_BYTECODE_PTR_H
-
-#include "util/alloc.h"
-#include "util/operators.h"
-
-#include <algorithm> // std::max
-#include <cstring>
-#include <memory>
-#include <stdexcept> // std::logic_error
-
-namespace ue2 {
-
-/**
- * \brief Smart pointer that knows its length and alignment and behaves like a
- * std::unique_ptr -- i.e. it retains unique ownership of the memory region.
- *
- * This is intended to be used for flat aligned memory regions that will
- * eventually end up copied into the Hyperscan bytecode.
- */
-template<typename T>
-class bytecode_ptr : totally_ordered<bytecode_ptr<T>> {
-public:
- bytecode_ptr() = default;
- explicit bytecode_ptr(size_t bytes_in, size_t alignment_in = alignof(T))
- : bytes(bytes_in), alignment(alignment_in) {
- // posix_memalign doesn't like us asking for smaller alignment.
- size_t mem_align = std::max(alignment, sizeof(void *));
- ptr.reset(static_cast<T *>(aligned_malloc_internal(bytes, mem_align)));
- if (!ptr) {
- throw std::bad_alloc();
- }
- }
-
- bytecode_ptr(std::nullptr_t) {}
-
- T *get() const { return ptr.get(); }
-
- T &operator*() { return *ptr; }
- const T &operator*() const { return *ptr; }
-
- T *operator->() { return ptr.get(); }
- const T *operator->() const { return ptr.get(); }
-
- explicit operator bool() const { return ptr != nullptr; }
-
- /** \brief Move converter for shared_ptr. */
- template <typename ST, class = typename std::enable_if<
- std::is_convertible<T *, ST *>::value>::type>
- operator std::shared_ptr<ST>() && {
- auto d = ptr.get_deleter();
- return std::shared_ptr<ST>(ptr.release(), d);
- }
-
- void reset(T *p = nullptr) { ptr.reset(p); }
-
- T *release() {
- auto *p = ptr.release();
- bytes = 0;
- alignment = 0;
- return p;
- }
-
- void swap(bytecode_ptr &other) {
- using std::swap;
- swap(ptr, other.ptr);
- swap(bytes, other.bytes);
- swap(alignment, other.alignment);
- }
-
- /**
- * \brief Reduces the apparent size of the memory region. Note that this
- * does not reallocate and copy, it just changes the value returned by
- * size().
- */
- void shrink(size_t new_size) {
- if (new_size > bytes) {
- assert(0);
- throw std::logic_error("Must shrink to a smaller value");
- }
- bytes = new_size;
- }
-
- /** \brief Returns size of the memory region in bytes. */
- size_t size() const { return bytes; }
-
- /** \brief Returns alignment of the memory region in bytes. */
- size_t align() const { return alignment; }
-
- bool operator==(const bytecode_ptr &a) const { return ptr == a.ptr; }
- bool operator<(const bytecode_ptr &a) const { return ptr < a.ptr; }
-
-private:
- /** \brief Deleter function for std::unique_ptr. */
- template <typename DT> struct deleter {
- void operator()(DT *p) const { aligned_free_internal(p); }
- };
-
- std::unique_ptr<T, deleter<T>> ptr; //!< Underlying pointer.
- size_t bytes = 0; //!< Size of memory region in bytes.
- size_t alignment = 0; //!< Alignment of memory region in bytes.
-};
-
-/**
- * \brief Constructs a bytecode_ptr<T> with the given size and alignment.
- */
-template<typename T>
-inline bytecode_ptr<T> make_bytecode_ptr(size_t size,
- size_t align = alignof(T)) {
- return bytecode_ptr<T>(size, align);
-}
-
-/**
- * \brief Constructs a bytecode_ptr<T> with the given size and alignment and
- * fills the memory region with zeroes.
- */
-template<typename T>
-inline bytecode_ptr<T> make_zeroed_bytecode_ptr(size_t size,
- size_t align = alignof(T)) {
- auto ptr = make_bytecode_ptr<T>(size, align);
- std::memset(ptr.get(), 0, size);
- return ptr;
-}
-
-} // namespace ue2
-
-#endif // UTIL_BYTECODE_PTR_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief bytecode_ptr: Smart pointer with unique ownership that knows its
+ * length and alignment.
+ */
+
+#ifndef UTIL_BYTECODE_PTR_H
+#define UTIL_BYTECODE_PTR_H
+
+#include "util/alloc.h"
+#include "util/operators.h"
+
+#include <algorithm> // std::max
+#include <cstring>
+#include <memory>
+#include <stdexcept> // std::logic_error
+
+namespace ue2 {
+
+/**
+ * \brief Smart pointer that knows its length and alignment and behaves like a
+ * std::unique_ptr -- i.e. it retains unique ownership of the memory region.
+ *
+ * This is intended to be used for flat aligned memory regions that will
+ * eventually end up copied into the Hyperscan bytecode.
+ */
+template<typename T>
+class bytecode_ptr : totally_ordered<bytecode_ptr<T>> {
+public:
+ bytecode_ptr() = default;
+ explicit bytecode_ptr(size_t bytes_in, size_t alignment_in = alignof(T))
+ : bytes(bytes_in), alignment(alignment_in) {
+ // posix_memalign doesn't like us asking for smaller alignment.
+ size_t mem_align = std::max(alignment, sizeof(void *));
+ ptr.reset(static_cast<T *>(aligned_malloc_internal(bytes, mem_align)));
+ if (!ptr) {
+ throw std::bad_alloc();
+ }
+ }
+
+ bytecode_ptr(std::nullptr_t) {}
+
+ T *get() const { return ptr.get(); }
+
+ T &operator*() { return *ptr; }
+ const T &operator*() const { return *ptr; }
+
+ T *operator->() { return ptr.get(); }
+ const T *operator->() const { return ptr.get(); }
+
+ explicit operator bool() const { return ptr != nullptr; }
+
+ /** \brief Move converter for shared_ptr. */
+ template <typename ST, class = typename std::enable_if<
+ std::is_convertible<T *, ST *>::value>::type>
+ operator std::shared_ptr<ST>() && {
+ auto d = ptr.get_deleter();
+ return std::shared_ptr<ST>(ptr.release(), d);
+ }
+
+ void reset(T *p = nullptr) { ptr.reset(p); }
+
+ T *release() {
+ auto *p = ptr.release();
+ bytes = 0;
+ alignment = 0;
+ return p;
+ }
+
+ void swap(bytecode_ptr &other) {
+ using std::swap;
+ swap(ptr, other.ptr);
+ swap(bytes, other.bytes);
+ swap(alignment, other.alignment);
+ }
+
+ /**
+ * \brief Reduces the apparent size of the memory region. Note that this
+ * does not reallocate and copy, it just changes the value returned by
+ * size().
+ */
+ void shrink(size_t new_size) {
+ if (new_size > bytes) {
+ assert(0);
+ throw std::logic_error("Must shrink to a smaller value");
+ }
+ bytes = new_size;
+ }
+
+ /** \brief Returns size of the memory region in bytes. */
+ size_t size() const { return bytes; }
+
+ /** \brief Returns alignment of the memory region in bytes. */
+ size_t align() const { return alignment; }
+
+ bool operator==(const bytecode_ptr &a) const { return ptr == a.ptr; }
+ bool operator<(const bytecode_ptr &a) const { return ptr < a.ptr; }
+
+private:
+ /** \brief Deleter function for std::unique_ptr. */
+ template <typename DT> struct deleter {
+ void operator()(DT *p) const { aligned_free_internal(p); }
+ };
+
+ std::unique_ptr<T, deleter<T>> ptr; //!< Underlying pointer.
+ size_t bytes = 0; //!< Size of memory region in bytes.
+ size_t alignment = 0; //!< Alignment of memory region in bytes.
+};
+
+/**
+ * \brief Constructs a bytecode_ptr<T> with the given size and alignment.
+ */
+template<typename T>
+inline bytecode_ptr<T> make_bytecode_ptr(size_t size,
+ size_t align = alignof(T)) {
+ return bytecode_ptr<T>(size, align);
+}
+
+/**
+ * \brief Constructs a bytecode_ptr<T> with the given size and alignment and
+ * fills the memory region with zeroes.
+ */
+template<typename T>
+inline bytecode_ptr<T> make_zeroed_bytecode_ptr(size_t size,
+ size_t align = alignof(T)) {
+ auto ptr = make_bytecode_ptr<T>(size, align);
+ std::memset(ptr.get(), 0, size);
+ return ptr;
+}
+
+} // namespace ue2
+
+#endif // UTIL_BYTECODE_PTR_H
diff --git a/contrib/libs/hyperscan/src/util/charreach.cpp b/contrib/libs/hyperscan/src/util/charreach.cpp
index 18b6b6be74e..9116b719db3 100644
--- a/contrib/libs/hyperscan/src/util/charreach.cpp
+++ b/contrib/libs/hyperscan/src/util/charreach.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/util/charreach.h b/contrib/libs/hyperscan/src/util/charreach.h
index 12df7d3711e..f6d3a2af3eb 100644
--- a/contrib/libs/hyperscan/src/util/charreach.h
+++ b/contrib/libs/hyperscan/src/util/charreach.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -135,38 +135,38 @@ public:
size_t find_nth(size_t n) const { return bits.find_nth(n); }
/// Bitwise OR.
- CharReach operator|(const CharReach &a) const {
- CharReach cr(*this);
- cr.bits |= a.bits;
- return cr;
- }
+ CharReach operator|(const CharReach &a) const {
+ CharReach cr(*this);
+ cr.bits |= a.bits;
+ return cr;
+ }
/// Bitwise OR-equals.
- void operator|=(const CharReach &a) { bits |= a.bits; }
+ void operator|=(const CharReach &a) { bits |= a.bits; }
/// Bitwise AND.
- CharReach operator&(const CharReach &a) const {
- CharReach cr(*this);
- cr.bits &= a.bits;
- return cr;
- }
+ CharReach operator&(const CharReach &a) const {
+ CharReach cr(*this);
+ cr.bits &= a.bits;
+ return cr;
+ }
/// Bitwise AND-equals.
- void operator&=(const CharReach &a) { bits &= a.bits; }
+ void operator&=(const CharReach &a) { bits &= a.bits; }
/// Bitwise XOR.
- CharReach operator^(const CharReach &a) const {
- CharReach cr(*this);
- cr.bits ^= a.bits;
- return cr;
- }
+ CharReach operator^(const CharReach &a) const {
+ CharReach cr(*this);
+ cr.bits ^= a.bits;
+ return cr;
+ }
/// Bitwise complement.
- CharReach operator~(void) const {
- CharReach cr(*this);
- cr.flip();
- return cr;
- }
+ CharReach operator~(void) const {
+ CharReach cr(*this);
+ cr.flip();
+ return cr;
+ }
/// Do we only contain bits representing alpha characters?
bool isAlpha() const;
@@ -198,15 +198,15 @@ bool isutf8start(const CharReach &cr);
} // namespace ue2
-namespace std {
-
-template<>
-struct hash<ue2::CharReach> {
- size_t operator()(const ue2::CharReach &cr) const {
- return cr.hash();
- }
-};
-
-} // namespace std
-
+namespace std {
+
+template<>
+struct hash<ue2::CharReach> {
+ size_t operator()(const ue2::CharReach &cr) const {
+ return cr.hash();
+ }
+};
+
+} // namespace std
+
#endif // NG_CHARREACH_H
diff --git a/contrib/libs/hyperscan/src/util/charreach_util.h b/contrib/libs/hyperscan/src/util/charreach_util.h
index b843482dd15..f0dc4227b01 100644
--- a/contrib/libs/hyperscan/src/util/charreach_util.h
+++ b/contrib/libs/hyperscan/src/util/charreach_util.h
@@ -29,11 +29,11 @@
#ifndef CHARREACH_UTIL_H
#define CHARREACH_UTIL_H
-#include "ue2common.h"
+#include "ue2common.h"
namespace ue2 {
-class CharReach;
+class CharReach;
void make_caseless(CharReach *cr);
diff --git a/contrib/libs/hyperscan/src/util/clique.cpp b/contrib/libs/hyperscan/src/util/clique.cpp
index f6e07571ad6..c2befea4971 100644
--- a/contrib/libs/hyperscan/src/util/clique.cpp
+++ b/contrib/libs/hyperscan/src/util/clique.cpp
@@ -1,130 +1,130 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief An algorithm to find cliques.
- */
-
-#include "clique.h"
-#include "container.h"
-#include "graph_range.h"
-#include "make_unique.h"
-
-#include <map>
-#include <set>
-#include <stack>
-
-using namespace std;
-
-namespace ue2 {
-
-static
-vector<u32> getNeighborInfo(const CliqueGraph &g,
- const CliqueVertex &cv, const set<u32> &group) {
- u32 id = g[cv].stateId;
- vector<u32> neighbor;
- // find neighbors for cv
- for (const auto &v : adjacent_vertices_range(cv, g)) {
- if (g[v].stateId != id && contains(group, g[v].stateId)){
- neighbor.push_back(g[v].stateId);
- DEBUG_PRINTF("Neighbor:%u\n", g[v].stateId);
- }
- }
-
- return neighbor;
-}
-
-static
-vector<u32> findCliqueGroup(CliqueGraph &cg) {
- stack<vector<u32>> gStack;
-
- // Create mapping between vertex and id
- map<u32, CliqueVertex> vertexMap;
- vector<u32> init;
- for (const auto &v : vertices_range(cg)) {
- vertexMap[cg[v].stateId] = v;
- init.push_back(cg[v].stateId);
- }
- gStack.push(init);
-
- // Get the vertex to start from
- vector<u32> clique;
- while (!gStack.empty()) {
- vector<u32> g = move(gStack.top());
- gStack.pop();
-
- // Choose a vertex from the graph
- u32 id = g[0];
- CliqueVertex &n = vertexMap.at(id);
- clique.push_back(id);
- // Corresponding vertex in the original graph
- set<u32> subgraphId(g.begin(), g.end());
- auto neighbor = getNeighborInfo(cg, n, subgraphId);
- // Get graph consisting of neighbors for left branch
- if (!neighbor.empty()) {
- gStack.push(neighbor);
- }
- }
-
- return clique;
-}
-
-template<typename Graph>
-bool graph_empty(const Graph &g) {
- typename Graph::vertex_iterator vi, ve;
- tie(vi, ve) = vertices(g);
- return vi == ve;
-}
-
-vector<vector<u32>> removeClique(CliqueGraph &cg) {
- DEBUG_PRINTF("graph size:%zu\n", num_vertices(cg));
- vector<vector<u32>> cliquesVec = {findCliqueGroup(cg)};
- while (!graph_empty(cg)) {
- const vector<u32> &c = cliquesVec.back();
- vector<CliqueVertex> dead;
- for (const auto &v : vertices_range(cg)) {
- u32 id = cg[v].stateId;
- if (find(c.begin(), c.end(), id) != c.end()) {
- dead.push_back(v);
- }
- }
- for (const auto &v : dead) {
- clear_vertex(v, cg);
- remove_vertex(v, cg);
- }
- if (graph_empty(cg)) {
- break;
- }
- auto clique = findCliqueGroup(cg);
- cliquesVec.push_back(clique);
- }
-
- return cliquesVec;
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief An algorithm to find cliques.
+ */
+
+#include "clique.h"
+#include "container.h"
+#include "graph_range.h"
+#include "make_unique.h"
+
+#include <map>
+#include <set>
+#include <stack>
+
+using namespace std;
+
+namespace ue2 {
+
+static
+vector<u32> getNeighborInfo(const CliqueGraph &g,
+ const CliqueVertex &cv, const set<u32> &group) {
+ u32 id = g[cv].stateId;
+ vector<u32> neighbor;
+ // find neighbors for cv
+ for (const auto &v : adjacent_vertices_range(cv, g)) {
+ if (g[v].stateId != id && contains(group, g[v].stateId)){
+ neighbor.push_back(g[v].stateId);
+ DEBUG_PRINTF("Neighbor:%u\n", g[v].stateId);
+ }
+ }
+
+ return neighbor;
+}
+
+static
+vector<u32> findCliqueGroup(CliqueGraph &cg) {
+ stack<vector<u32>> gStack;
+
+ // Create mapping between vertex and id
+ map<u32, CliqueVertex> vertexMap;
+ vector<u32> init;
+ for (const auto &v : vertices_range(cg)) {
+ vertexMap[cg[v].stateId] = v;
+ init.push_back(cg[v].stateId);
+ }
+ gStack.push(init);
+
+ // Get the vertex to start from
+ vector<u32> clique;
+ while (!gStack.empty()) {
+ vector<u32> g = move(gStack.top());
+ gStack.pop();
+
+ // Choose a vertex from the graph
+ u32 id = g[0];
+ CliqueVertex &n = vertexMap.at(id);
+ clique.push_back(id);
+ // Corresponding vertex in the original graph
+ set<u32> subgraphId(g.begin(), g.end());
+ auto neighbor = getNeighborInfo(cg, n, subgraphId);
+ // Get graph consisting of neighbors for left branch
+ if (!neighbor.empty()) {
+ gStack.push(neighbor);
+ }
+ }
+
+ return clique;
+}
+
+template<typename Graph>
+bool graph_empty(const Graph &g) {
+ typename Graph::vertex_iterator vi, ve;
+ tie(vi, ve) = vertices(g);
+ return vi == ve;
+}
+
+vector<vector<u32>> removeClique(CliqueGraph &cg) {
+ DEBUG_PRINTF("graph size:%zu\n", num_vertices(cg));
+ vector<vector<u32>> cliquesVec = {findCliqueGroup(cg)};
+ while (!graph_empty(cg)) {
+ const vector<u32> &c = cliquesVec.back();
+ vector<CliqueVertex> dead;
+ for (const auto &v : vertices_range(cg)) {
+ u32 id = cg[v].stateId;
+ if (find(c.begin(), c.end(), id) != c.end()) {
+ dead.push_back(v);
+ }
+ }
+ for (const auto &v : dead) {
+ clear_vertex(v, cg);
+ remove_vertex(v, cg);
+ }
+ if (graph_empty(cg)) {
+ break;
+ }
+ auto clique = findCliqueGroup(cg);
+ cliquesVec.push_back(clique);
+ }
+
+ return cliquesVec;
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/util/clique.h b/contrib/libs/hyperscan/src/util/clique.h
index 4886c8b7ddd..89c6d4ed488 100644
--- a/contrib/libs/hyperscan/src/util/clique.h
+++ b/contrib/libs/hyperscan/src/util/clique.h
@@ -1,60 +1,60 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief An algorithm to find cliques.
- */
-
-#ifndef CLIQUE_H
-#define CLIQUE_H
-
-#include "ue2common.h"
-
-#include <vector>
-
-#include <boost/graph/adjacency_list.hpp>
-
-namespace ue2 {
-
-struct CliqueVertexProps {
- CliqueVertexProps() {}
- explicit CliqueVertexProps(u32 state_in) : stateId(state_in) {}
-
- u32 stateId = ~0U;
-};
-
-typedef boost::adjacency_list<boost::listS, boost::listS, boost::undirectedS,
- CliqueVertexProps> CliqueGraph;
-typedef CliqueGraph::vertex_descriptor CliqueVertex;
-
-/** \brief Returns a vector of cliques found in a graph. */
-std::vector<std::vector<u32>> removeClique(CliqueGraph &cg);
-
-} // namespace ue2
-
-#endif
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief An algorithm to find cliques.
+ */
+
+#ifndef CLIQUE_H
+#define CLIQUE_H
+
+#include "ue2common.h"
+
+#include <vector>
+
+#include <boost/graph/adjacency_list.hpp>
+
+namespace ue2 {
+
+struct CliqueVertexProps {
+ CliqueVertexProps() {}
+ explicit CliqueVertexProps(u32 state_in) : stateId(state_in) {}
+
+ u32 stateId = ~0U;
+};
+
+typedef boost::adjacency_list<boost::listS, boost::listS, boost::undirectedS,
+ CliqueVertexProps> CliqueGraph;
+typedef CliqueGraph::vertex_descriptor CliqueVertex;
+
+/** \brief Returns a vector of cliques found in a graph. */
+std::vector<std::vector<u32>> removeClique(CliqueGraph &cg);
+
+} // namespace ue2
+
+#endif
diff --git a/contrib/libs/hyperscan/src/util/compare.h b/contrib/libs/hyperscan/src/util/compare.h
index ca1114aa47a..eaa717a4c29 100644
--- a/contrib/libs/hyperscan/src/util/compare.h
+++ b/contrib/libs/hyperscan/src/util/compare.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -97,10 +97,10 @@ u64a theirtoupper64(const u64a x) {
static really_inline
int cmpNocaseNaive(const u8 *p1, const u8 *p2, size_t len) {
- const u8 *pEnd = p1 + len;
+ const u8 *pEnd = p1 + len;
for (; p1 < pEnd; p1++, p2++) {
- assert(!ourisalpha(*p2) || myisupper(*p2)); // Already upper-case.
- if ((u8)mytoupper(*p1) != *p2) {
+ assert(!ourisalpha(*p2) || myisupper(*p2)); // Already upper-case.
+ if ((u8)mytoupper(*p1) != *p2) {
return 1;
}
}
@@ -109,7 +109,7 @@ int cmpNocaseNaive(const u8 *p1, const u8 *p2, size_t len) {
static really_inline
int cmpCaseNaive(const u8 *p1, const u8 *p2, size_t len) {
- const u8 *pEnd = p1 + len;
+ const u8 *pEnd = p1 + len;
for (; p1 < pEnd; p1++, p2++) {
if (*p1 != *p2) {
return 1;
@@ -130,11 +130,11 @@ int cmpCaseNaive(const u8 *p1, const u8 *p2, size_t len) {
#define CMP_SIZE sizeof(CMP_T)
-/**
- * \brief Compare two strings, optionally caselessly.
- *
- * Note: If nocase is true, p2 is assumed to be already upper-case.
- */
+/**
+ * \brief Compare two strings, optionally caselessly.
+ *
+ * Note: If nocase is true, p2 is assumed to be already upper-case.
+ */
#if defined(ARCH_IA32)
static UNUSED never_inline
#else
@@ -151,13 +151,13 @@ int cmpForward(const u8 *p1, const u8 *p2, size_t len, char nocase) {
if (nocase) { // Case-insensitive version.
for (; p1 < p1_end; p1 += CMP_SIZE, p2 += CMP_SIZE) {
- assert(ULOAD(p2) == TOUPPER(ULOAD(p2))); // Already upper-case.
- if (TOUPPER(ULOAD(p1)) != ULOAD(p2)) {
+ assert(ULOAD(p2) == TOUPPER(ULOAD(p2))); // Already upper-case.
+ if (TOUPPER(ULOAD(p1)) != ULOAD(p2)) {
return 1;
}
}
- assert(ULOAD(p2_end) == TOUPPER(ULOAD(p2_end))); // Already upper-case.
- if (TOUPPER(ULOAD(p1_end)) != ULOAD(p2_end)) {
+ assert(ULOAD(p2_end) == TOUPPER(ULOAD(p2_end))); // Already upper-case.
+ if (TOUPPER(ULOAD(p1_end)) != ULOAD(p2_end)) {
return 1;
}
} else { // Case-sensitive version.
diff --git a/contrib/libs/hyperscan/src/util/container.h b/contrib/libs/hyperscan/src/util/container.h
index dd329d9b805..68f60e99eed 100644
--- a/contrib/libs/hyperscan/src/util/container.h
+++ b/contrib/libs/hyperscan/src/util/container.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -41,7 +41,7 @@
#include <set>
#include <type_traits>
#include <utility>
-#include <vector>
+#include <vector>
namespace ue2 {
@@ -79,9 +79,9 @@ void insert(C *container, typename C::iterator pos, const D &donor) {
}
/**
- * \brief Constructs a vector from a range bounded by the given pair of
- * iterators.
- */
+ * \brief Constructs a vector from a range bounded by the given pair of
+ * iterators.
+ */
template <typename It>
auto make_vector_from(const std::pair<It, It> &range)
-> std::vector<decltype(*range.first)> {
@@ -89,14 +89,14 @@ auto make_vector_from(const std::pair<It, It> &range)
return std::vector<T>(range.first, range.second);
}
-/** \brief Sort a sequence container and remove duplicates. */
-template <typename C, typename Compare = std::less<typename C::value_type>>
-void sort_and_unique(C &container, Compare comp = Compare()) {
- std::sort(std::begin(container), std::end(container), comp);
- container.erase(std::unique(std::begin(container), std::end(container)),
- std::end(container));
-}
-
+/** \brief Sort a sequence container and remove duplicates. */
+template <typename C, typename Compare = std::less<typename C::value_type>>
+void sort_and_unique(C &container, Compare comp = Compare()) {
+ std::sort(std::begin(container), std::end(container), comp);
+ container.erase(std::unique(std::begin(container), std::end(container)),
+ std::end(container));
+}
+
/** \brief Returns a set containing the keys in the given associative
* container. */
template <typename C>
@@ -111,9 +111,9 @@ std::set<typename C::key_type> assoc_keys(const C &container) {
/**
* \brief Return the length in bytes of the given vector of (POD) objects.
*/
-template <typename T, typename Alloc>
-typename std::vector<T, Alloc>::size_type
-byte_length(const std::vector<T, Alloc> &vec) {
+template <typename T, typename Alloc>
+typename std::vector<T, Alloc>::size_type
+byte_length(const std::vector<T, Alloc> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
return vec.size() * sizeof(T);
}
@@ -122,8 +122,8 @@ byte_length(const std::vector<T, Alloc> &vec) {
* \brief Copy the given vector of POD objects to the given location in memory.
* It is safe to give this function an empty vector.
*/
-template<typename T, typename Alloc>
-void *copy_bytes(void *dest, const std::vector<T, Alloc> &vec) {
+template<typename T, typename Alloc>
+void *copy_bytes(void *dest, const std::vector<T, Alloc> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
assert(dest);
@@ -202,17 +202,17 @@ void erase_all(C *container, const D &donor) {
}
}
-
-template<typename C, typename Pred>
-bool any_of_in(const C &c, Pred p) {
- return std::any_of(c.begin(), c.end(), std::move(p));
-}
-
-template<typename C, typename Pred>
-bool all_of_in(const C &c, Pred p) {
- return std::all_of(c.begin(), c.end(), std::move(p));
-}
-
+
+template<typename C, typename Pred>
+bool any_of_in(const C &c, Pred p) {
+ return std::any_of(c.begin(), c.end(), std::move(p));
+}
+
+template<typename C, typename Pred>
+bool all_of_in(const C &c, Pred p) {
+ return std::all_of(c.begin(), c.end(), std::move(p));
+}
+
} // namespace ue2
#ifdef DUMP_SUPPORT
diff --git a/contrib/libs/hyperscan/src/util/copybytes.h b/contrib/libs/hyperscan/src/util/copybytes.h
index aa146153594..7f37d96bc5f 100644
--- a/contrib/libs/hyperscan/src/util/copybytes.h
+++ b/contrib/libs/hyperscan/src/util/copybytes.h
@@ -1,77 +1,77 @@
-/*
+/*
* Copyright (c) 2016-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef COPY_BYTES_H
-#define COPY_BYTES_H
-
-#include "unaligned.h"
-#include "simd_utils.h"
-
-static really_inline
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef COPY_BYTES_H
+#define COPY_BYTES_H
+
+#include "unaligned.h"
+#include "simd_utils.h"
+
+static really_inline
void copy_upto_64_bytes(u8 *dst, const u8 *src, unsigned int len) {
- switch (len) {
- case 0:
- break;
- case 1:
- *dst = *src;
- break;
- case 2:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- break;
- case 3:
- unaligned_store_u16(dst, unaligned_load_u16(src));
- dst[2] = src[2];
- break;
- case 4:
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 5:
- case 6:
- case 7:
- unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
- unaligned_store_u32(dst, unaligned_load_u32(src));
- break;
- case 8:
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
- unaligned_store_u64a(dst, unaligned_load_u64a(src));
- break;
- case 16:
- storeu128(dst, loadu128(src));
- break;
+ switch (len) {
+ case 0:
+ break;
+ case 1:
+ *dst = *src;
+ break;
+ case 2:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ break;
+ case 3:
+ unaligned_store_u16(dst, unaligned_load_u16(src));
+ dst[2] = src[2];
+ break;
+ case 4:
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 5:
+ case 6:
+ case 7:
+ unaligned_store_u32(dst + len - 4, unaligned_load_u32(src + len - 4));
+ unaligned_store_u32(dst, unaligned_load_u32(src));
+ break;
+ case 8:
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ unaligned_store_u64a(dst + len - 8, unaligned_load_u64a(src + len - 8));
+ unaligned_store_u64a(dst, unaligned_load_u64a(src));
+ break;
+ case 16:
+ storeu128(dst, loadu128(src));
+ break;
case 17:
case 18:
case 19:
@@ -90,24 +90,24 @@ void copy_upto_64_bytes(u8 *dst, const u8 *src, unsigned int len) {
storeu128(dst + len - 16, loadu128(src + len - 16));
storeu128(dst, loadu128(src));
break;
- case 32:
- storeu256(dst, loadu256(src));
- break;
+ case 32:
+ storeu256(dst, loadu256(src));
+ break;
#ifdef HAVE_AVX512
case 64:
storebytes512(dst, loadu512(src), 64);
break;
- default:
+ default:
assert(len < 64);
u64a k = (1ULL << len) - 1;
storeu_mask_m512(dst, k, loadu_maskz_m512(k, src));
- break;
+ break;
#else
default:
assert(0);
break;
#endif
- }
-}
-
-#endif
+ }
+}
+
+#endif
diff --git a/contrib/libs/hyperscan/src/util/cpuid_flags.c b/contrib/libs/hyperscan/src/util/cpuid_flags.c
index c15aafc0eeb..c00ce58e2d9 100644
--- a/contrib/libs/hyperscan/src/util/cpuid_flags.c
+++ b/contrib/libs/hyperscan/src/util/cpuid_flags.c
@@ -27,43 +27,43 @@
*/
#include "cpuid_flags.h"
-#include "cpuid_inline.h"
+#include "cpuid_inline.h"
#include "ue2common.h"
#include "hs_compile.h" // for HS_MODE_ flags
#include "hs_internal.h"
-#include "util/arch.h"
+#include "util/arch.h"
-#if !defined(_WIN32) && !defined(CPUID_H_)
+#if !defined(_WIN32) && !defined(CPUID_H_)
#include <cpuid.h>
#endif
u64a cpuid_flags(void) {
u64a cap = 0;
- if (check_avx2()) {
- DEBUG_PRINTF("AVX2 enabled\n");
+ if (check_avx2()) {
+ DEBUG_PRINTF("AVX2 enabled\n");
cap |= HS_CPU_FEATURES_AVX2;
}
- if (check_avx512()) {
- DEBUG_PRINTF("AVX512 enabled\n");
- cap |= HS_CPU_FEATURES_AVX512;
- }
-
+ if (check_avx512()) {
+ DEBUG_PRINTF("AVX512 enabled\n");
+ cap |= HS_CPU_FEATURES_AVX512;
+ }
+
if (check_avx512vbmi()) {
DEBUG_PRINTF("AVX512VBMI enabled\n");
cap |= HS_CPU_FEATURES_AVX512VBMI;
}
-#if !defined(FAT_RUNTIME) && !defined(HAVE_AVX2)
+#if !defined(FAT_RUNTIME) && !defined(HAVE_AVX2)
cap &= ~HS_CPU_FEATURES_AVX2;
#endif
-#if (!defined(FAT_RUNTIME) && !defined(HAVE_AVX512)) || \
- (defined(FAT_RUNTIME) && !defined(BUILD_AVX512))
- cap &= ~HS_CPU_FEATURES_AVX512;
-#endif
-
+#if (!defined(FAT_RUNTIME) && !defined(HAVE_AVX512)) || \
+ (defined(FAT_RUNTIME) && !defined(BUILD_AVX512))
+ cap &= ~HS_CPU_FEATURES_AVX512;
+#endif
+
#if (!defined(FAT_RUNTIME) && !defined(HAVE_AVX512VBMI)) || \
(defined(FAT_RUNTIME) && !defined(BUILD_AVX512VBMI))
cap &= ~HS_CPU_FEATURES_AVX512VBMI;
@@ -83,37 +83,37 @@ struct family_id {
* Family Numbers" */
static const struct family_id known_microarch[] = {
{ 0x6, 0x37, HS_TUNE_FAMILY_SLM }, /* baytrail */
- { 0x6, 0x4A, HS_TUNE_FAMILY_SLM }, /* silvermont */
- { 0x6, 0x4C, HS_TUNE_FAMILY_SLM }, /* silvermont */
+ { 0x6, 0x4A, HS_TUNE_FAMILY_SLM }, /* silvermont */
+ { 0x6, 0x4C, HS_TUNE_FAMILY_SLM }, /* silvermont */
{ 0x6, 0x4D, HS_TUNE_FAMILY_SLM }, /* avoton, rangley */
- { 0x6, 0x5A, HS_TUNE_FAMILY_SLM }, /* silvermont */
- { 0x6, 0x5D, HS_TUNE_FAMILY_SLM }, /* silvermont */
+ { 0x6, 0x5A, HS_TUNE_FAMILY_SLM }, /* silvermont */
+ { 0x6, 0x5D, HS_TUNE_FAMILY_SLM }, /* silvermont */
+
+ { 0x6, 0x5C, HS_TUNE_FAMILY_GLM }, /* goldmont */
+ { 0x6, 0x5F, HS_TUNE_FAMILY_GLM }, /* denverton */
- { 0x6, 0x5C, HS_TUNE_FAMILY_GLM }, /* goldmont */
- { 0x6, 0x5F, HS_TUNE_FAMILY_GLM }, /* denverton */
-
{ 0x6, 0x3C, HS_TUNE_FAMILY_HSW }, /* haswell */
{ 0x6, 0x45, HS_TUNE_FAMILY_HSW }, /* haswell */
{ 0x6, 0x46, HS_TUNE_FAMILY_HSW }, /* haswell */
- { 0x6, 0x3F, HS_TUNE_FAMILY_HSW }, /* haswell Xeon */
+ { 0x6, 0x3F, HS_TUNE_FAMILY_HSW }, /* haswell Xeon */
- { 0x6, 0x3E, HS_TUNE_FAMILY_IVB }, /* ivybridge Xeon */
+ { 0x6, 0x3E, HS_TUNE_FAMILY_IVB }, /* ivybridge Xeon */
{ 0x6, 0x3A, HS_TUNE_FAMILY_IVB }, /* ivybridge */
{ 0x6, 0x2A, HS_TUNE_FAMILY_SNB }, /* sandybridge */
- { 0x6, 0x2D, HS_TUNE_FAMILY_SNB }, /* sandybridge Xeon */
+ { 0x6, 0x2D, HS_TUNE_FAMILY_SNB }, /* sandybridge Xeon */
{ 0x6, 0x3D, HS_TUNE_FAMILY_BDW }, /* broadwell Core-M */
- { 0x6, 0x47, HS_TUNE_FAMILY_BDW }, /* broadwell */
+ { 0x6, 0x47, HS_TUNE_FAMILY_BDW }, /* broadwell */
{ 0x6, 0x4F, HS_TUNE_FAMILY_BDW }, /* broadwell xeon */
{ 0x6, 0x56, HS_TUNE_FAMILY_BDW }, /* broadwell xeon-d */
- { 0x6, 0x4E, HS_TUNE_FAMILY_SKL }, /* Skylake Mobile */
- { 0x6, 0x5E, HS_TUNE_FAMILY_SKL }, /* Skylake Core/E3 Xeon */
- { 0x6, 0x55, HS_TUNE_FAMILY_SKX }, /* Skylake Xeon */
+ { 0x6, 0x4E, HS_TUNE_FAMILY_SKL }, /* Skylake Mobile */
+ { 0x6, 0x5E, HS_TUNE_FAMILY_SKL }, /* Skylake Core/E3 Xeon */
+ { 0x6, 0x55, HS_TUNE_FAMILY_SKX }, /* Skylake Xeon */
- { 0x6, 0x8E, HS_TUNE_FAMILY_SKL }, /* Kabylake Mobile */
- { 0x6, 0x9E, HS_TUNE_FAMILY_SKL }, /* Kabylake desktop */
+ { 0x6, 0x8E, HS_TUNE_FAMILY_SKL }, /* Kabylake Mobile */
+ { 0x6, 0x9E, HS_TUNE_FAMILY_SKL }, /* Kabylake desktop */
{ 0x6, 0x7D, HS_TUNE_FAMILY_ICL }, /* Icelake */
{ 0x6, 0x7E, HS_TUNE_FAMILY_ICL }, /* Icelake */
@@ -128,13 +128,13 @@ const char *dumpTune(u32 tune) {
#define T_CASE(x) case x: return #x;
switch (tune) {
T_CASE(HS_TUNE_FAMILY_SLM);
- T_CASE(HS_TUNE_FAMILY_GLM);
+ T_CASE(HS_TUNE_FAMILY_GLM);
T_CASE(HS_TUNE_FAMILY_HSW);
T_CASE(HS_TUNE_FAMILY_SNB);
T_CASE(HS_TUNE_FAMILY_IVB);
T_CASE(HS_TUNE_FAMILY_BDW);
- T_CASE(HS_TUNE_FAMILY_SKL);
- T_CASE(HS_TUNE_FAMILY_SKX);
+ T_CASE(HS_TUNE_FAMILY_SKL);
+ T_CASE(HS_TUNE_FAMILY_SKX);
T_CASE(HS_TUNE_FAMILY_ICL);
T_CASE(HS_TUNE_FAMILY_ICX);
}
diff --git a/contrib/libs/hyperscan/src/util/cpuid_flags.h b/contrib/libs/hyperscan/src/util/cpuid_flags.h
index 3d5d63cee73..527c6d52f39 100644
--- a/contrib/libs/hyperscan/src/util/cpuid_flags.h
+++ b/contrib/libs/hyperscan/src/util/cpuid_flags.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,17 +26,17 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef UTIL_CPUID_H_
-#define UTIL_CPUID_H_
+#ifndef UTIL_CPUID_H_
+#define UTIL_CPUID_H_
#include "ue2common.h"
-#if !defined(_WIN32) && !defined(CPUID_H_)
-#include <cpuid.h>
- /* system header doesn't have a header guard */
-#define CPUID_H_
-#endif
-
+#if !defined(_WIN32) && !defined(CPUID_H_)
+#include <cpuid.h>
+ /* system header doesn't have a header guard */
+#define CPUID_H_
+#endif
+
#ifdef __cplusplus
extern "C"
{
@@ -51,5 +51,5 @@ u32 cpuid_tune(void);
} /* extern "C" */
#endif
-#endif /* UTIL_CPUID_H_ */
+#endif /* UTIL_CPUID_H_ */
diff --git a/contrib/libs/hyperscan/src/util/cpuid_inline.h b/contrib/libs/hyperscan/src/util/cpuid_inline.h
index 49515d23b91..b7b42452898 100644
--- a/contrib/libs/hyperscan/src/util/cpuid_inline.h
+++ b/contrib/libs/hyperscan/src/util/cpuid_inline.h
@@ -1,193 +1,193 @@
-/*
+/*
* Copyright (c) 2017-2020, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef CPUID_INLINE_H_
-#define CPUID_INLINE_H_
-
-#include "ue2common.h"
-#include "cpuid_flags.h"
-
-#if !defined(_WIN32) && !defined(CPUID_H_)
-#include <cpuid.h>
-/* system header doesn't have a header guard */
-#define CPUID_H_
-#endif
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-static inline
-void cpuid(unsigned int op, unsigned int leaf, unsigned int *eax,
- unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
-#ifndef _WIN32
- __cpuid_count(op, leaf, *eax, *ebx, *ecx, *edx);
-#else
- int a[4];
- __cpuidex(a, op, leaf);
- *eax = a[0];
- *ebx = a[1];
- *ecx = a[2];
- *edx = a[3];
-#endif
-}
-
-// ECX
-#define CPUID_SSE3 (1 << 0)
-#define CPUID_SSSE3 (1 << 9)
-#define CPUID_SSE4_1 (1 << 19)
-#define CPUID_SSE4_2 (1 << 20)
-#define CPUID_POPCNT (1 << 23)
-#define CPUID_XSAVE (1 << 27)
-#define CPUID_AVX (1 << 28)
-
-// EDX
-#define CPUID_FXSAVE (1 << 24)
-#define CPUID_SSE (1 << 25)
-#define CPUID_SSE2 (1 << 26)
-#define CPUID_HTT (1 << 28)
-
-// Structured Extended Feature Flags Enumeration Leaf ECX values
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef CPUID_INLINE_H_
+#define CPUID_INLINE_H_
+
+#include "ue2common.h"
+#include "cpuid_flags.h"
+
+#if !defined(_WIN32) && !defined(CPUID_H_)
+#include <cpuid.h>
+/* system header doesn't have a header guard */
+#define CPUID_H_
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static inline
+void cpuid(unsigned int op, unsigned int leaf, unsigned int *eax,
+ unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
+#ifndef _WIN32
+ __cpuid_count(op, leaf, *eax, *ebx, *ecx, *edx);
+#else
+ int a[4];
+ __cpuidex(a, op, leaf);
+ *eax = a[0];
+ *ebx = a[1];
+ *ecx = a[2];
+ *edx = a[3];
+#endif
+}
+
+// ECX
+#define CPUID_SSE3 (1 << 0)
+#define CPUID_SSSE3 (1 << 9)
+#define CPUID_SSE4_1 (1 << 19)
+#define CPUID_SSE4_2 (1 << 20)
+#define CPUID_POPCNT (1 << 23)
+#define CPUID_XSAVE (1 << 27)
+#define CPUID_AVX (1 << 28)
+
+// EDX
+#define CPUID_FXSAVE (1 << 24)
+#define CPUID_SSE (1 << 25)
+#define CPUID_SSE2 (1 << 26)
+#define CPUID_HTT (1 << 28)
+
+// Structured Extended Feature Flags Enumeration Leaf ECX values
#define CPUID_AVX512VBMI (1 << 1)
// Structured Extended Feature Flags Enumeration Leaf EBX values
-#define CPUID_BMI (1 << 3)
-#define CPUID_AVX2 (1 << 5)
-#define CPUID_BMI2 (1 << 8)
-#define CPUID_AVX512F (1 << 16)
-#define CPUID_AVX512BW (1 << 30)
-
-// Extended Control Register 0 (XCR0) values
-#define CPUID_XCR0_SSE (1 << 1)
-#define CPUID_XCR0_AVX (1 << 2)
-#define CPUID_XCR0_OPMASK (1 << 5) // k-regs
-#define CPUID_XCR0_ZMM_Hi256 (1 << 6) // upper 256 bits of ZMM0-ZMM15
-#define CPUID_XCR0_Hi16_ZMM (1 << 7) // ZMM16-ZMM31
-
-#define CPUID_XCR0_AVX512 \
- (CPUID_XCR0_OPMASK | CPUID_XCR0_ZMM_Hi256 | CPUID_XCR0_Hi16_ZMM)
-
-static inline
-u64a xgetbv(u32 op) {
-#if defined(_WIN32) || defined(__INTEL_COMPILER)
- return _xgetbv(op);
-#else
- u32 a, d;
- __asm__ volatile (
- "xgetbv\n"
- : "=a"(a),
- "=d"(d)
- : "c"(op));
- return ((u64a)d << 32) + a;
-#endif
-}
-
-static inline
-int check_avx2(void) {
-#if defined(__INTEL_COMPILER)
- return _may_i_use_cpu_feature(_FEATURE_AVX2);
-#else
- unsigned int eax, ebx, ecx, edx;
-
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
-
- /* check AVX is supported and XGETBV is enabled by OS */
- if ((ecx & (CPUID_AVX | CPUID_XSAVE)) != (CPUID_AVX | CPUID_XSAVE)) {
- DEBUG_PRINTF("AVX and XSAVE not supported\n");
- return 0;
- }
-
- /* check that SSE and AVX registers are enabled by OS */
- u64a xcr0 = xgetbv(0);
- if ((xcr0 & (CPUID_XCR0_SSE | CPUID_XCR0_AVX)) !=
- (CPUID_XCR0_SSE | CPUID_XCR0_AVX)) {
- DEBUG_PRINTF("SSE and AVX registers not enabled\n");
- return 0;
- }
-
- /* ECX and EDX contain capability flags */
- ecx = 0;
- cpuid(7, 0, &eax, &ebx, &ecx, &edx);
-
- if (ebx & CPUID_AVX2) {
- DEBUG_PRINTF("AVX2 enabled\n");
- return 1;
- }
-
- return 0;
-#endif
-}
-
-static inline
-int check_avx512(void) {
- /*
- * For our purposes, having avx512 really means "can we use AVX512BW?"
- */
-#if defined(__INTEL_COMPILER)
- return _may_i_use_cpu_feature(_FEATURE_AVX512BW | _FEATURE_AVX512VL);
-#else
- unsigned int eax, ebx, ecx, edx;
-
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
-
- /* check XSAVE is enabled by OS */
- if (!(ecx & CPUID_XSAVE)) {
- DEBUG_PRINTF("AVX and XSAVE not supported\n");
- return 0;
- }
-
- /* check that AVX 512 registers are enabled by OS */
- u64a xcr0 = xgetbv(0);
- if ((xcr0 & CPUID_XCR0_AVX512) != CPUID_XCR0_AVX512) {
- DEBUG_PRINTF("AVX512 registers not enabled\n");
- return 0;
- }
-
- /* ECX and EDX contain capability flags */
- ecx = 0;
- cpuid(7, 0, &eax, &ebx, &ecx, &edx);
-
- if (!(ebx & CPUID_AVX512F)) {
- DEBUG_PRINTF("AVX512F (AVX512 Foundation) instructions not enabled\n");
- return 0;
- }
-
- if (ebx & CPUID_AVX512BW) {
- DEBUG_PRINTF("AVX512BW instructions enabled\n");
- return 1;
- }
-
- return 0;
-#endif
-}
-
-static inline
+#define CPUID_BMI (1 << 3)
+#define CPUID_AVX2 (1 << 5)
+#define CPUID_BMI2 (1 << 8)
+#define CPUID_AVX512F (1 << 16)
+#define CPUID_AVX512BW (1 << 30)
+
+// Extended Control Register 0 (XCR0) values
+#define CPUID_XCR0_SSE (1 << 1)
+#define CPUID_XCR0_AVX (1 << 2)
+#define CPUID_XCR0_OPMASK (1 << 5) // k-regs
+#define CPUID_XCR0_ZMM_Hi256 (1 << 6) // upper 256 bits of ZMM0-ZMM15
+#define CPUID_XCR0_Hi16_ZMM (1 << 7) // ZMM16-ZMM31
+
+#define CPUID_XCR0_AVX512 \
+ (CPUID_XCR0_OPMASK | CPUID_XCR0_ZMM_Hi256 | CPUID_XCR0_Hi16_ZMM)
+
+static inline
+u64a xgetbv(u32 op) {
+#if defined(_WIN32) || defined(__INTEL_COMPILER)
+ return _xgetbv(op);
+#else
+ u32 a, d;
+ __asm__ volatile (
+ "xgetbv\n"
+ : "=a"(a),
+ "=d"(d)
+ : "c"(op));
+ return ((u64a)d << 32) + a;
+#endif
+}
+
+static inline
+int check_avx2(void) {
+#if defined(__INTEL_COMPILER)
+ return _may_i_use_cpu_feature(_FEATURE_AVX2);
+#else
+ unsigned int eax, ebx, ecx, edx;
+
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+
+ /* check AVX is supported and XGETBV is enabled by OS */
+ if ((ecx & (CPUID_AVX | CPUID_XSAVE)) != (CPUID_AVX | CPUID_XSAVE)) {
+ DEBUG_PRINTF("AVX and XSAVE not supported\n");
+ return 0;
+ }
+
+ /* check that SSE and AVX registers are enabled by OS */
+ u64a xcr0 = xgetbv(0);
+ if ((xcr0 & (CPUID_XCR0_SSE | CPUID_XCR0_AVX)) !=
+ (CPUID_XCR0_SSE | CPUID_XCR0_AVX)) {
+ DEBUG_PRINTF("SSE and AVX registers not enabled\n");
+ return 0;
+ }
+
+ /* ECX and EDX contain capability flags */
+ ecx = 0;
+ cpuid(7, 0, &eax, &ebx, &ecx, &edx);
+
+ if (ebx & CPUID_AVX2) {
+ DEBUG_PRINTF("AVX2 enabled\n");
+ return 1;
+ }
+
+ return 0;
+#endif
+}
+
+static inline
+int check_avx512(void) {
+ /*
+ * For our purposes, having avx512 really means "can we use AVX512BW?"
+ */
+#if defined(__INTEL_COMPILER)
+ return _may_i_use_cpu_feature(_FEATURE_AVX512BW | _FEATURE_AVX512VL);
+#else
+ unsigned int eax, ebx, ecx, edx;
+
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+
+ /* check XSAVE is enabled by OS */
+ if (!(ecx & CPUID_XSAVE)) {
+ DEBUG_PRINTF("AVX and XSAVE not supported\n");
+ return 0;
+ }
+
+ /* check that AVX 512 registers are enabled by OS */
+ u64a xcr0 = xgetbv(0);
+ if ((xcr0 & CPUID_XCR0_AVX512) != CPUID_XCR0_AVX512) {
+ DEBUG_PRINTF("AVX512 registers not enabled\n");
+ return 0;
+ }
+
+ /* ECX and EDX contain capability flags */
+ ecx = 0;
+ cpuid(7, 0, &eax, &ebx, &ecx, &edx);
+
+ if (!(ebx & CPUID_AVX512F)) {
+ DEBUG_PRINTF("AVX512F (AVX512 Foundation) instructions not enabled\n");
+ return 0;
+ }
+
+ if (ebx & CPUID_AVX512BW) {
+ DEBUG_PRINTF("AVX512BW instructions enabled\n");
+ return 1;
+ }
+
+ return 0;
+#endif
+}
+
+static inline
int check_avx512vbmi(void) {
#if defined(__INTEL_COMPILER)
return _may_i_use_cpu_feature(_FEATURE_AVX512VBMI);
@@ -233,28 +233,28 @@ int check_avx512vbmi(void) {
}
static inline
-int check_ssse3(void) {
- unsigned int eax, ebx, ecx, edx;
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
- return !!(ecx & CPUID_SSSE3);
-}
-
-static inline
-int check_sse42(void) {
- unsigned int eax, ebx, ecx, edx;
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
- return !!(ecx & CPUID_SSE4_2);
-}
-
-static inline
-int check_popcnt(void) {
- unsigned int eax, ebx, ecx, edx;
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
- return !!(ecx & CPUID_POPCNT);
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* CPUID_INLINE_H_ */
+int check_ssse3(void) {
+ unsigned int eax, ebx, ecx, edx;
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+ return !!(ecx & CPUID_SSSE3);
+}
+
+static inline
+int check_sse42(void) {
+ unsigned int eax, ebx, ecx, edx;
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+ return !!(ecx & CPUID_SSE4_2);
+}
+
+static inline
+int check_popcnt(void) {
+ unsigned int eax, ebx, ecx, edx;
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+ return !!(ecx & CPUID_POPCNT);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CPUID_INLINE_H_ */
diff --git a/contrib/libs/hyperscan/src/util/depth.h b/contrib/libs/hyperscan/src/util/depth.h
index 652fe36fdab..5305c6f1b33 100644
--- a/contrib/libs/hyperscan/src/util/depth.h
+++ b/contrib/libs/hyperscan/src/util/depth.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,8 +34,8 @@
#define DEPTH_H
#include "ue2common.h"
-#include "util/hash.h"
-#include "util/operators.h"
+#include "util/hash.h"
+#include "util/operators.h"
#ifdef DUMP_SUPPORT
#include <string>
@@ -52,12 +52,12 @@ struct DepthOverflowError {};
* \brief Type used to represent depth information; value is either a count,
* or the special values "infinity" and "unreachable".
*/
-class depth : totally_ordered<depth> {
+class depth : totally_ordered<depth> {
public:
- /** \brief The default depth is special value "unreachable". */
- depth() = default;
+ /** \brief The default depth is special value "unreachable". */
+ depth() = default;
- explicit depth(u32 v) : val(v) {
+ explicit depth(u32 v) : val(v) {
if (v > max_value()) {
DEBUG_PRINTF("depth %u too large to represent!\n", v);
throw DepthOverflowError();
@@ -193,53 +193,53 @@ public:
return *this;
}
- depth operator-(s32 d) const {
- if (is_unreachable()) {
- return unreachable();
- }
- if (is_infinite()) {
- return infinity();
- }
-
- s64a rv = val - d;
- if (rv < 0 || (u64a)rv >= val_infinity) {
- DEBUG_PRINTF("depth %lld too large to represent!\n", rv);
- throw DepthOverflowError();
- }
-
- return depth((u32)rv);
- }
-
- depth operator-=(s32 d) {
- depth rv = *this - d;
- *this = rv;
- return *this;
- }
-
+ depth operator-(s32 d) const {
+ if (is_unreachable()) {
+ return unreachable();
+ }
+ if (is_infinite()) {
+ return infinity();
+ }
+
+ s64a rv = val - d;
+ if (rv < 0 || (u64a)rv >= val_infinity) {
+ DEBUG_PRINTF("depth %lld too large to represent!\n", rv);
+ throw DepthOverflowError();
+ }
+
+ return depth((u32)rv);
+ }
+
+ depth operator-=(s32 d) {
+ depth rv = *this - d;
+ *this = rv;
+ return *this;
+ }
+
#ifdef DUMP_SUPPORT
/** \brief Render as a string, useful for debugging. */
std::string str() const;
#endif
- size_t hash() const {
- return val;
+ size_t hash() const {
+ return val;
}
private:
static constexpr u32 val_infinity = (1u << 31) - 1;
static constexpr u32 val_unreachable = 1u << 31;
- u32 val = val_unreachable;
+ u32 val = val_unreachable;
};
/**
* \brief Encapsulates a min/max pair.
*/
-struct DepthMinMax : totally_ordered<DepthMinMax> {
- depth min{depth::infinity()};
- depth max{0};
+struct DepthMinMax : totally_ordered<DepthMinMax> {
+ depth min{depth::infinity()};
+ depth max{0};
- DepthMinMax() = default;
+ DepthMinMax() = default;
DepthMinMax(const depth &mn, const depth &mx) : min(mn), max(mx) {}
bool operator<(const DepthMinMax &b) const {
@@ -257,7 +257,7 @@ struct DepthMinMax : totally_ordered<DepthMinMax> {
/** \brief Render as a string, useful for debugging. */
std::string str() const;
#endif
-
+
};
/**
@@ -267,22 +267,22 @@ DepthMinMax unionDepthMinMax(const DepthMinMax &a, const DepthMinMax &b);
} // namespace ue2
-namespace std {
-
-template<>
-struct hash<ue2::depth> {
- size_t operator()(const ue2::depth &d) const {
- return d.hash();
- }
-};
-
-template<>
-struct hash<ue2::DepthMinMax> {
- size_t operator()(const ue2::DepthMinMax &d) const {
- return hash_all(d.min, d.max);
- }
-};
-
-} // namespace
-
+namespace std {
+
+template<>
+struct hash<ue2::depth> {
+ size_t operator()(const ue2::depth &d) const {
+ return d.hash();
+ }
+};
+
+template<>
+struct hash<ue2::DepthMinMax> {
+ size_t operator()(const ue2::DepthMinMax &d) const {
+ return hash_all(d.min, d.max);
+ }
+};
+
+} // namespace
+
#endif // DEPTH_H
diff --git a/contrib/libs/hyperscan/src/util/determinise.h b/contrib/libs/hyperscan/src/util/determinise.h
index 8cb2d119306..102a197441e 100644
--- a/contrib/libs/hyperscan/src/util/determinise.h
+++ b/contrib/libs/hyperscan/src/util/determinise.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,9 +38,9 @@
#include "container.h"
#include "ue2common.h"
-#include <algorithm>
+#include <algorithm>
#include <array>
-#include <queue>
+#include <queue>
#include <vector>
namespace ue2 {
@@ -72,44 +72,44 @@ namespace ue2 {
* \param state_limit limit on the number of dfa states to construct
* \param statesets_out a mapping from DFA state to the set of NFA states in
* the automaton
- * \return true on success, false if state limit exceeded
+ * \return true on success, false if state limit exceeded
*/
template<class Auto, class ds>
never_inline
-bool determinise(Auto &n, std::vector<ds> &dstates, size_t state_limit,
+bool determinise(Auto &n, std::vector<ds> &dstates, size_t state_limit,
std::vector<typename Auto::StateSet> *statesets_out = nullptr) {
DEBUG_PRINTF("the determinator\n");
- using StateSet = typename Auto::StateSet;
- typename Auto::StateMap dstate_ids;
+ using StateSet = typename Auto::StateSet;
+ typename Auto::StateMap dstate_ids;
const size_t alphabet_size = n.alphasize;
- dstates.clear();
- dstates.reserve(state_limit);
+ dstates.clear();
+ dstates.reserve(state_limit);
- dstate_ids.emplace(n.dead, DEAD_STATE);
+ dstate_ids.emplace(n.dead, DEAD_STATE);
dstates.push_back(ds(alphabet_size));
std::fill_n(dstates[0].next.begin(), alphabet_size, DEAD_STATE);
- std::queue<std::pair<StateSet, dstate_id_t>> q;
- q.emplace(n.dead, DEAD_STATE);
+ std::queue<std::pair<StateSet, dstate_id_t>> q;
+ q.emplace(n.dead, DEAD_STATE);
const std::vector<StateSet> &init = n.initial();
for (u32 i = 0; i < init.size(); i++) {
- q.emplace(init[i], dstates.size());
+ q.emplace(init[i], dstates.size());
assert(!contains(dstate_ids, init[i]));
- dstate_ids.emplace(init[i], dstates.size());
+ dstate_ids.emplace(init[i], dstates.size());
dstates.push_back(ds(alphabet_size));
}
std::vector<StateSet> succs(alphabet_size, n.dead);
- while (!q.empty()) {
- auto m = std::move(q.front());
- q.pop();
- StateSet &curr = m.first;
- dstate_id_t curr_id = m.second;
-
+ while (!q.empty()) {
+ auto m = std::move(q.front());
+ q.pop();
+ StateSet &curr = m.first;
+ dstate_id_t curr_id = m.second;
+
DEBUG_PRINTF("curr: %hu\n", curr_id);
/* fill in accepts */
@@ -139,48 +139,48 @@ bool determinise(Auto &n, std::vector<ds> &dstates, size_t state_limit,
if (s && succs[s] == succs[s - 1]) {
succ_id = dstates[curr_id].next[s - 1];
} else {
- auto p = dstate_ids.find(succs[s]);
- if (p != dstate_ids.end()) { // succ[s] is already present
- succ_id = p->second;
+ auto p = dstate_ids.find(succs[s]);
+ if (p != dstate_ids.end()) { // succ[s] is already present
+ succ_id = p->second;
if (succ_id > curr_id && !dstates[succ_id].daddy
&& n.unalpha[s] < N_CHARS) {
dstates[succ_id].daddy = curr_id;
}
} else {
- succ_id = dstate_ids.size();
- dstate_ids.emplace(succs[s], succ_id);
+ succ_id = dstate_ids.size();
+ dstate_ids.emplace(succs[s], succ_id);
dstates.push_back(ds(alphabet_size));
dstates.back().daddy = n.unalpha[s] < N_CHARS ? curr_id : 0;
- q.emplace(succs[s], succ_id);
+ q.emplace(succs[s], succ_id);
}
DEBUG_PRINTF("-->%hu on %02hx\n", succ_id, n.unalpha[s]);
}
if (succ_id >= state_limit) {
- DEBUG_PRINTF("succ_id %hu >= state_limit %zu\n",
+ DEBUG_PRINTF("succ_id %hu >= state_limit %zu\n",
succ_id, state_limit);
- dstates.clear();
- return false;
+ dstates.clear();
+ return false;
}
dstates[curr_id].next[s] = succ_id;
}
}
- // The dstates vector will persist in the raw_dfa.
- dstates.shrink_to_fit();
-
+ // The dstates vector will persist in the raw_dfa.
+ dstates.shrink_to_fit();
+
if (statesets_out) {
- auto &statesets = *statesets_out;
- statesets.resize(dstate_ids.size());
- for (auto &m : dstate_ids) {
- statesets[m.second] = std::move(m.first);
- }
+ auto &statesets = *statesets_out;
+ statesets.resize(dstate_ids.size());
+ for (auto &m : dstate_ids) {
+ statesets[m.second] = std::move(m.first);
+ }
}
-
+
DEBUG_PRINTF("ok\n");
- return true;
+ return true;
}
static inline
diff --git a/contrib/libs/hyperscan/src/util/dump_charclass.h b/contrib/libs/hyperscan/src/util/dump_charclass.h
index b10d1b162b1..999641340a7 100644
--- a/contrib/libs/hyperscan/src/util/dump_charclass.h
+++ b/contrib/libs/hyperscan/src/util/dump_charclass.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,9 +37,9 @@
#include <cstdio>
#include <ostream>
-#include <sstream>
+#include <sstream>
#include <string>
-#include <vector>
+#include <vector>
namespace ue2 {
@@ -50,23 +50,23 @@ enum cc_output_t {
class CharReach;
-void describeClass(std::ostream &os, const CharReach &cr, size_t maxLength = 16,
- enum cc_output_t out_type = CC_OUT_TEXT);
+void describeClass(std::ostream &os, const CharReach &cr, size_t maxLength = 16,
+ enum cc_output_t out_type = CC_OUT_TEXT);
std::string describeClass(const CharReach &cr, size_t maxLength = 16,
enum cc_output_t out_type = CC_OUT_TEXT);
-template<typename Container>
-std::string describeClasses(const Container &container,
- size_t maxClassLength = 16,
- enum cc_output_t out_type = CC_OUT_TEXT) {
- std::ostringstream oss;
- for (const CharReach &cr : container) {
- describeClass(oss, cr, maxClassLength, out_type);
- }
- return oss.str();
-}
-
+template<typename Container>
+std::string describeClasses(const Container &container,
+ size_t maxClassLength = 16,
+ enum cc_output_t out_type = CC_OUT_TEXT) {
+ std::ostringstream oss;
+ for (const CharReach &cr : container) {
+ describeClass(oss, cr, maxClassLength, out_type);
+ }
+ return oss.str();
+}
+
void describeClass(FILE *f, const CharReach &cr, size_t maxLength,
enum cc_output_t out_type);
diff --git a/contrib/libs/hyperscan/src/util/exhaust.h b/contrib/libs/hyperscan/src/util/exhaust.h
index 0d8f96f6ab2..d6f2ac06d94 100644
--- a/contrib/libs/hyperscan/src/util/exhaust.h
+++ b/contrib/libs/hyperscan/src/util/exhaust.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@
#include "ue2common.h"
-/** Index meaning a given exhaustion key is invalid. */
-#define INVALID_EKEY (~(u32)0)
+/** Index meaning a given exhaustion key is invalid. */
+#define INVALID_EKEY (~(u32)0)
#endif
diff --git a/contrib/libs/hyperscan/src/util/fatbit.h b/contrib/libs/hyperscan/src/util/fatbit.h
index fa6f5c3793a..3c65db1a59f 100644
--- a/contrib/libs/hyperscan/src/util/fatbit.h
+++ b/contrib/libs/hyperscan/src/util/fatbit.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,10 +40,10 @@
#include "multibit.h"
#include "ue2common.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MIN_FAT_SIZE 32
struct fatbit {
@@ -62,32 +62,32 @@ void fatbit_clear(struct fatbit *bits) {
static really_inline
char fatbit_set(struct fatbit *bits, u32 total_bits, u32 key) {
- assert(ISALIGNED(bits));
+ assert(ISALIGNED(bits));
return mmbit_set(bits->fb_int.raw, total_bits, key);
}
static really_inline
void fatbit_unset(struct fatbit *bits, u32 total_bits, u32 key) {
- assert(ISALIGNED(bits));
+ assert(ISALIGNED(bits));
mmbit_unset(bits->fb_int.raw, total_bits, key);
}
static really_inline
char fatbit_isset(const struct fatbit *bits, u32 total_bits, u32 key) {
- assert(ISALIGNED(bits));
+ assert(ISALIGNED(bits));
return mmbit_isset(bits->fb_int.raw, total_bits, key);
}
static really_inline
u32 fatbit_iterate(const struct fatbit *bits, u32 total_bits, u32 it_in) {
- assert(ISALIGNED(bits));
+ assert(ISALIGNED(bits));
/* TODO: iterate_flat could be specialised as we don't have to worry about
* partial blocks. */
return mmbit_iterate(bits->fb_int.raw, total_bits, it_in);
}
-#ifdef __cplusplus
-} // extern "C"
-#endif
+#ifdef __cplusplus
+} // extern "C"
+#endif
#endif
diff --git a/contrib/libs/hyperscan/src/util/fatbit_build.cpp b/contrib/libs/hyperscan/src/util/fatbit_build.cpp
index 5a251b1cc0b..77f4b550229 100644
--- a/contrib/libs/hyperscan/src/util/fatbit_build.cpp
+++ b/contrib/libs/hyperscan/src/util/fatbit_build.cpp
@@ -1,44 +1,44 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#include "fatbit_build.h"
-
-#include "fatbit.h"
-#include "multibit_build.h"
-
-#include <algorithm>
-
-using namespace std;
-
-namespace ue2 {
-
-u32 fatbit_size(u32 total_bits) {
- return max(u32{sizeof(struct fatbit)}, mmbit_size(total_bits));
-}
-
-} // namespace ue2
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#include "fatbit_build.h"
+
+#include "fatbit.h"
+#include "multibit_build.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace ue2 {
+
+u32 fatbit_size(u32 total_bits) {
+ return max(u32{sizeof(struct fatbit)}, mmbit_size(total_bits));
+}
+
+} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/util/fatbit_build.h b/contrib/libs/hyperscan/src/util/fatbit_build.h
index 0fed10c06af..d76116570c2 100644
--- a/contrib/libs/hyperscan/src/util/fatbit_build.h
+++ b/contrib/libs/hyperscan/src/util/fatbit_build.h
@@ -1,48 +1,48 @@
-/*
- * Copyright (c) 2016, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Fatbit: build code
- */
-
-#ifndef FATBIT_BUILD_H
-#define FATBIT_BUILD_H
-
-#include "ue2common.h"
-
-namespace ue2 {
-
-/**
- * \brief Return the size in bytes of a fatbit that can store the given
- * number of bits.
- */
-u32 fatbit_size(u32 total_bits);
-
-} // namespace ue2
-
-#endif // FATBIT_BUILD_H
+/*
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Fatbit: build code
+ */
+
+#ifndef FATBIT_BUILD_H
+#define FATBIT_BUILD_H
+
+#include "ue2common.h"
+
+namespace ue2 {
+
+/**
+ * \brief Return the size in bytes of a fatbit that can store the given
+ * number of bits.
+ */
+u32 fatbit_size(u32 total_bits);
+
+} // namespace ue2
+
+#endif // FATBIT_BUILD_H
diff --git a/contrib/libs/hyperscan/src/util/flat_containers.h b/contrib/libs/hyperscan/src/util/flat_containers.h
index 822c1f89571..41452eb42ac 100644
--- a/contrib/libs/hyperscan/src/util/flat_containers.h
+++ b/contrib/libs/hyperscan/src/util/flat_containers.h
@@ -1,664 +1,664 @@
-/*
- * Copyright (c) 2015-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UTIL_FLAT_CONTAINERS_H
-#define UTIL_FLAT_CONTAINERS_H
-
-#include "ue2common.h"
-#include "util/hash.h"
-#include "util/operators.h"
-#include "util/small_vector.h"
-
-#include <algorithm>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-
-#include <boost/iterator/iterator_facade.hpp>
-
-namespace ue2 {
-
-namespace flat_detail {
-
-// Iterator facade that wraps an underlying iterator, so that we get our
-// own iterator types.
-template <class WrappedIter, class Value>
-class iter_wrapper
- : public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
- boost::random_access_traversal_tag> {
-public:
- iter_wrapper() = default;
- explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
-
- // Templated copy-constructor to allow for interoperable iterator and
- // const_iterator.
-private:
- template <class, class> friend class iter_wrapper;
-
-public:
- template <class OtherIter, class OtherValue>
- iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
- typename std::enable_if<std::is_convertible<
- OtherIter, WrappedIter>::value>::type * = nullptr)
- : it(std::move(other.it)) {}
-
- WrappedIter get() const { return it; }
-
-private:
- friend class boost::iterator_core_access;
-
- WrappedIter it;
-
- void increment() { ++it; }
- void decrement() { --it; }
- void advance(size_t n) { it += n; }
- typename std::iterator_traits<WrappedIter>::difference_type
- distance_to(const iter_wrapper &other) const {
- return other.it - it;
- }
- bool equal(const iter_wrapper &other) const { return it == other.it; }
- Value &dereference() const { return *it; }
-};
-
-template <class T, class Compare, class Allocator>
-class flat_base {
-protected:
- // Underlying storage is a small vector with local space for one element.
- using storage_type = small_vector<T, 1, Allocator>;
- using storage_alloc_type = typename storage_type::allocator_type;
-
- // Putting our storage and comparator in a tuple allows us to make use of
- // the empty base class optimization (if this STL implements it for
- // std::tuple).
- std::tuple<storage_type, Compare> storage;
-
- flat_base(const Compare &compare, const Allocator &alloc)
- : storage(storage_type(storage_alloc_type(alloc)), compare) {}
-
- storage_type &data() { return std::get<0>(this->storage); }
- const storage_type &data() const { return std::get<0>(this->storage); }
-
- Compare &comp() { return std::get<1>(this->storage); }
- const Compare &comp() const { return std::get<1>(this->storage); }
-
-public:
- // Common member types.
- using key_compare = Compare;
-
- Allocator get_allocator() const {
- return data().get_allocator();
- }
-
- key_compare key_comp() const {
- return comp();
- }
-
- // Capacity.
-
- bool empty() const { return data().empty(); }
- size_t size() const { return data().size(); }
- size_t max_size() const { return data().max_size(); }
-
- // Modifiers.
-
- void clear() {
- data().clear();
- }
-
- void swap(flat_base &a) {
- using std::swap;
- swap(comp(), a.comp());
- swap(data(), a.data());
- }
-};
-
-} // namespace flat_detail
-
-/**
- * \brief Set container implemented internally as a sorted vector. Use this
- * rather than std::set for small sets as it's faster, uses less memory and
- * incurs less malloc time.
- *
- * Note: we used to use boost::flat_set, but have run into problems with all
- * the extra machinery it instantiates.
- */
-template <class T, class Compare = std::less<T>,
- class Allocator = std::allocator<T>>
-class flat_set
- : public flat_detail::flat_base<T, Compare, Allocator>,
- public totally_ordered<flat_set<T, Compare, Allocator>> {
- using base_type = flat_detail::flat_base<T, Compare, Allocator>;
- using storage_type = typename base_type::storage_type;
- using storage_iterator = typename storage_type::iterator;
- using storage_const_iterator = typename storage_type::const_iterator;
- using base_type::data;
- using base_type::comp;
-
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // Construct a non-const iterator from a const iterator. Used in flat_map
- // and flat_set erase() calls to work around g++-4.8 compatibility issues.
- storage_iterator mutable_iterator(storage_const_iterator it) {
- return data().begin() + std::distance(data().cbegin(), it);
- }
-#endif
-
-public:
- // Member types.
- using key_type = T;
- using value_type = T;
- using size_type = typename storage_type::size_type;
- using difference_type = typename storage_type::difference_type;
- using key_compare = typename base_type::key_compare;
- using value_compare = Compare;
- using allocator_type = Allocator;
- using reference = value_type &;
- using const_reference = const value_type &;
- using allocator_traits_type = typename std::allocator_traits<Allocator>;
- using pointer = typename allocator_traits_type::pointer;
- using const_pointer = typename allocator_traits_type::const_pointer;
-
- // Iterator types.
-
- using iterator = flat_detail::iter_wrapper<typename storage_type::iterator,
- const value_type>;
- using const_iterator =
- flat_detail::iter_wrapper<typename storage_type::const_iterator,
- const value_type>;
-
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- // Constructors.
-
- flat_set(const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : base_type(compare, alloc) {}
-
- template <class InputIt>
- flat_set(InputIt first, InputIt last, const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : flat_set(compare, alloc) {
- insert(first, last);
- }
-
- flat_set(std::initializer_list<value_type> init,
- const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : flat_set(compare, alloc) {
- insert(init.begin(), init.end());
- }
-
- flat_set(const flat_set &) = default;
- flat_set(flat_set &&) = default;
- flat_set &operator=(const flat_set &) = default;
- flat_set &operator=(flat_set &&) = default;
-
- // Iterators.
-
- iterator begin() { return iterator(data().begin()); }
- const_iterator cbegin() const { return const_iterator(data().cbegin()); }
- const_iterator begin() const { return cbegin(); }
-
- iterator end() { return iterator(data().end()); }
- const_iterator cend() const { return const_iterator(data().cend()); }
- const_iterator end() const { return cend(); }
-
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- const_reverse_iterator crbegin() const {
- return const_reverse_iterator(cend());
- }
- const_reverse_iterator rbegin() const { return crbegin(); }
-
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator crend() const {
- return const_reverse_iterator(cbegin());
- }
- const_reverse_iterator rend() const { return crend(); }
-
- // Modifiers.
-
- std::pair<iterator, bool> insert(const value_type &value) {
- auto it = std::lower_bound(data().begin(), data().end(), value, comp());
- if (it == data().end() || comp()(value, *it)) {
- return std::make_pair(iterator(data().insert(it, value)), true);
- }
- return std::make_pair(iterator(it), false);
- }
-
- iterator insert(UNUSED const_iterator hint, const value_type &value) {
- return insert(value).first;
- }
-
- std::pair<iterator, bool> insert(value_type &&value) {
- auto it = std::lower_bound(data().begin(), data().end(), value, comp());
- if (it == data().end() || comp()(value, *it)) {
- return std::make_pair(iterator(data().insert(it, std::move(value))),
- true);
- }
- return std::make_pair(iterator(it), false);
- }
-
- iterator insert(UNUSED const_iterator hint, value_type &&value) {
- return insert(value).first;
- }
-
- template <class InputIt>
- void insert(InputIt first, InputIt second) {
- for (; first != second; ++first) {
- insert(*first);
- }
- }
-
- void insert(std::initializer_list<value_type> ilist) {
- insert(ilist.begin(), ilist.end());
- }
-
- template<class...Args>
- std::pair<iterator, bool> emplace(Args&&... args) {
- return insert(value_type(std::forward<Args>(args)...));
- }
-
- void erase(const_iterator pos) {
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // Cope with libstdc++ 4.8's incomplete STL (it's missing C++11
- // vector::erase(const_iterator)) by explicitly using a non-const
- // iterator.
- auto pos_it = mutable_iterator(pos.get());
-#else
- auto pos_it = pos.get();
-#endif
- data().erase(pos_it);
- }
-
- void erase(const_iterator first, const_iterator last) {
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // As above, work around libstdc++ 4.8's incomplete C++11 support.
- auto first_it = mutable_iterator(first.get());
- auto last_it = mutable_iterator(last.get());
-#else
- auto first_it = first.get();
- auto last_it = last.get();
-#endif
- data().erase(first_it, last_it);
- }
-
- void erase(const key_type &key) {
- auto it = find(key);
- if (it != end()) {
- erase(it);
- }
- }
-
- // Lookup.
-
- size_type count(const value_type &value) const {
- return find(value) != end() ? 1 : 0;
- }
-
- iterator find(const value_type &value) {
- auto it = std::lower_bound(data().begin(), data().end(), value, comp());
- if (it != data().end() && comp()(value, *it)) {
- it = data().end();
- }
- return iterator(it);
- }
-
- const_iterator find(const value_type &value) const {
- auto it = std::lower_bound(data().begin(), data().end(), value, comp());
- if (it != data().end() && comp()(value, *it)) {
- it = data().end();
- }
- return const_iterator(it);
- }
-
- // Observers.
-
- value_compare value_comp() const {
- return comp();
- }
-
- // Operators. All others provided by ue2::totally_ordered.
-
- bool operator==(const flat_set &a) const {
- return data() == a.data();
- }
- bool operator<(const flat_set &a) const {
- return data() < a.data();
- }
-
- // Free swap function for ADL.
- friend void swap(flat_set &a, flat_set &b) {
- a.swap(b);
- }
-};
-
-/**
- * \brief Map container implemented internally as a sorted vector. Use this
- * rather than std::map for small maps as it's faster, uses less memory and
- * incurs less malloc time.
- *
- * Note: we used to use boost::flat_map, but have run into problems with all
- * the extra machinery it instantiates.
- *
- * Note: ue2::flat_map does NOT provide mutable iterators, as (given the way
- * the data is stored) it is difficult to provide a real mutable iterator that
- * wraps std::pair<const Key, T>. Instead, all iterators are const, and you
- * should use flat_map::at() or flat_map::operator[] to mutate the contents of
- * the container.
- */
-template <class Key, class T, class Compare = std::less<Key>,
- class Allocator = std::allocator<std::pair<Key, T>>>
-class flat_map
- : public flat_detail::flat_base<std::pair<Key, T>, Compare, Allocator>,
- public totally_ordered<flat_map<Key, T, Compare, Allocator>> {
-public:
- // Member types.
- using key_type = Key;
- using mapped_type = T;
- using value_type = std::pair<const Key, T>;
-
-private:
- using base_type =
- flat_detail::flat_base<std::pair<Key, T>, Compare, Allocator>;
- using keyval_storage_type = std::pair<key_type, mapped_type>;
- using storage_type = typename base_type::storage_type;
- using storage_iterator = typename storage_type::iterator;
- using storage_const_iterator = typename storage_type::const_iterator;
- using base_type::data;
- using base_type::comp;
-
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // Construct a non-const iterator from a const iterator. Used in flat_map
- // and flat_set erase() calls to work around g++-4.8 compatibility issues.
- storage_iterator mutable_iterator(storage_const_iterator it) {
- return data().begin() + std::distance(data().cbegin(), it);
- }
-#endif
-
-public:
- // More Member types.
- using size_type = typename storage_type::size_type;
- using difference_type = typename storage_type::difference_type;
- using key_compare = typename base_type::key_compare;
- using allocator_type = Allocator;
- using reference = value_type &;
- using const_reference = const value_type &;
- using allocator_traits_type = typename std::allocator_traits<Allocator>;
- using pointer = typename allocator_traits_type::pointer;
- using const_pointer = typename allocator_traits_type::const_pointer;
-
-public:
- using const_iterator =
- flat_detail::iter_wrapper<typename storage_type::const_iterator,
- const keyval_storage_type>;
-
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- // All iterators are const for flat_map.
- using iterator = const_iterator;
- using reverse_iterator = const_reverse_iterator;
-
- // Constructors.
-
- flat_map(const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : base_type(compare, alloc) {}
-
- template <class InputIt>
- flat_map(InputIt first, InputIt last, const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : flat_map(compare, alloc) {
- insert(first, last);
- }
-
- flat_map(std::initializer_list<value_type> init,
- const Compare &compare = Compare(),
- const Allocator &alloc = Allocator())
- : flat_map(compare, alloc) {
- insert(init.begin(), init.end());
- }
-
- flat_map(const flat_map &) = default;
- flat_map(flat_map &&) = default;
- flat_map &operator=(const flat_map &) = default;
- flat_map &operator=(flat_map &&) = default;
-
- // Iterators.
-
- const_iterator cbegin() const { return const_iterator(data().cbegin()); }
- const_iterator begin() const { return cbegin(); }
-
- const_iterator cend() const { return const_iterator(data().cend()); }
- const_iterator end() const { return cend(); }
-
- const_reverse_iterator crbegin() const {
- return const_reverse_iterator(cend());
- }
- const_reverse_iterator rbegin() const { return crbegin(); }
-
- const_reverse_iterator crend() const {
- return const_reverse_iterator(cbegin());
- }
- const_reverse_iterator rend() const { return crend(); }
-
-private:
- storage_iterator data_lower_bound(const key_type &key) {
- return std::lower_bound(
- data().begin(), data().end(), key,
- [&](const keyval_storage_type &elem, const key_type &k) {
- return comp()(elem.first, k);
- });
- }
-
- storage_const_iterator
- data_lower_bound(const key_type &key) const {
- return std::lower_bound(
- data().begin(), data().end(), key,
- [&](const keyval_storage_type &elem, const key_type &k) {
- return comp()(elem.first, k);
- });
- }
-
- std::pair<storage_iterator, bool> data_insert(const value_type &value) {
- auto it = data_lower_bound(value.first);
- if (it == data().end() || comp()(value.first, it->first)) {
- return std::make_pair(data().insert(it, value), true);
- }
- return std::make_pair(it, false);
- }
-
- std::pair<storage_iterator, bool> data_insert(value_type &&value) {
- auto it = data_lower_bound(value.first);
- if (it == data().end() || comp()(value.first, it->first)) {
- return std::make_pair(data().insert(it, std::move(value)), true);
- }
- return std::make_pair(it, false);
- }
-
- storage_iterator data_find(const key_type &key) {
- auto it = data_lower_bound(key);
- if (it != data().end() && comp()(key, it->first)) {
- it = data().end();
- }
- return it;
- }
-
- storage_const_iterator data_find(const key_type &key) const {
- auto it = data_lower_bound(key);
- if (it != data().end() && comp()(key, it->first)) {
- it = data().end();
- }
- return it;
- }
-
-public:
- // Modifiers.
-
- std::pair<iterator, bool> insert(const value_type &value) {
- auto rv = data_insert(value);
- return std::make_pair(iterator(rv.first), rv.second);
- }
-
- std::pair<iterator, bool> insert(value_type &&value) {
- auto rv = data_insert(std::move(value));
- return std::make_pair(iterator(rv.first), rv.second);
- }
-
- template <class InputIt>
- void insert(InputIt first, InputIt second) {
- for (; first != second; ++first) {
- insert(*first);
- }
- }
-
- void insert(std::initializer_list<value_type> ilist) {
- insert(ilist.begin(), ilist.end());
- }
-
- template<class...Args>
- std::pair<iterator, bool> emplace(Args&&... args) {
- return insert(value_type(std::forward<Args>(args)...));
- }
-
- void erase(const_iterator pos) {
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // Cope with libstdc++ 4.8's incomplete STL (it's missing C++11
- // vector::erase(const_iterator)) by explicitly using a non-const
- // iterator.
- auto pos_it = mutable_iterator(pos.get());
-#else
- auto pos_it = pos.get();
-#endif
- data().erase(pos_it);
- }
-
- void erase(const_iterator first, const_iterator last) {
-#if defined(SMALL_VECTOR_IS_STL_VECTOR)
- // As above, work around libstdc++ 4.8's incomplete C++11 support.
- auto first_it = mutable_iterator(first.get());
- auto last_it = mutable_iterator(last.get());
-#else
- auto first_it = first.get();
- auto last_it = last.get();
-#endif
- data().erase(first_it, last_it);
- }
-
- void erase(const key_type &key) {
- auto it = find(key);
- if (it != end()) {
- erase(it);
- }
- }
-
- // Lookup.
-
- size_type count(const key_type &key) const {
- return find(key) != end() ? 1 : 0;
- }
-
- const_iterator find(const key_type &key) const {
- return const_iterator(data_find(key));
- }
-
- // Element access.
-
- mapped_type &at(const key_type &key) {
- auto it = data_find(key);
- if (it == data().end()) {
- throw std::out_of_range("element not found");
- }
- return it->second;
- }
-
- const mapped_type &at(const key_type &key) const {
- auto it = data_find(key);
- if (it == data().end()) {
- throw std::out_of_range("element not found");
- }
- return it->second;
- }
-
- mapped_type &operator[](const key_type &key) {
- auto p = data_insert(value_type(key, mapped_type()));
- return p.first->second;
- }
-
- // Observers.
-
- class value_compare {
- friend class flat_map;
- protected:
- Compare c;
- value_compare(Compare c_in) : c(c_in) {}
- public:
- bool operator()(const value_type &lhs, const value_type &rhs) {
- return c(lhs.first, rhs.first);
- }
- };
-
- value_compare value_comp() const {
- return value_compare(comp());
- }
-
- // Operators. All others provided by ue2::totally_ordered.
-
- bool operator==(const flat_map &a) const {
- return data() == a.data();
- }
- bool operator<(const flat_map &a) const {
- return data() < a.data();
- }
-
- // Free swap function for ADL.
- friend void swap(flat_map &a, flat_map &b) {
- a.swap(b);
- }
-};
-
-} // namespace ue2
-
-namespace std {
-
-template<typename T, typename Compare, typename Allocator>
-struct hash<ue2::flat_set<T, Compare, Allocator>> {
- size_t operator()(const ue2::flat_set<T, Compare, Allocator> &f) {
- return ue2::ue2_hasher()(f);
- }
-};
-
-template<typename Key, typename T, typename Compare, typename Allocator>
-struct hash<ue2::flat_map<Key, T, Compare, Allocator>> {
- size_t operator()(const ue2::flat_map<Key, T, Compare, Allocator> &f) {
- return ue2::ue2_hasher()(f);
- }
-};
-
-} // namespace std
-
-#endif // UTIL_FLAT_CONTAINERS_H
+/*
+ * Copyright (c) 2015-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UTIL_FLAT_CONTAINERS_H
+#define UTIL_FLAT_CONTAINERS_H
+
+#include "ue2common.h"
+#include "util/hash.h"
+#include "util/operators.h"
+#include "util/small_vector.h"
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include <boost/iterator/iterator_facade.hpp>
+
+namespace ue2 {
+
+namespace flat_detail {
+
+// Iterator facade that wraps an underlying iterator, so that we get our
+// own iterator types.
+template <class WrappedIter, class Value>
+class iter_wrapper
+ : public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
+ boost::random_access_traversal_tag> {
+public:
+ iter_wrapper() = default;
+ explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
+
+ // Templated copy-constructor to allow for interoperable iterator and
+ // const_iterator.
+private:
+ template <class, class> friend class iter_wrapper;
+
+public:
+ template <class OtherIter, class OtherValue>
+ iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
+ typename std::enable_if<std::is_convertible<
+ OtherIter, WrappedIter>::value>::type * = nullptr)
+ : it(std::move(other.it)) {}
+
+ WrappedIter get() const { return it; }
+
+private:
+ friend class boost::iterator_core_access;
+
+ WrappedIter it;
+
+ void increment() { ++it; }
+ void decrement() { --it; }
+ void advance(size_t n) { it += n; }
+ typename std::iterator_traits<WrappedIter>::difference_type
+ distance_to(const iter_wrapper &other) const {
+ return other.it - it;
+ }
+ bool equal(const iter_wrapper &other) const { return it == other.it; }
+ Value &dereference() const { return *it; }
+};
+
+template <class T, class Compare, class Allocator>
+class flat_base {
+protected:
+ // Underlying storage is a small vector with local space for one element.
+ using storage_type = small_vector<T, 1, Allocator>;
+ using storage_alloc_type = typename storage_type::allocator_type;
+
+ // Putting our storage and comparator in a tuple allows us to make use of
+ // the empty base class optimization (if this STL implements it for
+ // std::tuple).
+ std::tuple<storage_type, Compare> storage;
+
+ flat_base(const Compare &compare, const Allocator &alloc)
+ : storage(storage_type(storage_alloc_type(alloc)), compare) {}
+
+ storage_type &data() { return std::get<0>(this->storage); }
+ const storage_type &data() const { return std::get<0>(this->storage); }
+
+ Compare &comp() { return std::get<1>(this->storage); }
+ const Compare &comp() const { return std::get<1>(this->storage); }
+
+public:
+ // Common member types.
+ using key_compare = Compare;
+
+ Allocator get_allocator() const {
+ return data().get_allocator();
+ }
+
+ key_compare key_comp() const {
+ return comp();
+ }
+
+ // Capacity.
+
+ bool empty() const { return data().empty(); }
+ size_t size() const { return data().size(); }
+ size_t max_size() const { return data().max_size(); }
+
+ // Modifiers.
+
+ void clear() {
+ data().clear();
+ }
+
+ void swap(flat_base &a) {
+ using std::swap;
+ swap(comp(), a.comp());
+ swap(data(), a.data());
+ }
+};
+
+} // namespace flat_detail
+
+/**
+ * \brief Set container implemented internally as a sorted vector. Use this
+ * rather than std::set for small sets as it's faster, uses less memory and
+ * incurs less malloc time.
+ *
+ * Note: we used to use boost::flat_set, but have run into problems with all
+ * the extra machinery it instantiates.
+ */
+template <class T, class Compare = std::less<T>,
+ class Allocator = std::allocator<T>>
+class flat_set
+ : public flat_detail::flat_base<T, Compare, Allocator>,
+ public totally_ordered<flat_set<T, Compare, Allocator>> {
+ using base_type = flat_detail::flat_base<T, Compare, Allocator>;
+ using storage_type = typename base_type::storage_type;
+ using storage_iterator = typename storage_type::iterator;
+ using storage_const_iterator = typename storage_type::const_iterator;
+ using base_type::data;
+ using base_type::comp;
+
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // Construct a non-const iterator from a const iterator. Used in flat_map
+ // and flat_set erase() calls to work around g++-4.8 compatibility issues.
+ storage_iterator mutable_iterator(storage_const_iterator it) {
+ return data().begin() + std::distance(data().cbegin(), it);
+ }
+#endif
+
+public:
+ // Member types.
+ using key_type = T;
+ using value_type = T;
+ using size_type = typename storage_type::size_type;
+ using difference_type = typename storage_type::difference_type;
+ using key_compare = typename base_type::key_compare;
+ using value_compare = Compare;
+ using allocator_type = Allocator;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using allocator_traits_type = typename std::allocator_traits<Allocator>;
+ using pointer = typename allocator_traits_type::pointer;
+ using const_pointer = typename allocator_traits_type::const_pointer;
+
+ // Iterator types.
+
+ using iterator = flat_detail::iter_wrapper<typename storage_type::iterator,
+ const value_type>;
+ using const_iterator =
+ flat_detail::iter_wrapper<typename storage_type::const_iterator,
+ const value_type>;
+
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // Constructors.
+
+ flat_set(const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : base_type(compare, alloc) {}
+
+ template <class InputIt>
+ flat_set(InputIt first, InputIt last, const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : flat_set(compare, alloc) {
+ insert(first, last);
+ }
+
+ flat_set(std::initializer_list<value_type> init,
+ const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : flat_set(compare, alloc) {
+ insert(init.begin(), init.end());
+ }
+
+ flat_set(const flat_set &) = default;
+ flat_set(flat_set &&) = default;
+ flat_set &operator=(const flat_set &) = default;
+ flat_set &operator=(flat_set &&) = default;
+
+ // Iterators.
+
+ iterator begin() { return iterator(data().begin()); }
+ const_iterator cbegin() const { return const_iterator(data().cbegin()); }
+ const_iterator begin() const { return cbegin(); }
+
+ iterator end() { return iterator(data().end()); }
+ const_iterator cend() const { return const_iterator(data().cend()); }
+ const_iterator end() const { return cend(); }
+
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator(cend());
+ }
+ const_reverse_iterator rbegin() const { return crbegin(); }
+
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator(cbegin());
+ }
+ const_reverse_iterator rend() const { return crend(); }
+
+ // Modifiers.
+
+ std::pair<iterator, bool> insert(const value_type &value) {
+ auto it = std::lower_bound(data().begin(), data().end(), value, comp());
+ if (it == data().end() || comp()(value, *it)) {
+ return std::make_pair(iterator(data().insert(it, value)), true);
+ }
+ return std::make_pair(iterator(it), false);
+ }
+
+ iterator insert(UNUSED const_iterator hint, const value_type &value) {
+ return insert(value).first;
+ }
+
+ std::pair<iterator, bool> insert(value_type &&value) {
+ auto it = std::lower_bound(data().begin(), data().end(), value, comp());
+ if (it == data().end() || comp()(value, *it)) {
+ return std::make_pair(iterator(data().insert(it, std::move(value))),
+ true);
+ }
+ return std::make_pair(iterator(it), false);
+ }
+
+ iterator insert(UNUSED const_iterator hint, value_type &&value) {
+ return insert(value).first;
+ }
+
+ template <class InputIt>
+ void insert(InputIt first, InputIt second) {
+ for (; first != second; ++first) {
+ insert(*first);
+ }
+ }
+
+ void insert(std::initializer_list<value_type> ilist) {
+ insert(ilist.begin(), ilist.end());
+ }
+
+ template<class...Args>
+ std::pair<iterator, bool> emplace(Args&&... args) {
+ return insert(value_type(std::forward<Args>(args)...));
+ }
+
+ void erase(const_iterator pos) {
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // Cope with libstdc++ 4.8's incomplete STL (it's missing C++11
+ // vector::erase(const_iterator)) by explicitly using a non-const
+ // iterator.
+ auto pos_it = mutable_iterator(pos.get());
+#else
+ auto pos_it = pos.get();
+#endif
+ data().erase(pos_it);
+ }
+
+ void erase(const_iterator first, const_iterator last) {
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // As above, work around libstdc++ 4.8's incomplete C++11 support.
+ auto first_it = mutable_iterator(first.get());
+ auto last_it = mutable_iterator(last.get());
+#else
+ auto first_it = first.get();
+ auto last_it = last.get();
+#endif
+ data().erase(first_it, last_it);
+ }
+
+ void erase(const key_type &key) {
+ auto it = find(key);
+ if (it != end()) {
+ erase(it);
+ }
+ }
+
+ // Lookup.
+
+ size_type count(const value_type &value) const {
+ return find(value) != end() ? 1 : 0;
+ }
+
+ iterator find(const value_type &value) {
+ auto it = std::lower_bound(data().begin(), data().end(), value, comp());
+ if (it != data().end() && comp()(value, *it)) {
+ it = data().end();
+ }
+ return iterator(it);
+ }
+
+ const_iterator find(const value_type &value) const {
+ auto it = std::lower_bound(data().begin(), data().end(), value, comp());
+ if (it != data().end() && comp()(value, *it)) {
+ it = data().end();
+ }
+ return const_iterator(it);
+ }
+
+ // Observers.
+
+ value_compare value_comp() const {
+ return comp();
+ }
+
+ // Operators. All others provided by ue2::totally_ordered.
+
+ bool operator==(const flat_set &a) const {
+ return data() == a.data();
+ }
+ bool operator<(const flat_set &a) const {
+ return data() < a.data();
+ }
+
+ // Free swap function for ADL.
+ friend void swap(flat_set &a, flat_set &b) {
+ a.swap(b);
+ }
+};
+
+/**
+ * \brief Map container implemented internally as a sorted vector. Use this
+ * rather than std::map for small maps as it's faster, uses less memory and
+ * incurs less malloc time.
+ *
+ * Note: we used to use boost::flat_map, but have run into problems with all
+ * the extra machinery it instantiates.
+ *
+ * Note: ue2::flat_map does NOT provide mutable iterators, as (given the way
+ * the data is stored) it is difficult to provide a real mutable iterator that
+ * wraps std::pair<const Key, T>. Instead, all iterators are const, and you
+ * should use flat_map::at() or flat_map::operator[] to mutate the contents of
+ * the container.
+ */
+template <class Key, class T, class Compare = std::less<Key>,
+ class Allocator = std::allocator<std::pair<Key, T>>>
+class flat_map
+ : public flat_detail::flat_base<std::pair<Key, T>, Compare, Allocator>,
+ public totally_ordered<flat_map<Key, T, Compare, Allocator>> {
+public:
+ // Member types.
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = std::pair<const Key, T>;
+
+private:
+ using base_type =
+ flat_detail::flat_base<std::pair<Key, T>, Compare, Allocator>;
+ using keyval_storage_type = std::pair<key_type, mapped_type>;
+ using storage_type = typename base_type::storage_type;
+ using storage_iterator = typename storage_type::iterator;
+ using storage_const_iterator = typename storage_type::const_iterator;
+ using base_type::data;
+ using base_type::comp;
+
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // Construct a non-const iterator from a const iterator. Used in flat_map
+ // and flat_set erase() calls to work around g++-4.8 compatibility issues.
+ storage_iterator mutable_iterator(storage_const_iterator it) {
+ return data().begin() + std::distance(data().cbegin(), it);
+ }
+#endif
+
+public:
+ // More Member types.
+ using size_type = typename storage_type::size_type;
+ using difference_type = typename storage_type::difference_type;
+ using key_compare = typename base_type::key_compare;
+ using allocator_type = Allocator;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using allocator_traits_type = typename std::allocator_traits<Allocator>;
+ using pointer = typename allocator_traits_type::pointer;
+ using const_pointer = typename allocator_traits_type::const_pointer;
+
+public:
+ using const_iterator =
+ flat_detail::iter_wrapper<typename storage_type::const_iterator,
+ const keyval_storage_type>;
+
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // All iterators are const for flat_map.
+ using iterator = const_iterator;
+ using reverse_iterator = const_reverse_iterator;
+
+ // Constructors.
+
+ flat_map(const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : base_type(compare, alloc) {}
+
+ template <class InputIt>
+ flat_map(InputIt first, InputIt last, const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : flat_map(compare, alloc) {
+ insert(first, last);
+ }
+
+ flat_map(std::initializer_list<value_type> init,
+ const Compare &compare = Compare(),
+ const Allocator &alloc = Allocator())
+ : flat_map(compare, alloc) {
+ insert(init.begin(), init.end());
+ }
+
+ flat_map(const flat_map &) = default;
+ flat_map(flat_map &&) = default;
+ flat_map &operator=(const flat_map &) = default;
+ flat_map &operator=(flat_map &&) = default;
+
+ // Iterators.
+
+ const_iterator cbegin() const { return const_iterator(data().cbegin()); }
+ const_iterator begin() const { return cbegin(); }
+
+ const_iterator cend() const { return const_iterator(data().cend()); }
+ const_iterator end() const { return cend(); }
+
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator(cend());
+ }
+ const_reverse_iterator rbegin() const { return crbegin(); }
+
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator(cbegin());
+ }
+ const_reverse_iterator rend() const { return crend(); }
+
+private:
+ storage_iterator data_lower_bound(const key_type &key) {
+ return std::lower_bound(
+ data().begin(), data().end(), key,
+ [&](const keyval_storage_type &elem, const key_type &k) {
+ return comp()(elem.first, k);
+ });
+ }
+
+ storage_const_iterator
+ data_lower_bound(const key_type &key) const {
+ return std::lower_bound(
+ data().begin(), data().end(), key,
+ [&](const keyval_storage_type &elem, const key_type &k) {
+ return comp()(elem.first, k);
+ });
+ }
+
+ std::pair<storage_iterator, bool> data_insert(const value_type &value) {
+ auto it = data_lower_bound(value.first);
+ if (it == data().end() || comp()(value.first, it->first)) {
+ return std::make_pair(data().insert(it, value), true);
+ }
+ return std::make_pair(it, false);
+ }
+
+ std::pair<storage_iterator, bool> data_insert(value_type &&value) {
+ auto it = data_lower_bound(value.first);
+ if (it == data().end() || comp()(value.first, it->first)) {
+ return std::make_pair(data().insert(it, std::move(value)), true);
+ }
+ return std::make_pair(it, false);
+ }
+
+ storage_iterator data_find(const key_type &key) {
+ auto it = data_lower_bound(key);
+ if (it != data().end() && comp()(key, it->first)) {
+ it = data().end();
+ }
+ return it;
+ }
+
+ storage_const_iterator data_find(const key_type &key) const {
+ auto it = data_lower_bound(key);
+ if (it != data().end() && comp()(key, it->first)) {
+ it = data().end();
+ }
+ return it;
+ }
+
+public:
+ // Modifiers.
+
+ std::pair<iterator, bool> insert(const value_type &value) {
+ auto rv = data_insert(value);
+ return std::make_pair(iterator(rv.first), rv.second);
+ }
+
+ std::pair<iterator, bool> insert(value_type &&value) {
+ auto rv = data_insert(std::move(value));
+ return std::make_pair(iterator(rv.first), rv.second);
+ }
+
+ template <class InputIt>
+ void insert(InputIt first, InputIt second) {
+ for (; first != second; ++first) {
+ insert(*first);
+ }
+ }
+
+ void insert(std::initializer_list<value_type> ilist) {
+ insert(ilist.begin(), ilist.end());
+ }
+
+ template<class...Args>
+ std::pair<iterator, bool> emplace(Args&&... args) {
+ return insert(value_type(std::forward<Args>(args)...));
+ }
+
+ void erase(const_iterator pos) {
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // Cope with libstdc++ 4.8's incomplete STL (it's missing C++11
+ // vector::erase(const_iterator)) by explicitly using a non-const
+ // iterator.
+ auto pos_it = mutable_iterator(pos.get());
+#else
+ auto pos_it = pos.get();
+#endif
+ data().erase(pos_it);
+ }
+
+ void erase(const_iterator first, const_iterator last) {
+#if defined(SMALL_VECTOR_IS_STL_VECTOR)
+ // As above, work around libstdc++ 4.8's incomplete C++11 support.
+ auto first_it = mutable_iterator(first.get());
+ auto last_it = mutable_iterator(last.get());
+#else
+ auto first_it = first.get();
+ auto last_it = last.get();
+#endif
+ data().erase(first_it, last_it);
+ }
+
+ void erase(const key_type &key) {
+ auto it = find(key);
+ if (it != end()) {
+ erase(it);
+ }
+ }
+
+ // Lookup.
+
+ size_type count(const key_type &key) const {
+ return find(key) != end() ? 1 : 0;
+ }
+
+ const_iterator find(const key_type &key) const {
+ return const_iterator(data_find(key));
+ }
+
+ // Element access.
+
+ mapped_type &at(const key_type &key) {
+ auto it = data_find(key);
+ if (it == data().end()) {
+ throw std::out_of_range("element not found");
+ }
+ return it->second;
+ }
+
+ const mapped_type &at(const key_type &key) const {
+ auto it = data_find(key);
+ if (it == data().end()) {
+ throw std::out_of_range("element not found");
+ }
+ return it->second;
+ }
+
+ mapped_type &operator[](const key_type &key) {
+ auto p = data_insert(value_type(key, mapped_type()));
+ return p.first->second;
+ }
+
+ // Observers.
+
+ class value_compare {
+ friend class flat_map;
+ protected:
+ Compare c;
+ value_compare(Compare c_in) : c(c_in) {}
+ public:
+ bool operator()(const value_type &lhs, const value_type &rhs) {
+ return c(lhs.first, rhs.first);
+ }
+ };
+
+ value_compare value_comp() const {
+ return value_compare(comp());
+ }
+
+ // Operators. All others provided by ue2::totally_ordered.
+
+ bool operator==(const flat_map &a) const {
+ return data() == a.data();
+ }
+ bool operator<(const flat_map &a) const {
+ return data() < a.data();
+ }
+
+ // Free swap function for ADL.
+ friend void swap(flat_map &a, flat_map &b) {
+ a.swap(b);
+ }
+};
+
+} // namespace ue2
+
+namespace std {
+
+template<typename T, typename Compare, typename Allocator>
+struct hash<ue2::flat_set<T, Compare, Allocator>> {
+ size_t operator()(const ue2::flat_set<T, Compare, Allocator> &f) {
+ return ue2::ue2_hasher()(f);
+ }
+};
+
+template<typename Key, typename T, typename Compare, typename Allocator>
+struct hash<ue2::flat_map<Key, T, Compare, Allocator>> {
+ size_t operator()(const ue2::flat_map<Key, T, Compare, Allocator> &f) {
+ return ue2::ue2_hasher()(f);
+ }
+};
+
+} // namespace std
+
+#endif // UTIL_FLAT_CONTAINERS_H
diff --git a/contrib/libs/hyperscan/src/util/graph.h b/contrib/libs/hyperscan/src/util/graph.h
index 054269a726e..3e18dae5527 100644
--- a/contrib/libs/hyperscan/src/util/graph.h
+++ b/contrib/libs/hyperscan/src/util/graph.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,26 +35,26 @@
#include "container.h"
#include "ue2common.h"
-#include "util/flat_containers.h"
+#include "util/flat_containers.h"
#include "util/graph_range.h"
-#include "util/unordered.h"
+#include "util/unordered.h"
#include <boost/graph/depth_first_search.hpp>
-#include <boost/graph/strong_components.hpp>
-#include <boost/range/adaptor/map.hpp>
-
-#include <algorithm>
-#include <map>
-#include <set>
-#include <utility>
-#include <vector>
-
+#include <boost/graph/strong_components.hpp>
+#include <boost/range/adaptor/map.hpp>
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
namespace ue2 {
/** \brief True if the given vertex has no out-edges. */
template<class Graph>
bool isLeafNode(const typename Graph::vertex_descriptor& v, const Graph& g) {
- return out_degree(v, g) == 0;
+ return out_degree(v, g) == 0;
}
/** \brief True if vertex \a v has an edge to itself. */
@@ -92,7 +92,7 @@ size_t proper_in_degree(const typename Graph::vertex_descriptor &v,
/** \brief True if vertex \a v has at least one successor. */
template<class Graph>
bool has_successor(const typename Graph::vertex_descriptor &v, const Graph &g) {
- return out_degree(v, g) > 0;
+ return out_degree(v, g) > 0;
}
/** \brief True if vertex \a v has at least one successor other than itself. */
@@ -116,7 +116,7 @@ bool has_proper_successor(const typename Graph::vertex_descriptor &v,
template<class Graph, class SourceCont, class OutCont>
void find_reachable(const Graph &g, const SourceCont &sources, OutCont *out) {
using vertex_descriptor = typename Graph::vertex_descriptor;
- std::unordered_map<vertex_descriptor, boost::default_color_type> colours;
+ std::unordered_map<vertex_descriptor, boost::default_color_type> colours;
for (auto v : sources) {
boost::depth_first_visit(g, v,
@@ -134,7 +134,7 @@ void find_reachable(const Graph &g, const SourceCont &sources, OutCont *out) {
template<class Graph, class SourceCont, class OutCont>
void find_unreachable(const Graph &g, const SourceCont &sources, OutCont *out) {
using vertex_descriptor = typename Graph::vertex_descriptor;
- std::unordered_set<vertex_descriptor> reachable;
+ std::unordered_set<vertex_descriptor> reachable;
find_reachable(g, sources, &reachable);
@@ -146,46 +146,46 @@ void find_unreachable(const Graph &g, const SourceCont &sources, OutCont *out) {
}
template <class Graph>
-flat_set<typename Graph::vertex_descriptor>
-find_vertices_in_cycles(const Graph &g) {
- using vertex_descriptor = typename Graph::vertex_descriptor;
-
- std::map<vertex_descriptor, size_t> comp_map;
-
- boost::strong_components(g, boost::make_assoc_property_map(comp_map));
-
- std::map<size_t, std::vector<vertex_descriptor>> comps;
-
- for (const auto &e : comp_map) {
- comps[e.second].push_back(e.first);
- }
-
- flat_set<vertex_descriptor> rv;
-
- for (const auto &comp : comps | boost::adaptors::map_values) {
- /* every vertex in a strongly connected component is reachable from
- * every other vertex in the component. A vertex is involved in a cycle
- * therefore if it is in a strongly connected component with more than
- * one vertex or if it is the only vertex and it has a self loop. */
- assert(!comp.empty());
- if (comp.size() > 1) {
- insert(&rv, comp);
+flat_set<typename Graph::vertex_descriptor>
+find_vertices_in_cycles(const Graph &g) {
+ using vertex_descriptor = typename Graph::vertex_descriptor;
+
+ std::map<vertex_descriptor, size_t> comp_map;
+
+ boost::strong_components(g, boost::make_assoc_property_map(comp_map));
+
+ std::map<size_t, std::vector<vertex_descriptor>> comps;
+
+ for (const auto &e : comp_map) {
+ comps[e.second].push_back(e.first);
+ }
+
+ flat_set<vertex_descriptor> rv;
+
+ for (const auto &comp : comps | boost::adaptors::map_values) {
+ /* every vertex in a strongly connected component is reachable from
+ * every other vertex in the component. A vertex is involved in a cycle
+ * therefore if it is in a strongly connected component with more than
+ * one vertex or if it is the only vertex and it has a self loop. */
+ assert(!comp.empty());
+ if (comp.size() > 1) {
+ insert(&rv, comp);
continue;
- }
- vertex_descriptor v = *comp.begin();
- if (hasSelfLoop(v, g)) {
- rv.insert(v);
- }
- }
-
- return rv;
-}
-
-template <class Graph>
+ }
+ vertex_descriptor v = *comp.begin();
+ if (hasSelfLoop(v, g)) {
+ rv.insert(v);
+ }
+ }
+
+ return rv;
+}
+
+template <class Graph>
bool has_parallel_edge(const Graph &g) {
using vertex_descriptor = typename Graph::vertex_descriptor;
- ue2_unordered_set<std::pair<vertex_descriptor, vertex_descriptor>> seen;
-
+ ue2_unordered_set<std::pair<vertex_descriptor, vertex_descriptor>> seen;
+
for (const auto &e : edges_range(g)) {
auto u = source(e, g);
auto v = target(e, g);
@@ -222,45 +222,45 @@ bool is_dag(const Graph &g, bool ignore_self_loops = false) {
return true;
}
-template<typename Cont>
-class vertex_recorder : public boost::default_dfs_visitor {
-public:
- explicit vertex_recorder(Cont &o) : out(o) {}
- template<class G>
- void discover_vertex(typename Cont::value_type v, const G &) {
- out.insert(v);
- }
- Cont &out;
-};
-
-template<typename Cont>
-vertex_recorder<Cont> make_vertex_recorder(Cont &o) {
- return vertex_recorder<Cont>(o);
-}
-
-/**
- * \brief A vertex recorder visitor that sets the bits in the given bitset
- * type (e.g. boost::dynamic_bitset) corresponding to the indices of the
- * vertices encountered.
- */
-template<typename Bitset>
-class vertex_index_bitset_recorder : public boost::default_dfs_visitor {
-public:
- explicit vertex_index_bitset_recorder(Bitset &o) : out(o) {}
- template<class Graph>
- void discover_vertex(typename Graph::vertex_descriptor v, const Graph &g) {
- assert(g[v].index < out.size());
- out.set(g[v].index);
- }
- Bitset &out;
-};
-
-template<typename Bitset>
-vertex_index_bitset_recorder<Bitset>
-make_vertex_index_bitset_recorder(Bitset &o) {
- return vertex_index_bitset_recorder<Bitset>(o);
-}
-
+template<typename Cont>
+class vertex_recorder : public boost::default_dfs_visitor {
+public:
+ explicit vertex_recorder(Cont &o) : out(o) {}
+ template<class G>
+ void discover_vertex(typename Cont::value_type v, const G &) {
+ out.insert(v);
+ }
+ Cont &out;
+};
+
+template<typename Cont>
+vertex_recorder<Cont> make_vertex_recorder(Cont &o) {
+ return vertex_recorder<Cont>(o);
+}
+
+/**
+ * \brief A vertex recorder visitor that sets the bits in the given bitset
+ * type (e.g. boost::dynamic_bitset) corresponding to the indices of the
+ * vertices encountered.
+ */
+template<typename Bitset>
+class vertex_index_bitset_recorder : public boost::default_dfs_visitor {
+public:
+ explicit vertex_index_bitset_recorder(Bitset &o) : out(o) {}
+ template<class Graph>
+ void discover_vertex(typename Graph::vertex_descriptor v, const Graph &g) {
+ assert(g[v].index < out.size());
+ out.set(g[v].index);
+ }
+ Bitset &out;
+};
+
+template<typename Bitset>
+vertex_index_bitset_recorder<Bitset>
+make_vertex_index_bitset_recorder(Bitset &o) {
+ return vertex_index_bitset_recorder<Bitset>(o);
+}
+
template <class Graph>
std::pair<typename Graph::edge_descriptor, bool>
add_edge_if_not_present(typename Graph::vertex_descriptor u,
@@ -283,40 +283,40 @@ std::pair<typename Graph::edge_descriptor, bool> add_edge_if_not_present(
return e;
}
-#ifndef NDEBUG
-
-template <class Graph>
-bool hasCorrectlyNumberedVertices(const Graph &g) {
- auto count = num_vertices(g);
- std::vector<bool> ids(count, false);
- for (auto v : vertices_range(g)) {
- auto id = g[v].index;
- if (id >= count || ids[id]) {
- return false; // duplicate
- }
- ids[id] = true;
- }
- return std::find(ids.begin(), ids.end(), false) == ids.end()
- && count == vertex_index_upper_bound(g);
-}
-
-template <class Graph>
-bool hasCorrectlyNumberedEdges(const Graph &g) {
- auto count = num_edges(g);
- std::vector<bool> ids(count, false);
- for (const auto &e : edges_range(g)) {
- auto id = g[e].index;
- if (id >= count || ids[id]) {
- return false; // duplicate
- }
- ids[id] = true;
- }
- return std::find(ids.begin(), ids.end(), false) == ids.end()
- && count == edge_index_upper_bound(g);
-}
-
-#endif
-
+#ifndef NDEBUG
+
+template <class Graph>
+bool hasCorrectlyNumberedVertices(const Graph &g) {
+ auto count = num_vertices(g);
+ std::vector<bool> ids(count, false);
+ for (auto v : vertices_range(g)) {
+ auto id = g[v].index;
+ if (id >= count || ids[id]) {
+ return false; // duplicate
+ }
+ ids[id] = true;
+ }
+ return std::find(ids.begin(), ids.end(), false) == ids.end()
+ && count == vertex_index_upper_bound(g);
+}
+
+template <class Graph>
+bool hasCorrectlyNumberedEdges(const Graph &g) {
+ auto count = num_edges(g);
+ std::vector<bool> ids(count, false);
+ for (const auto &e : edges_range(g)) {
+ auto id = g[e].index;
+ if (id >= count || ids[id]) {
+ return false; // duplicate
+ }
+ ids[id] = true;
+ }
+ return std::find(ids.begin(), ids.end(), false) == ids.end()
+ && count == edge_index_upper_bound(g);
+}
+
+#endif
+
} // namespace ue2
#endif // UTIL_GRAPH_H
diff --git a/contrib/libs/hyperscan/src/util/graph_range.h b/contrib/libs/hyperscan/src/util/graph_range.h
index ae3bd9bf66d..3df06911a72 100644
--- a/contrib/libs/hyperscan/src/util/graph_range.h
+++ b/contrib/libs/hyperscan/src/util/graph_range.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/util/graph_small_color_map.h b/contrib/libs/hyperscan/src/util/graph_small_color_map.h
index 036d4ca772c..249b71531c5 100644
--- a/contrib/libs/hyperscan/src/util/graph_small_color_map.h
+++ b/contrib/libs/hyperscan/src/util/graph_small_color_map.h
@@ -1,119 +1,119 @@
-/*
+/*
* Copyright (c) 2017-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \brief Small Color Map: implements a property map designed to represent
- * colors using minimal memory (two bits per index).
- *
- * This is based on the Boost BGL two_bit_color_map, but provides some extra
- * functionality (such as a fill operation).
- */
-
-#ifndef GRAPH_SMALL_COLOR_MAP_H
-#define GRAPH_SMALL_COLOR_MAP_H
-
-#include "ue2common.h"
-
-#include <cstring>
-#include <memory>
-#include <vector>
-
-namespace ue2 {
-
-enum class small_color : u8 {
- white = 0,
- gray = 1,
- black = 2
- // Note: we have room for one more colour.
-};
-
-} // namespace ue2
-
-namespace boost {
-
-/** \brief Specialisation of boost::color_traits for small_color. */
-template<>
-struct color_traits<ue2::small_color> {
- static ue2::small_color white() { return ue2::small_color::white; }
- static ue2::small_color gray() { return ue2::small_color::gray; }
- static ue2::small_color black() { return ue2::small_color::black; }
-};
-
-} // namespace boost
-
-namespace ue2 {
-
-static constexpr u8 fill_lut[] = {
- 0, // white
- 0x55, // gray
- 0xaa, // black
-};
-
-/**
- * \brief Small Color Map: implements a property map designed to represent
- * colors using minimal memory (two bits per index).
- *
- * If your graph type provides an index map in get(vertex_index, g), you can
- * use make_small_color_map() to construct this.
- */
-template<typename IndexMap>
-class small_color_map {
- size_t n;
- IndexMap index_map;
-
- // This class is passed by value into (potentially recursive) BGL
- // algorithms, so we use a shared_ptr to keep the copy lightweight and
- // ensure that data is correctly destroyed.
- std::shared_ptr<std::vector<u8>> data;
-
- static constexpr size_t bit_size = 2;
- static constexpr size_t entries_per_byte = (sizeof(u8) * 8) / bit_size;
- static constexpr u8 bit_mask = (1U << bit_size) - 1;
-
-public:
- using key_type = typename boost::property_traits<IndexMap>::key_type;
- using value_type = small_color;
- using reference = small_color;
- using category = boost::read_write_property_map_tag;
-
- small_color_map(size_t n_in, const IndexMap &index_map_in)
- : n(n_in), index_map(index_map_in) {
- size_t num_bytes = (n + entries_per_byte - 1) / entries_per_byte;
- data = std::make_shared<std::vector<unsigned char>>(num_bytes);
- fill(small_color::white);
- }
-
- void fill(small_color color) {
- assert(static_cast<u8>(color) < sizeof(fill_lut));
- u8 val = fill_lut[static_cast<u8>(color)];
- std::memset(data->data(), val, data->size());
- }
-
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \brief Small Color Map: implements a property map designed to represent
+ * colors using minimal memory (two bits per index).
+ *
+ * This is based on the Boost BGL two_bit_color_map, but provides some extra
+ * functionality (such as a fill operation).
+ */
+
+#ifndef GRAPH_SMALL_COLOR_MAP_H
+#define GRAPH_SMALL_COLOR_MAP_H
+
+#include "ue2common.h"
+
+#include <cstring>
+#include <memory>
+#include <vector>
+
+namespace ue2 {
+
+enum class small_color : u8 {
+ white = 0,
+ gray = 1,
+ black = 2
+ // Note: we have room for one more colour.
+};
+
+} // namespace ue2
+
+namespace boost {
+
+/** \brief Specialisation of boost::color_traits for small_color. */
+template<>
+struct color_traits<ue2::small_color> {
+ static ue2::small_color white() { return ue2::small_color::white; }
+ static ue2::small_color gray() { return ue2::small_color::gray; }
+ static ue2::small_color black() { return ue2::small_color::black; }
+};
+
+} // namespace boost
+
+namespace ue2 {
+
+static constexpr u8 fill_lut[] = {
+ 0, // white
+ 0x55, // gray
+ 0xaa, // black
+};
+
+/**
+ * \brief Small Color Map: implements a property map designed to represent
+ * colors using minimal memory (two bits per index).
+ *
+ * If your graph type provides an index map in get(vertex_index, g), you can
+ * use make_small_color_map() to construct this.
+ */
+template<typename IndexMap>
+class small_color_map {
+ size_t n;
+ IndexMap index_map;
+
+ // This class is passed by value into (potentially recursive) BGL
+ // algorithms, so we use a shared_ptr to keep the copy lightweight and
+ // ensure that data is correctly destroyed.
+ std::shared_ptr<std::vector<u8>> data;
+
+ static constexpr size_t bit_size = 2;
+ static constexpr size_t entries_per_byte = (sizeof(u8) * 8) / bit_size;
+ static constexpr u8 bit_mask = (1U << bit_size) - 1;
+
+public:
+ using key_type = typename boost::property_traits<IndexMap>::key_type;
+ using value_type = small_color;
+ using reference = small_color;
+ using category = boost::read_write_property_map_tag;
+
+ small_color_map(size_t n_in, const IndexMap &index_map_in)
+ : n(n_in), index_map(index_map_in) {
+ size_t num_bytes = (n + entries_per_byte - 1) / entries_per_byte;
+ data = std::make_shared<std::vector<unsigned char>>(num_bytes);
+ fill(small_color::white);
+ }
+
+ void fill(small_color color) {
+ assert(static_cast<u8>(color) < sizeof(fill_lut));
+ u8 val = fill_lut[static_cast<u8>(color)];
+ std::memset(data->data(), val, data->size());
+ }
+
size_t count(small_color color) const {
assert(static_cast<u8>(color) < sizeof(fill_lut));
size_t num = 0;
@@ -129,48 +129,48 @@ public:
return num;
}
- small_color get_impl(key_type key) const {
- auto i = get(index_map, key);
- assert(i < n);
- size_t byte = i / entries_per_byte;
- assert(byte < data->size());
- size_t bit = (i % entries_per_byte) * bit_size;
- u8 val = ((*data)[byte] >> bit) & bit_mask;
- return static_cast<small_color>(val);
- }
-
- void put_impl(key_type key, small_color color) {
- auto i = get(index_map, key);
- assert(i < n);
- size_t byte = i / entries_per_byte;
- assert(byte < data->size());
- size_t bit = (i % entries_per_byte) * bit_size;
- auto &block = (*data)[byte];
- u8 val = static_cast<u8>(color);
- block = (block & ~(bit_mask << bit)) | (val << bit);
- }
-};
-
-template<typename IndexMap>
-small_color get(const small_color_map<IndexMap> &color_map,
- typename boost::property_traits<IndexMap>::key_type key) {
- return color_map.get_impl(key);
-}
-
-template<typename IndexMap>
-void put(small_color_map<IndexMap> &color_map,
- typename boost::property_traits<IndexMap>::key_type key,
- small_color val) {
- color_map.put_impl(key, val);
-}
-
-template<typename Graph>
-auto make_small_color_map(const Graph &g)
- -> small_color_map<decltype(get(vertex_index, g))> {
- return small_color_map<decltype(get(vertex_index, g))>(
- num_vertices(g), get(vertex_index, g));
-}
-
-} // namespace ue2
-
-#endif // GRAPH_SMALL_COLOR_MAP_H
+ small_color get_impl(key_type key) const {
+ auto i = get(index_map, key);
+ assert(i < n);
+ size_t byte = i / entries_per_byte;
+ assert(byte < data->size());
+ size_t bit = (i % entries_per_byte) * bit_size;
+ u8 val = ((*data)[byte] >> bit) & bit_mask;
+ return static_cast<small_color>(val);
+ }
+
+ void put_impl(key_type key, small_color color) {
+ auto i = get(index_map, key);
+ assert(i < n);
+ size_t byte = i / entries_per_byte;
+ assert(byte < data->size());
+ size_t bit = (i % entries_per_byte) * bit_size;
+ auto &block = (*data)[byte];
+ u8 val = static_cast<u8>(color);
+ block = (block & ~(bit_mask << bit)) | (val << bit);
+ }
+};
+
+template<typename IndexMap>
+small_color get(const small_color_map<IndexMap> &color_map,
+ typename boost::property_traits<IndexMap>::key_type key) {
+ return color_map.get_impl(key);
+}
+
+template<typename IndexMap>
+void put(small_color_map<IndexMap> &color_map,
+ typename boost::property_traits<IndexMap>::key_type key,
+ small_color val) {
+ color_map.put_impl(key, val);
+}
+
+template<typename Graph>
+auto make_small_color_map(const Graph &g)
+ -> small_color_map<decltype(get(vertex_index, g))> {
+ return small_color_map<decltype(get(vertex_index, g))>(
+ num_vertices(g), get(vertex_index, g));
+}
+
+} // namespace ue2
+
+#endif // GRAPH_SMALL_COLOR_MAP_H
diff --git a/contrib/libs/hyperscan/src/util/hash.h b/contrib/libs/hyperscan/src/util/hash.h
index 5cd4cbd29be..60bc670abbf 100644
--- a/contrib/libs/hyperscan/src/util/hash.h
+++ b/contrib/libs/hyperscan/src/util/hash.h
@@ -1,207 +1,207 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Hashing utility functions.
- */
-
-#ifndef UTIL_HASH_H
-#define UTIL_HASH_H
-
-#include <functional>
-#include <string>
-#include <type_traits>
-#include <utility>
-
-namespace ue2 {
-
-namespace hash_detail {
-
-inline
-void hash_combine_impl(size_t &seed, size_t value) {
- // Note: constants explicitly truncated on 32-bit platforms.
- const size_t a = (size_t)0x0b4e0ef37bc32127ULL;
- const size_t b = (size_t)0x318f07b0c8eb9be9ULL;
- seed ^= value * a;
- seed += b;
-}
-
-/** \brief Helper that determines whether std::begin() exists for T. */
-template<typename T>
-struct is_container_check {
-private:
- template<typename C>
- static auto has_begin_function(const C &obj) -> decltype(std::begin(obj)) {
- return std::begin(obj);
- }
- static void has_begin_function(...) {
- return;
- }
- using has_begin_type = decltype(has_begin_function(std::declval<T>()));
-
-public:
- static const bool value = !std::is_void<has_begin_type>::value;
-};
-
-/** \brief Type trait to enable on whether T is a container. */
-template<typename T>
-struct is_container
- : public ::std::integral_constant<bool, is_container_check<T>::value> {};
-
-/** \brief Helper that determines whether T::hash() exists. */
-template<typename T>
-struct has_hash_member_check {
-private:
- template<typename C>
- static auto has_hash_member_function(const C &obj) -> decltype(obj.hash()) {
- return obj.hash();
- }
- static void has_hash_member_function(...) {
- return;
- }
- using has_hash = decltype(has_hash_member_function(std::declval<T>()));
-
-public:
- static const bool value = !std::is_void<has_hash>::value;
-};
-
-/** \brief Type trait to enable on whether T::hash() exists. */
-template<typename T>
-struct has_hash_member
- : public ::std::integral_constant<bool, has_hash_member_check<T>::value> {};
-
-/** \brief Default hash: falls back to std::hash. */
-template<typename T, typename Enable = void>
-struct ue2_hash {
- using decayed_type = typename std::decay<T>::type;
- size_t operator()(const T &obj) const {
- return std::hash<decayed_type>()(obj);
- }
-};
-
-/** \brief Hash for std::pair. */
-template<typename A, typename B>
-struct ue2_hash<std::pair<A, B>, void> {
- size_t operator()(const std::pair<A, B> &p) const {
- size_t v = 0;
- hash_combine_impl(v, ue2_hash<A>()(p.first));
- hash_combine_impl(v, ue2_hash<B>()(p.second));
- return v;
- }
-};
-
-/** \brief Hash for any type that has a hash() member function. */
-template<typename T>
-struct ue2_hash<T, typename std::enable_if<has_hash_member<T>::value>::type> {
- size_t operator()(const T &obj) const {
- return obj.hash();
- }
-};
-
-/**
- * \brief Hash for any container type that supports std::begin().
- *
- * We exempt std::string as std::hash<std:string> is provided and quicker.
- */
-template<typename T>
-struct ue2_hash<T, typename std::enable_if<
- is_container<T>::value &&
- !std::is_same<typename std::decay<T>::type, std::string>::value &&
- !has_hash_member<T>::value>::type> {
- size_t operator()(const T &obj) const {
- size_t v = 0;
- for (const auto &elem : obj) {
- using element_type = typename std::decay<decltype(elem)>::type;
- hash_combine_impl(v, ue2_hash<element_type>()(elem));
- }
- return v;
- }
-};
-
-/** \brief Hash for enum types. */
-template<typename T>
-struct ue2_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> {
- size_t operator()(const T &obj) const {
- using utype = typename std::underlying_type<T>::type;
- return ue2_hash<utype>()(static_cast<utype>(obj));
- }
-};
-
-template<typename T>
-void hash_combine(size_t &seed, const T &obj) {
- hash_combine_impl(seed, ue2_hash<T>()(obj));
-}
-
-template<typename T>
-void hash_build(size_t &v, const T &obj) {
- hash_combine(v, obj);
-}
-
-template<typename T, typename... Args>
-void hash_build(size_t &v, const T &obj, Args&&... args) {
- hash_build(v, obj);
- hash_build(v, args...); // recursive
-}
-
-} // namespace hash_detail
-
-using hash_detail::hash_combine;
-
-/**
- * \brief Hasher for general use.
- *
- * Provides operators for most standard containers and falls back to
- * std::hash<T>.
- */
-struct ue2_hasher {
- template<typename T>
- size_t operator()(const T &obj) const {
- return hash_detail::ue2_hash<T>()(obj);
- }
-};
-
-/**
- * \brief Computes the combined hash of all its arguments.
- *
- * Simply use:
- *
- * size_t hash = hash_all(a, b, c, d);
- *
- * Where a, b, c and d are hashable.
- */
-template<typename... Args>
-size_t hash_all(Args&&... args) {
- size_t v = 0;
- hash_detail::hash_build(v, args...);
- return v;
-}
-
-} // namespace ue2
-
-#endif // UTIL_HASH_H
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Hashing utility functions.
+ */
+
+#ifndef UTIL_HASH_H
+#define UTIL_HASH_H
+
+#include <functional>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+namespace ue2 {
+
+namespace hash_detail {
+
+inline
+void hash_combine_impl(size_t &seed, size_t value) {
+ // Note: constants explicitly truncated on 32-bit platforms.
+ const size_t a = (size_t)0x0b4e0ef37bc32127ULL;
+ const size_t b = (size_t)0x318f07b0c8eb9be9ULL;
+ seed ^= value * a;
+ seed += b;
+}
+
+/** \brief Helper that determines whether std::begin() exists for T. */
+template<typename T>
+struct is_container_check {
+private:
+ template<typename C>
+ static auto has_begin_function(const C &obj) -> decltype(std::begin(obj)) {
+ return std::begin(obj);
+ }
+ static void has_begin_function(...) {
+ return;
+ }
+ using has_begin_type = decltype(has_begin_function(std::declval<T>()));
+
+public:
+ static const bool value = !std::is_void<has_begin_type>::value;
+};
+
+/** \brief Type trait to enable on whether T is a container. */
+template<typename T>
+struct is_container
+ : public ::std::integral_constant<bool, is_container_check<T>::value> {};
+
+/** \brief Helper that determines whether T::hash() exists. */
+template<typename T>
+struct has_hash_member_check {
+private:
+ template<typename C>
+ static auto has_hash_member_function(const C &obj) -> decltype(obj.hash()) {
+ return obj.hash();
+ }
+ static void has_hash_member_function(...) {
+ return;
+ }
+ using has_hash = decltype(has_hash_member_function(std::declval<T>()));
+
+public:
+ static const bool value = !std::is_void<has_hash>::value;
+};
+
+/** \brief Type trait to enable on whether T::hash() exists. */
+template<typename T>
+struct has_hash_member
+ : public ::std::integral_constant<bool, has_hash_member_check<T>::value> {};
+
+/** \brief Default hash: falls back to std::hash. */
+template<typename T, typename Enable = void>
+struct ue2_hash {
+ using decayed_type = typename std::decay<T>::type;
+ size_t operator()(const T &obj) const {
+ return std::hash<decayed_type>()(obj);
+ }
+};
+
+/** \brief Hash for std::pair. */
+template<typename A, typename B>
+struct ue2_hash<std::pair<A, B>, void> {
+ size_t operator()(const std::pair<A, B> &p) const {
+ size_t v = 0;
+ hash_combine_impl(v, ue2_hash<A>()(p.first));
+ hash_combine_impl(v, ue2_hash<B>()(p.second));
+ return v;
+ }
+};
+
+/** \brief Hash for any type that has a hash() member function. */
+template<typename T>
+struct ue2_hash<T, typename std::enable_if<has_hash_member<T>::value>::type> {
+ size_t operator()(const T &obj) const {
+ return obj.hash();
+ }
+};
+
+/**
+ * \brief Hash for any container type that supports std::begin().
+ *
+ * We exempt std::string as std::hash<std:string> is provided and quicker.
+ */
+template<typename T>
+struct ue2_hash<T, typename std::enable_if<
+ is_container<T>::value &&
+ !std::is_same<typename std::decay<T>::type, std::string>::value &&
+ !has_hash_member<T>::value>::type> {
+ size_t operator()(const T &obj) const {
+ size_t v = 0;
+ for (const auto &elem : obj) {
+ using element_type = typename std::decay<decltype(elem)>::type;
+ hash_combine_impl(v, ue2_hash<element_type>()(elem));
+ }
+ return v;
+ }
+};
+
+/** \brief Hash for enum types. */
+template<typename T>
+struct ue2_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> {
+ size_t operator()(const T &obj) const {
+ using utype = typename std::underlying_type<T>::type;
+ return ue2_hash<utype>()(static_cast<utype>(obj));
+ }
+};
+
+template<typename T>
+void hash_combine(size_t &seed, const T &obj) {
+ hash_combine_impl(seed, ue2_hash<T>()(obj));
+}
+
+template<typename T>
+void hash_build(size_t &v, const T &obj) {
+ hash_combine(v, obj);
+}
+
+template<typename T, typename... Args>
+void hash_build(size_t &v, const T &obj, Args&&... args) {
+ hash_build(v, obj);
+ hash_build(v, args...); // recursive
+}
+
+} // namespace hash_detail
+
+using hash_detail::hash_combine;
+
+/**
+ * \brief Hasher for general use.
+ *
+ * Provides operators for most standard containers and falls back to
+ * std::hash<T>.
+ */
+struct ue2_hasher {
+ template<typename T>
+ size_t operator()(const T &obj) const {
+ return hash_detail::ue2_hash<T>()(obj);
+ }
+};
+
+/**
+ * \brief Computes the combined hash of all its arguments.
+ *
+ * Simply use:
+ *
+ * size_t hash = hash_all(a, b, c, d);
+ *
+ * Where a, b, c and d are hashable.
+ */
+template<typename... Args>
+size_t hash_all(Args&&... args) {
+ size_t v = 0;
+ hash_detail::hash_build(v, args...);
+ return v;
+}
+
+} // namespace ue2
+
+#endif // UTIL_HASH_H
diff --git a/contrib/libs/hyperscan/src/util/hash_dynamic_bitset.h b/contrib/libs/hyperscan/src/util/hash_dynamic_bitset.h
index 213d9237d5f..65bc29c30b7 100644
--- a/contrib/libs/hyperscan/src/util/hash_dynamic_bitset.h
+++ b/contrib/libs/hyperscan/src/util/hash_dynamic_bitset.h
@@ -1,96 +1,96 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Hashing utility functions.
- */
-
-#ifndef UTIL_HASH_DYNAMIC_BITSET_H
-#define UTIL_HASH_DYNAMIC_BITSET_H
-
-#include "hash.h"
-
-#include <boost/dynamic_bitset.hpp>
-
-#include <iterator>
-
-namespace ue2 {
-
-/**
- * \brief An output iterator which calculates the combined hash of all elements
- * written to it.
- *
- * The location to output the hash is provided to the constructor and should
- * already be zero initialised.
- */
-struct hash_output_it {
- using value_type = void;
- using difference_type = ptrdiff_t;
- using pointer = void *;
- using reference = void;
- using iterator_category = std::output_iterator_tag;
-
- hash_output_it(size_t *hash_out = nullptr) : out(hash_out) {}
- hash_output_it &operator++() {
- return *this;
- }
- hash_output_it &operator++(int) {
- return *this;
- }
-
- struct deref_proxy {
- deref_proxy(size_t *hash_out) : out(hash_out) {}
-
- template<typename T>
- void operator=(const T &val) const {
- hash_combine(*out, val);
- }
-
- private:
- size_t *out; /* output location of the owning iterator */
- };
-
- deref_proxy operator*() { return {out}; }
-
-private:
- size_t *out; /* location to output the hashes to */
-};
-
-/* Function object for hashing a dynamic bitset */
-struct hash_dynamic_bitset {
- size_t operator()(const boost::dynamic_bitset<> &bs) const {
- size_t rv = 0;
- to_block_range(bs, hash_output_it(&rv));
- return rv;
- }
-};
-
-} // namespace ue2
-
-#endif
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Hashing utility functions.
+ */
+
+#ifndef UTIL_HASH_DYNAMIC_BITSET_H
+#define UTIL_HASH_DYNAMIC_BITSET_H
+
+#include "hash.h"
+
+#include <boost/dynamic_bitset.hpp>
+
+#include <iterator>
+
+namespace ue2 {
+
+/**
+ * \brief An output iterator which calculates the combined hash of all elements
+ * written to it.
+ *
+ * The location to output the hash is provided to the constructor and should
+ * already be zero initialised.
+ */
+struct hash_output_it {
+ using value_type = void;
+ using difference_type = ptrdiff_t;
+ using pointer = void *;
+ using reference = void;
+ using iterator_category = std::output_iterator_tag;
+
+ hash_output_it(size_t *hash_out = nullptr) : out(hash_out) {}
+ hash_output_it &operator++() {
+ return *this;
+ }
+ hash_output_it &operator++(int) {
+ return *this;
+ }
+
+ struct deref_proxy {
+ deref_proxy(size_t *hash_out) : out(hash_out) {}
+
+ template<typename T>
+ void operator=(const T &val) const {
+ hash_combine(*out, val);
+ }
+
+ private:
+ size_t *out; /* output location of the owning iterator */
+ };
+
+ deref_proxy operator*() { return {out}; }
+
+private:
+ size_t *out; /* location to output the hashes to */
+};
+
+/* Function object for hashing a dynamic bitset */
+struct hash_dynamic_bitset {
+ size_t operator()(const boost::dynamic_bitset<> &bs) const {
+ size_t rv = 0;
+ to_block_range(bs, hash_output_it(&rv));
+ return rv;
+ }
+};
+
+} // namespace ue2
+
+#endif
diff --git a/contrib/libs/hyperscan/src/util/insertion_ordered.h b/contrib/libs/hyperscan/src/util/insertion_ordered.h
index c47b4d64736..2067d350792 100644
--- a/contrib/libs/hyperscan/src/util/insertion_ordered.h
+++ b/contrib/libs/hyperscan/src/util/insertion_ordered.h
@@ -1,368 +1,368 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UTIL_INSERTION_ORDERED_H
-#define UTIL_INSERTION_ORDERED_H
-
-/**
- * \file
- * \brief Insertion-ordered associative containers (set, map).
- */
-
-#include "util/operators.h"
-#include "util/unordered.h"
-
-#include <cassert>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-#include <boost/iterator/iterator_facade.hpp>
-
-namespace ue2 {
-
-namespace insertion_ordered_detail {
-
-// Iterator facade that wraps an underlying iterator, so that we get our
-// own iterator types.
-template<class WrappedIter, class Value>
-class iter_wrapper
- : public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
- boost::random_access_traversal_tag> {
-public:
- iter_wrapper() = default;
- explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
-
- // Templated copy-constructor to allow for interoperable iterator and
- // const_iterator.
- template<class, class> friend class iter_wrapper;
-
- template<class OtherIter, class OtherValue>
- iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
- typename std::enable_if<std::is_convertible<
- OtherIter, WrappedIter>::value>::type * = nullptr)
- : it(std::move(other.it)) {}
-
- WrappedIter get() const { return it; }
-
-private:
- friend class boost::iterator_core_access;
-
- WrappedIter it;
-
- void increment() { ++it; }
- void decrement() { --it; }
- void advance(size_t n) { it += n; }
- typename std::iterator_traits<WrappedIter>::difference_type
- distance_to(const iter_wrapper &other) const {
- return other.it - it;
- }
- bool equal(const iter_wrapper &other) const { return it == other.it; }
- Value &dereference() const { return *it; }
-};
-
-template<class Key, class Element>
-class element_store {
- std::vector<Element> data;
- ue2_unordered_map<Key, size_t> map;
-
-public:
- bool empty() const {
- return data.empty();
- }
-
- size_t size() const {
- assert(data.size() == map.size());
- return data.size();
- }
-
- void clear() {
- data.clear();
- map.clear();
- }
-
- void reserve(size_t n) {
- data.reserve(n);
- map.reserve(n);
- }
-
- // Iteration.
-
- using const_iterator =
- iter_wrapper<typename std::vector<Element>::const_iterator,
- const Element>;
- using iterator =
- iter_wrapper<typename std::vector<Element>::iterator, Element>;
-
- const_iterator begin() const {
- return const_iterator(data.begin());
- }
-
- const_iterator end() const {
- return const_iterator(data.end());
- }
-
- iterator begin() {
- return iterator(data.begin());
- }
-
- iterator end() {
- return iterator(data.end());
- }
-
- // Search.
-
- const_iterator find(const Key &key) const {
- auto map_it = map.find(key);
- if (map_it == map.end()) {
- return end();
- }
- auto idx = map_it->second;
- assert(idx < data.size());
- return begin() + idx;
- }
-
- iterator find(const Key &key) {
- auto map_it = map.find(key);
- if (map_it == map.end()) {
- return end();
- }
- auto idx = map_it->second;
- assert(idx < data.size());
- return begin() + idx;
- }
-
- // Insert.
-
- std::pair<iterator, bool> insert(const Key &key, const Element &element) {
- const auto idx = data.size();
- if (map.emplace(key, idx).second) {
- data.push_back(element);
- return {begin() + idx, true};
- }
- return {end(), false};
- }
-
- bool operator==(const element_store &a) const {
- return data == a.data;
- }
-
- bool operator<(const element_store &a) const {
- return data < a.data;
- }
-
- void swap(element_store &a) {
- using std::swap;
- swap(data, a.data);
- swap(map, a.map);
- }
-};
-
-} // namespace insertion_ordered_detail
-
-template<class Key, class Value>
-class insertion_ordered_map
- : public totally_ordered<insertion_ordered_map<Key, Value>> {
-public:
- using key_type = Key;
- using mapped_type = Value;
- using value_type = std::pair<const Key, Value>;
-
-private:
- using store_type = insertion_ordered_detail::element_store<Key, value_type>;
- store_type store;
-
-public:
- using const_iterator = typename store_type::const_iterator;
- using iterator = typename store_type::iterator;
-
- insertion_ordered_map() = default;
-
- template<class Iter>
- insertion_ordered_map(Iter it, Iter it_end) {
- insert(it, it_end);
- }
-
- explicit insertion_ordered_map(std::initializer_list<value_type> init) {
- insert(init.begin(), init.end());
- }
-
- const_iterator begin() const { return store.begin(); }
- const_iterator end() const { return store.end(); }
- iterator begin() { return store.begin(); }
- iterator end() { return store.end(); }
-
- const_iterator find(const Key &key) const {
- return store.find(key);
- }
-
- iterator find(const Key &key) {
- return store.find(key);
- }
-
- std::pair<iterator, bool> insert(const std::pair<const Key, Value> &p) {
- return store.insert(p.first, p);
- }
-
- template<class Iter>
- void insert(Iter it, Iter it_end) {
- for (; it != it_end; ++it) {
- insert(*it);
- }
- }
-
- Value &operator[](const Key &key) {
- auto it = find(key);
- if (it == end()) {
- it = insert({key, Value{}}).first;
- }
- return it->second;
- }
-
- const Value &at(const Key &key) const {
- return find(key)->second;
- }
-
- Value &at(const Key &key) {
- return find(key)->second;
- }
-
- bool empty() const {
- return store.empty();
- }
-
- size_t size() const {
- return store.size();
- }
-
- void clear() {
- store.clear();
- }
-
- void reserve(size_t n) {
- store.reserve(n);
- }
-
- bool operator==(const insertion_ordered_map &a) const {
- return store == a.store;
- }
-
- bool operator<(const insertion_ordered_map &a) const {
- return store < a.store;
- }
-
- void swap(insertion_ordered_map &a) {
- store.swap(a.store);
- }
-
- friend void swap(insertion_ordered_map &a, insertion_ordered_map &b) {
- a.swap(b);
- }
-};
-
-template<class Key>
-class insertion_ordered_set
- : public totally_ordered<insertion_ordered_set<Key>> {
-public:
- using key_type = Key;
- using value_type = Key;
-
-private:
- using store_type = insertion_ordered_detail::element_store<Key, value_type>;
- store_type store;
-
-public:
- using const_iterator = typename store_type::const_iterator;
- using iterator = typename store_type::iterator;
-
- insertion_ordered_set() = default;
-
- template<class Iter>
- insertion_ordered_set(Iter it, Iter it_end) {
- insert(it, it_end);
- }
-
- explicit insertion_ordered_set(std::initializer_list<value_type> init) {
- insert(init.begin(), init.end());
- }
-
- const_iterator begin() const { return store.begin(); }
- const_iterator end() const { return store.end(); }
-
- const_iterator find(const Key &key) const {
- return store.find(key);
- }
-
- std::pair<iterator, bool> insert(const Key &key) {
- return store.insert(key, key);
- }
-
- template<class Iter>
- void insert(Iter it, Iter it_end) {
- for (; it != it_end; ++it) {
- insert(*it);
- }
- }
-
- bool empty() const {
- return store.empty();
- }
-
- size_t size() const {
- return store.size();
- }
-
- void clear() {
- store.clear();
- }
-
- void reserve(size_t n) {
- store.reserve(n);
- }
-
- bool operator==(const insertion_ordered_set &a) const {
- return store == a.store;
- }
-
- bool operator<(const insertion_ordered_set &a) const {
- return store < a.store;
- }
-
- void swap(insertion_ordered_set &a) {
- store.swap(a.store);
- }
-
- friend void swap(insertion_ordered_set &a, insertion_ordered_set &b) {
- a.swap(b);
- }
-};
-
-} // namespace ue2
-
-#endif // UTIL_INSERTION_ORDERED_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UTIL_INSERTION_ORDERED_H
+#define UTIL_INSERTION_ORDERED_H
+
+/**
+ * \file
+ * \brief Insertion-ordered associative containers (set, map).
+ */
+
+#include "util/operators.h"
+#include "util/unordered.h"
+
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <boost/iterator/iterator_facade.hpp>
+
+namespace ue2 {
+
+namespace insertion_ordered_detail {
+
+// Iterator facade that wraps an underlying iterator, so that we get our
+// own iterator types.
+template<class WrappedIter, class Value>
+class iter_wrapper
+ : public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
+ boost::random_access_traversal_tag> {
+public:
+ iter_wrapper() = default;
+ explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
+
+ // Templated copy-constructor to allow for interoperable iterator and
+ // const_iterator.
+ template<class, class> friend class iter_wrapper;
+
+ template<class OtherIter, class OtherValue>
+ iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
+ typename std::enable_if<std::is_convertible<
+ OtherIter, WrappedIter>::value>::type * = nullptr)
+ : it(std::move(other.it)) {}
+
+ WrappedIter get() const { return it; }
+
+private:
+ friend class boost::iterator_core_access;
+
+ WrappedIter it;
+
+ void increment() { ++it; }
+ void decrement() { --it; }
+ void advance(size_t n) { it += n; }
+ typename std::iterator_traits<WrappedIter>::difference_type
+ distance_to(const iter_wrapper &other) const {
+ return other.it - it;
+ }
+ bool equal(const iter_wrapper &other) const { return it == other.it; }
+ Value &dereference() const { return *it; }
+};
+
+template<class Key, class Element>
+class element_store {
+ std::vector<Element> data;
+ ue2_unordered_map<Key, size_t> map;
+
+public:
+ bool empty() const {
+ return data.empty();
+ }
+
+ size_t size() const {
+ assert(data.size() == map.size());
+ return data.size();
+ }
+
+ void clear() {
+ data.clear();
+ map.clear();
+ }
+
+ void reserve(size_t n) {
+ data.reserve(n);
+ map.reserve(n);
+ }
+
+ // Iteration.
+
+ using const_iterator =
+ iter_wrapper<typename std::vector<Element>::const_iterator,
+ const Element>;
+ using iterator =
+ iter_wrapper<typename std::vector<Element>::iterator, Element>;
+
+ const_iterator begin() const {
+ return const_iterator(data.begin());
+ }
+
+ const_iterator end() const {
+ return const_iterator(data.end());
+ }
+
+ iterator begin() {
+ return iterator(data.begin());
+ }
+
+ iterator end() {
+ return iterator(data.end());
+ }
+
+ // Search.
+
+ const_iterator find(const Key &key) const {
+ auto map_it = map.find(key);
+ if (map_it == map.end()) {
+ return end();
+ }
+ auto idx = map_it->second;
+ assert(idx < data.size());
+ return begin() + idx;
+ }
+
+ iterator find(const Key &key) {
+ auto map_it = map.find(key);
+ if (map_it == map.end()) {
+ return end();
+ }
+ auto idx = map_it->second;
+ assert(idx < data.size());
+ return begin() + idx;
+ }
+
+ // Insert.
+
+ std::pair<iterator, bool> insert(const Key &key, const Element &element) {
+ const auto idx = data.size();
+ if (map.emplace(key, idx).second) {
+ data.push_back(element);
+ return {begin() + idx, true};
+ }
+ return {end(), false};
+ }
+
+ bool operator==(const element_store &a) const {
+ return data == a.data;
+ }
+
+ bool operator<(const element_store &a) const {
+ return data < a.data;
+ }
+
+ void swap(element_store &a) {
+ using std::swap;
+ swap(data, a.data);
+ swap(map, a.map);
+ }
+};
+
+} // namespace insertion_ordered_detail
+
+template<class Key, class Value>
+class insertion_ordered_map
+ : public totally_ordered<insertion_ordered_map<Key, Value>> {
+public:
+ using key_type = Key;
+ using mapped_type = Value;
+ using value_type = std::pair<const Key, Value>;
+
+private:
+ using store_type = insertion_ordered_detail::element_store<Key, value_type>;
+ store_type store;
+
+public:
+ using const_iterator = typename store_type::const_iterator;
+ using iterator = typename store_type::iterator;
+
+ insertion_ordered_map() = default;
+
+ template<class Iter>
+ insertion_ordered_map(Iter it, Iter it_end) {
+ insert(it, it_end);
+ }
+
+ explicit insertion_ordered_map(std::initializer_list<value_type> init) {
+ insert(init.begin(), init.end());
+ }
+
+ const_iterator begin() const { return store.begin(); }
+ const_iterator end() const { return store.end(); }
+ iterator begin() { return store.begin(); }
+ iterator end() { return store.end(); }
+
+ const_iterator find(const Key &key) const {
+ return store.find(key);
+ }
+
+ iterator find(const Key &key) {
+ return store.find(key);
+ }
+
+ std::pair<iterator, bool> insert(const std::pair<const Key, Value> &p) {
+ return store.insert(p.first, p);
+ }
+
+ template<class Iter>
+ void insert(Iter it, Iter it_end) {
+ for (; it != it_end; ++it) {
+ insert(*it);
+ }
+ }
+
+ Value &operator[](const Key &key) {
+ auto it = find(key);
+ if (it == end()) {
+ it = insert({key, Value{}}).first;
+ }
+ return it->second;
+ }
+
+ const Value &at(const Key &key) const {
+ return find(key)->second;
+ }
+
+ Value &at(const Key &key) {
+ return find(key)->second;
+ }
+
+ bool empty() const {
+ return store.empty();
+ }
+
+ size_t size() const {
+ return store.size();
+ }
+
+ void clear() {
+ store.clear();
+ }
+
+ void reserve(size_t n) {
+ store.reserve(n);
+ }
+
+ bool operator==(const insertion_ordered_map &a) const {
+ return store == a.store;
+ }
+
+ bool operator<(const insertion_ordered_map &a) const {
+ return store < a.store;
+ }
+
+ void swap(insertion_ordered_map &a) {
+ store.swap(a.store);
+ }
+
+ friend void swap(insertion_ordered_map &a, insertion_ordered_map &b) {
+ a.swap(b);
+ }
+};
+
+template<class Key>
+class insertion_ordered_set
+ : public totally_ordered<insertion_ordered_set<Key>> {
+public:
+ using key_type = Key;
+ using value_type = Key;
+
+private:
+ using store_type = insertion_ordered_detail::element_store<Key, value_type>;
+ store_type store;
+
+public:
+ using const_iterator = typename store_type::const_iterator;
+ using iterator = typename store_type::iterator;
+
+ insertion_ordered_set() = default;
+
+ template<class Iter>
+ insertion_ordered_set(Iter it, Iter it_end) {
+ insert(it, it_end);
+ }
+
+ explicit insertion_ordered_set(std::initializer_list<value_type> init) {
+ insert(init.begin(), init.end());
+ }
+
+ const_iterator begin() const { return store.begin(); }
+ const_iterator end() const { return store.end(); }
+
+ const_iterator find(const Key &key) const {
+ return store.find(key);
+ }
+
+ std::pair<iterator, bool> insert(const Key &key) {
+ return store.insert(key, key);
+ }
+
+ template<class Iter>
+ void insert(Iter it, Iter it_end) {
+ for (; it != it_end; ++it) {
+ insert(*it);
+ }
+ }
+
+ bool empty() const {
+ return store.empty();
+ }
+
+ size_t size() const {
+ return store.size();
+ }
+
+ void clear() {
+ store.clear();
+ }
+
+ void reserve(size_t n) {
+ store.reserve(n);
+ }
+
+ bool operator==(const insertion_ordered_set &a) const {
+ return store == a.store;
+ }
+
+ bool operator<(const insertion_ordered_set &a) const {
+ return store < a.store;
+ }
+
+ void swap(insertion_ordered_set &a) {
+ store.swap(a.store);
+ }
+
+ friend void swap(insertion_ordered_set &a, insertion_ordered_set &b) {
+ a.swap(b);
+ }
+};
+
+} // namespace ue2
+
+#endif // UTIL_INSERTION_ORDERED_H
diff --git a/contrib/libs/hyperscan/src/util/intrinsics.h b/contrib/libs/hyperscan/src/util/intrinsics.h
index 6b3c865addf..edc4f6efb36 100644
--- a/contrib/libs/hyperscan/src/util/intrinsics.h
+++ b/contrib/libs/hyperscan/src/util/intrinsics.h
@@ -1,66 +1,66 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Wrapper around the compiler supplied intrinsic header
- */
-
-#ifndef INTRINSICS_H
-#define INTRINSICS_H
-
-#include "config.h"
-
-#ifdef __cplusplus
-# if defined(HAVE_CXX_X86INTRIN_H)
-# define USE_X86INTRIN_H
-# endif
-#else // C
-# if defined(HAVE_C_X86INTRIN_H)
-# define USE_X86INTRIN_H
-# endif
-#endif
-
-#ifdef __cplusplus
-# if defined(HAVE_CXX_INTRIN_H)
-# define USE_INTRIN_H
-# endif
-#else // C
-# if defined(HAVE_C_INTRIN_H)
-# define USE_INTRIN_H
-# endif
-#endif
-
-#if defined(USE_X86INTRIN_H)
-#include <x86intrin.h>
-#elif defined(USE_INTRIN_H)
-#include <intrin.h>
-#else
-#error no intrinsics file
-#endif
-
-#endif // INTRINSICS_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Wrapper around the compiler supplied intrinsic header
+ */
+
+#ifndef INTRINSICS_H
+#define INTRINSICS_H
+
+#include "config.h"
+
+#ifdef __cplusplus
+# if defined(HAVE_CXX_X86INTRIN_H)
+# define USE_X86INTRIN_H
+# endif
+#else // C
+# if defined(HAVE_C_X86INTRIN_H)
+# define USE_X86INTRIN_H
+# endif
+#endif
+
+#ifdef __cplusplus
+# if defined(HAVE_CXX_INTRIN_H)
+# define USE_INTRIN_H
+# endif
+#else // C
+# if defined(HAVE_C_INTRIN_H)
+# define USE_INTRIN_H
+# endif
+#endif
+
+#if defined(USE_X86INTRIN_H)
+#include <x86intrin.h>
+#elif defined(USE_INTRIN_H)
+#include <intrin.h>
+#else
+#error no intrinsics file
+#endif
+
+#endif // INTRINSICS_H
diff --git a/contrib/libs/hyperscan/src/util/join.h b/contrib/libs/hyperscan/src/util/join.h
index a251c6e0321..7d5a30c39a2 100644
--- a/contrib/libs/hyperscan/src/util/join.h
+++ b/contrib/libs/hyperscan/src/util/join.h
@@ -31,10 +31,10 @@
#define JOIN(x, y) JOIN_AGAIN(x, y)
#define JOIN_AGAIN(x, y) x ## y
-#define JOIN3(x, y, z) JOIN_AGAIN3(x, y, z)
-#define JOIN_AGAIN3(x, y, z) x ## y ## z
-
-#define JOIN4(w, x, y, z) JOIN_AGAIN4(w, x, y, z)
-#define JOIN_AGAIN4(w, x, y, z) w ## x ## y ## z
-
+#define JOIN3(x, y, z) JOIN_AGAIN3(x, y, z)
+#define JOIN_AGAIN3(x, y, z) x ## y ## z
+
+#define JOIN4(w, x, y, z) JOIN_AGAIN4(w, x, y, z)
+#define JOIN_AGAIN4(w, x, y, z) w ## x ## y ## z
+
#endif
diff --git a/contrib/libs/hyperscan/src/util/make_unique.h b/contrib/libs/hyperscan/src/util/make_unique.h
index ba15a9dfbb2..651e8c5cf95 100644
--- a/contrib/libs/hyperscan/src/util/make_unique.h
+++ b/contrib/libs/hyperscan/src/util/make_unique.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -39,9 +39,9 @@
namespace ue2 {
#if defined(USE_STD)
-using std::make_unique;
+using std::make_unique;
#else
-using boost::make_unique;
+using boost::make_unique;
#endif
}
diff --git a/contrib/libs/hyperscan/src/util/masked_move.c b/contrib/libs/hyperscan/src/util/masked_move.c
index fcbd24037ad..001cd49f28f 100644
--- a/contrib/libs/hyperscan/src/util/masked_move.c
+++ b/contrib/libs/hyperscan/src/util/masked_move.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,13 +29,13 @@
#include "ue2common.h"
#include "masked_move.h"
-#include "util/arch.h"
+#include "util/arch.h"
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
/* masks for masked moves */
/* magic mask for maskload (vmmaskmovq) - described in UE-2424 */
-const ALIGN_CL_DIRECTIVE u32 mm_mask_mask[16] = {
+const ALIGN_CL_DIRECTIVE u32 mm_mask_mask[16] = {
0x00000000U,
0x00000000U,
0x00000000U,
diff --git a/contrib/libs/hyperscan/src/util/masked_move.h b/contrib/libs/hyperscan/src/util/masked_move.h
index 9b8a6ebc3e9..4c877ca9e57 100644
--- a/contrib/libs/hyperscan/src/util/masked_move.h
+++ b/contrib/libs/hyperscan/src/util/masked_move.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,21 +29,21 @@
#ifndef MASKED_MOVE_H
#define MASKED_MOVE_H
-#include "arch.h"
+#include "arch.h"
+
+#if defined(HAVE_AVX2)
-#if defined(HAVE_AVX2)
-
#include "unaligned.h"
#include "simd_utils.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
extern const u32 mm_mask_mask[16];
extern const u32 mm_shuffle_end[32][8];
-#ifdef __cplusplus
-}
-#endif
+#ifdef __cplusplus
+}
+#endif
/* load mask for len bytes from start of buffer */
static really_inline m256
@@ -70,8 +70,8 @@ masked_move256_len(const u8 *buf, const u32 len) {
u32 end = unaligned_load_u32(buf + len - 4);
m256 preshufend = _mm256_broadcastq_epi64(_mm_cvtsi32_si128(end));
m256 v = _mm256_maskload_epi32((const int *)buf, lmask);
- m256 shufend = pshufb_m256(preshufend,
- loadu256(&mm_shuffle_end[len - 4]));
+ m256 shufend = pshufb_m256(preshufend,
+ loadu256(&mm_shuffle_end[len - 4]));
m256 target = or256(v, shufend);
return target;
diff --git a/contrib/libs/hyperscan/src/util/math.h b/contrib/libs/hyperscan/src/util/math.h
index 99db81df8c8..e18c5027765 100644
--- a/contrib/libs/hyperscan/src/util/math.h
+++ b/contrib/libs/hyperscan/src/util/math.h
@@ -1,50 +1,50 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UTIL_MATH_H_
-#define UTIL_MATH_H_
-
-#include "arch.h"
-#include "intrinsics.h"
-
-#include <math.h>
-
-static really_inline
-double our_pow(double x, double y) {
-#if defined(HAVE_AVX)
- /*
- * Clear the upper half of AVX registers before calling into the math lib.
- * On some versions of glibc this can save thousands of AVX-to-SSE
- * transitions.
- */
- _mm256_zeroupper();
-#endif
- return pow(x, y);
-}
-
-#endif // UTIL_MATH_H_
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UTIL_MATH_H_
+#define UTIL_MATH_H_
+
+#include "arch.h"
+#include "intrinsics.h"
+
+#include <math.h>
+
+static really_inline
+double our_pow(double x, double y) {
+#if defined(HAVE_AVX)
+ /*
+ * Clear the upper half of AVX registers before calling into the math lib.
+ * On some versions of glibc this can save thousands of AVX-to-SSE
+ * transitions.
+ */
+ _mm256_zeroupper();
+#endif
+ return pow(x, y);
+}
+
+#endif // UTIL_MATH_H_
diff --git a/contrib/libs/hyperscan/src/util/multibit.c b/contrib/libs/hyperscan/src/util/multibit.c
index b3afd24c426..de192d7dd77 100644
--- a/contrib/libs/hyperscan/src/util/multibit.c
+++ b/contrib/libs/hyperscan/src/util/multibit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/contrib/libs/hyperscan/src/util/multibit.h b/contrib/libs/hyperscan/src/util/multibit.h
index ffdbb8ebd04..c3a4ba461ae 100644
--- a/contrib/libs/hyperscan/src/util/multibit.h
+++ b/contrib/libs/hyperscan/src/util/multibit.h
@@ -162,7 +162,7 @@ u32 mmb_popcount(MMB_TYPE val) {
}
#ifndef MMMB_DEBUG
-#define MDEBUG_PRINTF(x, ...) do { } while(0)
+#define MDEBUG_PRINTF(x, ...) do { } while(0)
#else
#define MDEBUG_PRINTF DEBUG_PRINTF
#endif
@@ -665,84 +665,84 @@ char mmbit_any_precise(const u8 *bits, u32 total_bits) {
}
static really_inline
-char mmbit_all_flat(const u8 *bits, u32 total_bits) {
- while (total_bits > MMB_KEY_BITS) {
- if (mmb_load(bits) != MMB_ALL_ONES) {
- return 0;
- }
- bits += sizeof(MMB_TYPE);
- total_bits -= MMB_KEY_BITS;
- }
- while (total_bits > 8) {
- if (*bits != 0xff) {
- return 0;
- }
- bits++;
- total_bits -= 8;
- }
- u8 mask = (u8)mmb_mask_zero_to_nocheck(total_bits);
- return (*bits & mask) == mask;
-}
-
-static really_inline
-char mmbit_all_big(const u8 *bits, u32 total_bits) {
- u32 ks = mmbit_keyshift(total_bits);
-
- u32 level = 0;
- for (;;) {
- // Number of bits we expect to see switched on on this level.
- u32 level_bits;
- if (ks != 0) {
- u32 next_level_width = MMB_KEY_BITS << (ks - MMB_KEY_SHIFT);
- level_bits = ROUNDUP_N(total_bits, next_level_width) >> ks;
- } else {
- level_bits = total_bits;
- }
-
- const u8 *block_ptr = mmbit_get_level_root_const(bits, level);
-
- // All full-size blocks should be all-ones.
- while (level_bits >= MMB_KEY_BITS) {
- MMB_TYPE block = mmb_load(block_ptr);
- if (block != MMB_ALL_ONES) {
- return 0;
- }
- block_ptr += sizeof(MMB_TYPE);
- level_bits -= MMB_KEY_BITS;
- }
-
- // If we have bits remaining, we have a runt block on the end.
- if (level_bits > 0) {
- MMB_TYPE block = mmb_load(block_ptr);
- MMB_TYPE mask = mmb_mask_zero_to_nocheck(level_bits);
- if ((block & mask) != mask) {
- return 0;
- }
- }
-
- if (ks == 0) {
- break;
- }
-
- ks -= MMB_KEY_SHIFT;
- level++;
- }
-
- return 1;
-}
-
-/** \brief True if all keys are on. Guaranteed precise. */
-static really_inline
-char mmbit_all(const u8 *bits, u32 total_bits) {
- MDEBUG_PRINTF("%p total_bits %u\n", bits, total_bits);
-
- if (mmbit_is_flat_model(total_bits)) {
- return mmbit_all_flat(bits, total_bits);
- }
- return mmbit_all_big(bits, total_bits);
-}
-
-static really_inline
+char mmbit_all_flat(const u8 *bits, u32 total_bits) {
+ while (total_bits > MMB_KEY_BITS) {
+ if (mmb_load(bits) != MMB_ALL_ONES) {
+ return 0;
+ }
+ bits += sizeof(MMB_TYPE);
+ total_bits -= MMB_KEY_BITS;
+ }
+ while (total_bits > 8) {
+ if (*bits != 0xff) {
+ return 0;
+ }
+ bits++;
+ total_bits -= 8;
+ }
+ u8 mask = (u8)mmb_mask_zero_to_nocheck(total_bits);
+ return (*bits & mask) == mask;
+}
+
+static really_inline
+char mmbit_all_big(const u8 *bits, u32 total_bits) {
+ u32 ks = mmbit_keyshift(total_bits);
+
+ u32 level = 0;
+ for (;;) {
+ // Number of bits we expect to see switched on on this level.
+ u32 level_bits;
+ if (ks != 0) {
+ u32 next_level_width = MMB_KEY_BITS << (ks - MMB_KEY_SHIFT);
+ level_bits = ROUNDUP_N(total_bits, next_level_width) >> ks;
+ } else {
+ level_bits = total_bits;
+ }
+
+ const u8 *block_ptr = mmbit_get_level_root_const(bits, level);
+
+ // All full-size blocks should be all-ones.
+ while (level_bits >= MMB_KEY_BITS) {
+ MMB_TYPE block = mmb_load(block_ptr);
+ if (block != MMB_ALL_ONES) {
+ return 0;
+ }
+ block_ptr += sizeof(MMB_TYPE);
+ level_bits -= MMB_KEY_BITS;
+ }
+
+ // If we have bits remaining, we have a runt block on the end.
+ if (level_bits > 0) {
+ MMB_TYPE block = mmb_load(block_ptr);
+ MMB_TYPE mask = mmb_mask_zero_to_nocheck(level_bits);
+ if ((block & mask) != mask) {
+ return 0;
+ }
+ }
+
+ if (ks == 0) {
+ break;
+ }
+
+ ks -= MMB_KEY_SHIFT;
+ level++;
+ }
+
+ return 1;
+}
+
+/** \brief True if all keys are on. Guaranteed precise. */
+static really_inline
+char mmbit_all(const u8 *bits, u32 total_bits) {
+ MDEBUG_PRINTF("%p total_bits %u\n", bits, total_bits);
+
+ if (mmbit_is_flat_model(total_bits)) {
+ return mmbit_all_flat(bits, total_bits);
+ }
+ return mmbit_all_big(bits, total_bits);
+}
+
+static really_inline
MMB_TYPE get_flat_masks(u32 base, u32 it_start, u32 it_end) {
if (it_end <= base) {
return 0;
@@ -820,7 +820,7 @@ u32 mmbit_iterate_bounded_big(const u8 *bits, u32 total_bits, u32 it_start, u32
for (;;) {
assert(level <= max_level);
- u64a block_width = MMB_KEY_BITS << ks;
+ u64a block_width = MMB_KEY_BITS << ks;
u64a block_base = key * block_width;
u64a block_min = MAX(it_start, block_base);
u64a block_max = MIN(it_end, block_base + block_width - 1);
diff --git a/contrib/libs/hyperscan/src/util/multibit_build.cpp b/contrib/libs/hyperscan/src/util/multibit_build.cpp
index b1c10f5f671..67bb9ec7022 100644
--- a/contrib/libs/hyperscan/src/util/multibit_build.cpp
+++ b/contrib/libs/hyperscan/src/util/multibit_build.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@
#include "scatter.h"
#include "ue2common.h"
#include "rose/rose_build_scatter.h"
-#include "util/compile_error.h"
+#include "util/compile_error.h"
#include <cassert>
#include <cstring> // for memset
@@ -46,32 +46,32 @@ using namespace std;
namespace ue2 {
-u32 mmbit_size(u32 total_bits) {
- if (total_bits > MMB_MAX_BITS) {
- throw ResourceLimitError();
- }
-
- // Flat model multibit structures are just stored as a bit vector.
- if (total_bits <= MMB_FLAT_MAX_BITS) {
- return ROUNDUP_N(total_bits, 8) / 8;
- }
-
- u64a current_level = 1; // Number of blocks on current level.
- u64a total = 0; // Total number of blocks.
- while (current_level * MMB_KEY_BITS < total_bits) {
- total += current_level;
- current_level <<= MMB_KEY_SHIFT;
- }
-
- // Last level is a one-for-one bit vector. It needs room for total_bits
- // elements, rounded up to the nearest block.
- u64a last_level = ((u64a)total_bits + MMB_KEY_BITS - 1) / MMB_KEY_BITS;
- total += last_level;
-
- assert(total * sizeof(MMB_TYPE) <= UINT32_MAX);
- return (u32)(total * sizeof(MMB_TYPE));
-}
-
+u32 mmbit_size(u32 total_bits) {
+ if (total_bits > MMB_MAX_BITS) {
+ throw ResourceLimitError();
+ }
+
+ // Flat model multibit structures are just stored as a bit vector.
+ if (total_bits <= MMB_FLAT_MAX_BITS) {
+ return ROUNDUP_N(total_bits, 8) / 8;
+ }
+
+ u64a current_level = 1; // Number of blocks on current level.
+ u64a total = 0; // Total number of blocks.
+ while (current_level * MMB_KEY_BITS < total_bits) {
+ total += current_level;
+ current_level <<= MMB_KEY_SHIFT;
+ }
+
+ // Last level is a one-for-one bit vector. It needs room for total_bits
+ // elements, rounded up to the nearest block.
+ u64a last_level = ((u64a)total_bits + MMB_KEY_BITS - 1) / MMB_KEY_BITS;
+ total += last_level;
+
+ assert(total * sizeof(MMB_TYPE) <= UINT32_MAX);
+ return (u32)(total * sizeof(MMB_TYPE));
+}
+
namespace {
struct TreeNode {
MMB_TYPE mask = 0;
@@ -155,12 +155,12 @@ void bfs(vector<mmbit_sparse_iter> &out, const TreeNode &tree) {
/** \brief Construct a sparse iterator over the values in \a bits for a
* multibit of size \a total_bits. */
-vector<mmbit_sparse_iter> mmbBuildSparseIterator(const vector<u32> &bits,
- u32 total_bits) {
- vector<mmbit_sparse_iter> out;
+vector<mmbit_sparse_iter> mmbBuildSparseIterator(const vector<u32> &bits,
+ u32 total_bits) {
+ vector<mmbit_sparse_iter> out;
assert(!bits.empty());
assert(total_bits > 0);
- assert(total_bits <= MMB_MAX_BITS);
+ assert(total_bits <= MMB_MAX_BITS);
DEBUG_PRINTF("building sparse iter for %zu of %u bits\n",
bits.size(), total_bits);
@@ -186,7 +186,7 @@ vector<mmbit_sparse_iter> mmbBuildSparseIterator(const vector<u32> &bits,
#endif
DEBUG_PRINTF("iter has %zu records\n", out.size());
- return out;
+ return out;
}
template<typename T>
@@ -273,7 +273,7 @@ void mmbBuildInitRangePlan(u32 total_bits, u32 begin, u32 end,
}
// Partial block to deal with beginning.
- block_offset += (k1 / MMB_KEY_BITS) * sizeof(MMB_TYPE);
+ block_offset += (k1 / MMB_KEY_BITS) * sizeof(MMB_TYPE);
if (k1 % MMB_KEY_BITS) {
u32 idx = k1 / MMB_KEY_BITS;
u32 block_end = (idx + 1) * MMB_KEY_BITS;
diff --git a/contrib/libs/hyperscan/src/util/multibit_build.h b/contrib/libs/hyperscan/src/util/multibit_build.h
index 72820387fae..24f1bb55b06 100644
--- a/contrib/libs/hyperscan/src/util/multibit_build.h
+++ b/contrib/libs/hyperscan/src/util/multibit_build.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,41 +35,41 @@
#include "hs_common.h"
#include "multibit_internal.h"
-#include "hash.h"
+#include "hash.h"
#include <vector>
-inline
-bool operator==(const mmbit_sparse_iter &a, const mmbit_sparse_iter &b) {
- return a.mask == b.mask && a.val == b.val;
+inline
+bool operator==(const mmbit_sparse_iter &a, const mmbit_sparse_iter &b) {
+ return a.mask == b.mask && a.val == b.val;
}
-namespace std {
-
-template<>
-struct hash<mmbit_sparse_iter> {
- size_t operator()(const mmbit_sparse_iter &iter) const {
- return ue2::hash_all(iter.mask, iter.val);
- }
-};
-
-} // namespace std
-
+namespace std {
+
+template<>
+struct hash<mmbit_sparse_iter> {
+ size_t operator()(const mmbit_sparse_iter &iter) const {
+ return ue2::hash_all(iter.mask, iter.val);
+ }
+};
+
+} // namespace std
+
namespace ue2 {
-/**
- * \brief Return the size in bytes of a multibit that can store the given
- * number of bits.
- *
- * This will throw a resource limit assertion if the requested mmbit is too
- * large.
- */
-u32 mmbit_size(u32 total_bits);
-
+/**
+ * \brief Return the size in bytes of a multibit that can store the given
+ * number of bits.
+ *
+ * This will throw a resource limit assertion if the requested mmbit is too
+ * large.
+ */
+u32 mmbit_size(u32 total_bits);
+
/** \brief Construct a sparse iterator over the values in \a bits for a
* multibit of size \a total_bits. */
-std::vector<mmbit_sparse_iter>
-mmbBuildSparseIterator(const std::vector<u32> &bits, u32 total_bits);
+std::vector<mmbit_sparse_iter>
+mmbBuildSparseIterator(const std::vector<u32> &bits, u32 total_bits);
struct scatter_plan_raw;
diff --git a/contrib/libs/hyperscan/src/util/multibit_compress.h b/contrib/libs/hyperscan/src/util/multibit_compress.h
index 4844788f501..e7b4fd8e861 100644
--- a/contrib/libs/hyperscan/src/util/multibit_compress.h
+++ b/contrib/libs/hyperscan/src/util/multibit_compress.h
@@ -1,204 +1,204 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** file
- * \brief multibit compression API: compress / decompress / size
- */
-
-#ifndef MULTIBIT_COMPRESS_H
-#define MULTIBIT_COMPRESS_H
-
-#include "multibit.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** \brief size API. */
-static really_inline
-size_t mmbit_compsize(const u8 *bits, u32 total_bits) {
- // Deal with flat model.
- if (total_bits <= MMB_FLAT_MAX_BITS) {
- return (ROUNDUP_N(total_bits, 8) / 8);
- }
- // Deal with all cleared mmb.
- if (mmb_load(bits) == 0) {
- return sizeof(MMB_TYPE);
- }
- // Deal with normal pyramid mmb.
- const u32 max_level = mmbit_maxlevel(total_bits);
- u32 level = 0;
- u32 key = 0;
- u32 key_rem = 0;
- u32 num_block = 0;
- // Iteration-version of DFS
- while (1) {
- if (key_rem < MMB_KEY_BITS) {
- const u8 *block_ptr = mmbit_get_level_root_const(bits, level) +
- key * sizeof(MMB_TYPE);
- MMB_TYPE block = mmb_load(block_ptr);
- MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
- if (mmb_popcount(block) == mmb_popcount(block_1)) {
- num_block++;
- }
- if (level < max_level && block_1) {
- key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
- key_rem = 0;
- level++;
- continue;
- }
- }
- if (level-- == 0) {
- return sizeof(MMB_TYPE) * num_block;
- }
- key_rem = (key & MMB_KEY_MASK) + 1;
- key >>= MMB_KEY_SHIFT;
- }
-}
-
-/** \brief compress API. */
-static really_inline
-char mmbit_compress(const u8 *bits, u32 total_bits, u8 *comp,
- size_t *comp_space, size_t max_comp_space) {
- UNUSED u8 *comp_init = comp;
- // Compute comp_size first.
- size_t comp_size = mmbit_compsize(bits, total_bits);
- // Check whether out of writable range.
- if (comp_size > max_comp_space) {
- return 0;
- }
- *comp_space = comp_size; // Return comp_size outside.
- // Deal with flat model.
- if (total_bits <= MMB_FLAT_MAX_BITS) {
- memcpy(comp, bits, comp_size);
- return 1;
- }
- // Deal with all cleared mmb.
- if (mmb_load(bits) == 0) {
- memcpy(comp, bits, sizeof(MMB_TYPE));
- return 1;
- }
- // Deal with normal pyramid mmb.
- const u32 max_level = mmbit_maxlevel(total_bits);
- u32 level = 0;
- u32 key = 0;
- u32 key_rem = 0;
- // Iteration-version of DFS
- while (1) {
- if (key_rem < MMB_KEY_BITS) {
- const u8 *block_ptr = mmbit_get_level_root_const(bits, level) +
- key * sizeof(MMB_TYPE);
- MMB_TYPE block = mmb_load(block_ptr);
- MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
- if (mmb_popcount(block) == mmb_popcount(block_1)) {
- memcpy(comp, &block, sizeof(MMB_TYPE));
- comp += sizeof(MMB_TYPE);
- }
- if (level < max_level && block_1) {
- key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
- key_rem = 0;
- level++;
- continue;
- }
- }
- if (level-- == 0) {
- break;
- }
- key_rem = (key & MMB_KEY_MASK) + 1;
- key >>= MMB_KEY_SHIFT;
- }
- assert((u32)(comp - comp_init) == comp_size);
- return 1;
-}
-
-/** \brief decompress API. */
-static really_inline
-char mmbit_decompress(u8 *bits, u32 total_bits, const u8 *comp,
- size_t *comp_space, size_t max_comp_space) {
- UNUSED const u8 *comp_init = comp;
- size_t comp_size;
- // Deal with flat model.
- if (total_bits <= MMB_FLAT_MAX_BITS) {
- comp_size = ROUNDUP_N(total_bits, 8) / 8;
- memcpy(bits, comp, comp_size);
- *comp_space = comp_size;
- return 1;
- }
- // Deal with all cleared mmb.
- if (mmb_load(comp) == 0) {
- comp_size = sizeof(MMB_TYPE);
- memcpy(bits, comp, comp_size);
- *comp_space = comp_size;
- return 1;
- }
- // Deal with normal mmb.
- u32 max_level = mmbit_maxlevel(total_bits);
- u32 level = 0;
- u32 key = 0;
- u32 key_rem = 0;
- UNUSED const u8 *comp_end = comp_init + max_comp_space;
- // Iteration-version of DFS
- memcpy(bits, comp, sizeof(MMB_TYPE)); // Copy root block first.
- comp += sizeof(MMB_TYPE);
- while (1) {
- if (key_rem < MMB_KEY_BITS) {
- u8 *block_ptr = mmbit_get_level_root(bits, level) +
- key * sizeof(MMB_TYPE);
- MMB_TYPE block = mmb_load(block_ptr);
- MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
- if (level < max_level && block_1) {
- key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
- u8 *block_ptr_1 = mmbit_get_level_root(bits, level + 1) +
- key * sizeof(MMB_TYPE);
- memcpy(block_ptr_1, comp, sizeof(MMB_TYPE));
- comp += sizeof(MMB_TYPE);
- if (comp > comp_end) {
- return 0; // Out of buffer.
- }
- key_rem = 0;
- level++;
- continue;
- }
- }
- if (level-- == 0) {
- break;
- }
- key_rem = (key & MMB_KEY_MASK) + 1;
- key >>= MMB_KEY_SHIFT;
- }
- comp_size = (u32)(comp - comp_init);
- *comp_space = comp_size;
- return 1;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // MULTBIT_COMPRESS_H
-
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** file
+ * \brief multibit compression API: compress / decompress / size
+ */
+
+#ifndef MULTIBIT_COMPRESS_H
+#define MULTIBIT_COMPRESS_H
+
+#include "multibit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \brief size API. */
+static really_inline
+size_t mmbit_compsize(const u8 *bits, u32 total_bits) {
+ // Deal with flat model.
+ if (total_bits <= MMB_FLAT_MAX_BITS) {
+ return (ROUNDUP_N(total_bits, 8) / 8);
+ }
+ // Deal with all cleared mmb.
+ if (mmb_load(bits) == 0) {
+ return sizeof(MMB_TYPE);
+ }
+ // Deal with normal pyramid mmb.
+ const u32 max_level = mmbit_maxlevel(total_bits);
+ u32 level = 0;
+ u32 key = 0;
+ u32 key_rem = 0;
+ u32 num_block = 0;
+ // Iteration-version of DFS
+ while (1) {
+ if (key_rem < MMB_KEY_BITS) {
+ const u8 *block_ptr = mmbit_get_level_root_const(bits, level) +
+ key * sizeof(MMB_TYPE);
+ MMB_TYPE block = mmb_load(block_ptr);
+ MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
+ if (mmb_popcount(block) == mmb_popcount(block_1)) {
+ num_block++;
+ }
+ if (level < max_level && block_1) {
+ key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
+ key_rem = 0;
+ level++;
+ continue;
+ }
+ }
+ if (level-- == 0) {
+ return sizeof(MMB_TYPE) * num_block;
+ }
+ key_rem = (key & MMB_KEY_MASK) + 1;
+ key >>= MMB_KEY_SHIFT;
+ }
+}
+
+/** \brief compress API. */
+static really_inline
+char mmbit_compress(const u8 *bits, u32 total_bits, u8 *comp,
+ size_t *comp_space, size_t max_comp_space) {
+ UNUSED u8 *comp_init = comp;
+ // Compute comp_size first.
+ size_t comp_size = mmbit_compsize(bits, total_bits);
+ // Check whether out of writable range.
+ if (comp_size > max_comp_space) {
+ return 0;
+ }
+ *comp_space = comp_size; // Return comp_size outside.
+ // Deal with flat model.
+ if (total_bits <= MMB_FLAT_MAX_BITS) {
+ memcpy(comp, bits, comp_size);
+ return 1;
+ }
+ // Deal with all cleared mmb.
+ if (mmb_load(bits) == 0) {
+ memcpy(comp, bits, sizeof(MMB_TYPE));
+ return 1;
+ }
+ // Deal with normal pyramid mmb.
+ const u32 max_level = mmbit_maxlevel(total_bits);
+ u32 level = 0;
+ u32 key = 0;
+ u32 key_rem = 0;
+ // Iteration-version of DFS
+ while (1) {
+ if (key_rem < MMB_KEY_BITS) {
+ const u8 *block_ptr = mmbit_get_level_root_const(bits, level) +
+ key * sizeof(MMB_TYPE);
+ MMB_TYPE block = mmb_load(block_ptr);
+ MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
+ if (mmb_popcount(block) == mmb_popcount(block_1)) {
+ memcpy(comp, &block, sizeof(MMB_TYPE));
+ comp += sizeof(MMB_TYPE);
+ }
+ if (level < max_level && block_1) {
+ key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
+ key_rem = 0;
+ level++;
+ continue;
+ }
+ }
+ if (level-- == 0) {
+ break;
+ }
+ key_rem = (key & MMB_KEY_MASK) + 1;
+ key >>= MMB_KEY_SHIFT;
+ }
+ assert((u32)(comp - comp_init) == comp_size);
+ return 1;
+}
+
+/** \brief decompress API. */
+static really_inline
+char mmbit_decompress(u8 *bits, u32 total_bits, const u8 *comp,
+ size_t *comp_space, size_t max_comp_space) {
+ UNUSED const u8 *comp_init = comp;
+ size_t comp_size;
+ // Deal with flat model.
+ if (total_bits <= MMB_FLAT_MAX_BITS) {
+ comp_size = ROUNDUP_N(total_bits, 8) / 8;
+ memcpy(bits, comp, comp_size);
+ *comp_space = comp_size;
+ return 1;
+ }
+ // Deal with all cleared mmb.
+ if (mmb_load(comp) == 0) {
+ comp_size = sizeof(MMB_TYPE);
+ memcpy(bits, comp, comp_size);
+ *comp_space = comp_size;
+ return 1;
+ }
+ // Deal with normal mmb.
+ u32 max_level = mmbit_maxlevel(total_bits);
+ u32 level = 0;
+ u32 key = 0;
+ u32 key_rem = 0;
+ UNUSED const u8 *comp_end = comp_init + max_comp_space;
+ // Iteration-version of DFS
+ memcpy(bits, comp, sizeof(MMB_TYPE)); // Copy root block first.
+ comp += sizeof(MMB_TYPE);
+ while (1) {
+ if (key_rem < MMB_KEY_BITS) {
+ u8 *block_ptr = mmbit_get_level_root(bits, level) +
+ key * sizeof(MMB_TYPE);
+ MMB_TYPE block = mmb_load(block_ptr);
+ MMB_TYPE block_1 = block & ~mmb_mask_zero_to_nocheck(key_rem);
+ if (level < max_level && block_1) {
+ key = (key << MMB_KEY_SHIFT) + mmb_ctz(block_1);
+ u8 *block_ptr_1 = mmbit_get_level_root(bits, level + 1) +
+ key * sizeof(MMB_TYPE);
+ memcpy(block_ptr_1, comp, sizeof(MMB_TYPE));
+ comp += sizeof(MMB_TYPE);
+ if (comp > comp_end) {
+ return 0; // Out of buffer.
+ }
+ key_rem = 0;
+ level++;
+ continue;
+ }
+ }
+ if (level-- == 0) {
+ break;
+ }
+ key_rem = (key & MMB_KEY_MASK) + 1;
+ key >>= MMB_KEY_SHIFT;
+ }
+ comp_size = (u32)(comp - comp_init);
+ *comp_space = comp_size;
+ return 1;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // MULTBIT_COMPRESS_H
+
diff --git a/contrib/libs/hyperscan/src/util/multibit_internal.h b/contrib/libs/hyperscan/src/util/multibit_internal.h
index ebe53f958be..350f3bfd475 100644
--- a/contrib/libs/hyperscan/src/util/multibit_internal.h
+++ b/contrib/libs/hyperscan/src/util/multibit_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -47,9 +47,9 @@ extern "C" {
typedef u64a MMB_TYPE; /**< Basic block type for mmbit operations. */
#define MMB_MAX_LEVEL 6 /**< Maximum level in the mmbit pyramid. */
-/** \brief Maximum number of keys (bits) in a multibit. */
-#define MMB_MAX_BITS (1U << 31)
-
+/** \brief Maximum number of keys (bits) in a multibit. */
+#define MMB_MAX_BITS (1U << 31)
+
/** \brief Sparse iterator record type.
*
* A sparse iterator is a tree of these records, where val identifies the
diff --git a/contrib/libs/hyperscan/src/util/noncopyable.h b/contrib/libs/hyperscan/src/util/noncopyable.h
index 63128ef55ef..cd4f2e0261a 100644
--- a/contrib/libs/hyperscan/src/util/noncopyable.h
+++ b/contrib/libs/hyperscan/src/util/noncopyable.h
@@ -1,50 +1,50 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \file
- * \brief Class that makes derived classes non-copyable.
- */
-
-#ifndef UTIL_NONCOPYABLE_H
-#define UTIL_NONCOPYABLE_H
-
-namespace ue2 {
-
-/** \brief Class that makes derived classes non-copyable. */
-struct noncopyable {
- noncopyable() = default;
- noncopyable(const noncopyable &) = delete;
- noncopyable(noncopyable &&) = default;
- noncopyable &operator=(const noncopyable &) = delete;
- noncopyable &operator=(noncopyable &&) = default;
-};
-
-} // namespace ue2
-
-#endif // UTIL_NONCOPYABLE_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \file
+ * \brief Class that makes derived classes non-copyable.
+ */
+
+#ifndef UTIL_NONCOPYABLE_H
+#define UTIL_NONCOPYABLE_H
+
+namespace ue2 {
+
+/** \brief Class that makes derived classes non-copyable. */
+struct noncopyable {
+ noncopyable() = default;
+ noncopyable(const noncopyable &) = delete;
+ noncopyable(noncopyable &&) = default;
+ noncopyable &operator=(const noncopyable &) = delete;
+ noncopyable &operator=(noncopyable &&) = default;
+};
+
+} // namespace ue2
+
+#endif // UTIL_NONCOPYABLE_H
diff --git a/contrib/libs/hyperscan/src/util/operators.h b/contrib/libs/hyperscan/src/util/operators.h
index 2da8efea8ab..b0a1c1cca28 100644
--- a/contrib/libs/hyperscan/src/util/operators.h
+++ b/contrib/libs/hyperscan/src/util/operators.h
@@ -1,60 +1,60 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/**
- * \brief Ordered operators: provides all the other compare operators for types
- * that provide equal and less-than.
- *
- * This is similar to Boost's totally_ordered class, but much simpler and
- * without injecting the boost namespace into ADL lookup.
- */
-
-#ifndef UTIL_OPERATORS_H
-#define UTIL_OPERATORS_H
-
-namespace ue2 {
-
-/**
- * \brief Ordered operators: provides all the other compare operators for types
- * that provide equal and less-than.
- *
- * Simply inherit from this class with your class name as its template
- * parameter.
- */
-template<typename T>
-class totally_ordered {
-public:
- friend bool operator!=(const T &a, const T &b) { return !(a == b); }
- friend bool operator<=(const T &a, const T &b) { return !(b < a); }
- friend bool operator>(const T &a, const T &b) { return b < a; }
- friend bool operator>=(const T &a, const T &b) { return !(a < b); }
-};
-
-} // namespace
-
-#endif // UTIL_OPERATORS_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * \brief Ordered operators: provides all the other compare operators for types
+ * that provide equal and less-than.
+ *
+ * This is similar to Boost's totally_ordered class, but much simpler and
+ * without injecting the boost namespace into ADL lookup.
+ */
+
+#ifndef UTIL_OPERATORS_H
+#define UTIL_OPERATORS_H
+
+namespace ue2 {
+
+/**
+ * \brief Ordered operators: provides all the other compare operators for types
+ * that provide equal and less-than.
+ *
+ * Simply inherit from this class with your class name as its template
+ * parameter.
+ */
+template<typename T>
+class totally_ordered {
+public:
+ friend bool operator!=(const T &a, const T &b) { return !(a == b); }
+ friend bool operator<=(const T &a, const T &b) { return !(b < a); }
+ friend bool operator>(const T &a, const T &b) { return b < a; }
+ friend bool operator>=(const T &a, const T &b) { return !(a < b); }
+};
+
+} // namespace
+
+#endif // UTIL_OPERATORS_H
diff --git a/contrib/libs/hyperscan/src/util/partitioned_set.h b/contrib/libs/hyperscan/src/util/partitioned_set.h
index 89e4a38ff63..8a4d3dd9e16 100644
--- a/contrib/libs/hyperscan/src/util/partitioned_set.h
+++ b/contrib/libs/hyperscan/src/util/partitioned_set.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,8 +30,8 @@
#define PARTITIONED_SET_H
#include "container.h"
-#include "noncopyable.h"
-#include "flat_containers.h"
+#include "noncopyable.h"
+#include "flat_containers.h"
#include "ue2common.h"
#include <algorithm>
@@ -53,7 +53,7 @@ static constexpr size_t INVALID_SUBSET = ~(size_t)0;
*/
template<typename T>
-class partitioned_set : noncopyable {
+class partitioned_set : noncopyable {
public:
class subset {
public:
@@ -98,7 +98,7 @@ public:
* If the set was not split (due to there being no overlap with splitter or
* being a complete subset), INVALID_SUBSET is returned.
*/
- size_t split(size_t subset_index, const flat_set<T> &splitter) {
+ size_t split(size_t subset_index, const flat_set<T> &splitter) {
assert(!splitter.empty());
if (splitter.empty()) {
return INVALID_SUBSET;
@@ -128,10 +128,10 @@ public:
}
for (auto it = orig.members.begin(); it != orig.members.end(); ++it) {
- const auto &member = *it;
+ const auto &member = *it;
assert(member < member_to_subset.size());
- sp_it = std::lower_bound(sp_it, sp_e, member);
+ sp_it = std::lower_bound(sp_it, sp_e, member);
if (sp_it == sp_e) {
split_temp_diff.insert(split_temp_diff.end(), it,
orig.members.end());
@@ -190,7 +190,7 @@ public:
/**
* Returns all subsets which have a member in keys.
*/
- void find_overlapping(const flat_set<T> &keys,
+ void find_overlapping(const flat_set<T> &keys,
std::vector<size_t> *containing) const {
boost::dynamic_bitset<> seen(subsets.size()); // all zero by default.
diff --git a/contrib/libs/hyperscan/src/util/popcount.h b/contrib/libs/hyperscan/src/util/popcount.h
index 9ef0897c67f..eb08f6b1b20 100644
--- a/contrib/libs/hyperscan/src/util/popcount.h
+++ b/contrib/libs/hyperscan/src/util/popcount.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,19 +30,19 @@
* \brief Platform specific popcount functions
*/
-#ifndef UTIL_POPCOUNT_H_
-#define UTIL_POPCOUNT_H_
+#ifndef UTIL_POPCOUNT_H_
+#define UTIL_POPCOUNT_H_
#include "ue2common.h"
-#include "util/arch.h"
+#include "util/arch.h"
static really_inline
u32 popcount32(u32 x) {
#if defined(HAVE_POPCOUNT_INSTR)
// Single-instruction builtin.
- return _mm_popcnt_u32(x);
+ return _mm_popcnt_u32(x);
#else
- // Fast branch-free version from bit-twiddling hacks as older Intel
+ // Fast branch-free version from bit-twiddling hacks as older Intel
// processors do not have a POPCNT instruction.
x -= (x >> 1) & 0x55555555;
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
@@ -52,23 +52,23 @@ u32 popcount32(u32 x) {
static really_inline
u32 popcount64(u64a x) {
-#if defined(ARCH_X86_64)
-# if defined(HAVE_POPCOUNT_INSTR)
+#if defined(ARCH_X86_64)
+# if defined(HAVE_POPCOUNT_INSTR)
// Single-instruction builtin.
- return (u32)_mm_popcnt_u64(x);
-# else
- // Fast branch-free version from bit-twiddling hacks as older Intel
+ return (u32)_mm_popcnt_u64(x);
+# else
+ // Fast branch-free version from bit-twiddling hacks as older Intel
// processors do not have a POPCNT instruction.
x -= (x >> 1) & 0x5555555555555555;
x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
return (x * 0x0101010101010101) >> 56;
-# endif
+# endif
#else
// Synthesise from two 32-bit cases.
return popcount32(x >> 32) + popcount32(x);
#endif
}
-#endif /* UTIL_POPCOUNT_H_ */
+#endif /* UTIL_POPCOUNT_H_ */
diff --git a/contrib/libs/hyperscan/src/util/queue_index_factory.h b/contrib/libs/hyperscan/src/util/queue_index_factory.h
index a9bc8282893..e8f7028ec5b 100644
--- a/contrib/libs/hyperscan/src/util/queue_index_factory.h
+++ b/contrib/libs/hyperscan/src/util/queue_index_factory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,11 +33,11 @@
#define UTIL_QUEUE_INDEX_FACTORY_H
#include "ue2common.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
namespace ue2 {
-class QueueIndexFactory : noncopyable {
+class QueueIndexFactory : noncopyable {
public:
QueueIndexFactory() : val(0) {}
u32 get_queue() { return val++; }
diff --git a/contrib/libs/hyperscan/src/util/report.h b/contrib/libs/hyperscan/src/util/report.h
index 233f705b039..ee830d0f102 100644
--- a/contrib/libs/hyperscan/src/util/report.h
+++ b/contrib/libs/hyperscan/src/util/report.h
@@ -35,10 +35,10 @@
#define UTIL_REPORT_H
#include "ue2common.h"
-#include "util/exhaust.h" // for INVALID_EKEY
+#include "util/exhaust.h" // for INVALID_EKEY
#include "util/logical.h" // for INVALID_LKEY
-#include "util/hash.h"
-#include "util/order_check.h"
+#include "util/hash.h"
+#include "util/order_check.h"
#include <cassert>
@@ -46,39 +46,39 @@ namespace ue2 {
class ReportManager;
-enum ReportType {
- EXTERNAL_CALLBACK,
- EXTERNAL_CALLBACK_SOM_REL,
- INTERNAL_SOM_LOC_SET,
- INTERNAL_SOM_LOC_SET_IF_UNSET,
- INTERNAL_SOM_LOC_SET_IF_WRITABLE,
- INTERNAL_SOM_LOC_SET_SOM_REV_NFA,
- INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET,
- INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE,
- INTERNAL_SOM_LOC_COPY,
- INTERNAL_SOM_LOC_COPY_IF_WRITABLE,
- INTERNAL_SOM_LOC_MAKE_WRITABLE,
- EXTERNAL_CALLBACK_SOM_STORED,
- EXTERNAL_CALLBACK_SOM_ABS,
- EXTERNAL_CALLBACK_SOM_REV_NFA,
- INTERNAL_SOM_LOC_SET_FROM,
- INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE,
- INTERNAL_ROSE_CHAIN,
- EXTERNAL_CALLBACK_SOM_PASS
-};
-
+enum ReportType {
+ EXTERNAL_CALLBACK,
+ EXTERNAL_CALLBACK_SOM_REL,
+ INTERNAL_SOM_LOC_SET,
+ INTERNAL_SOM_LOC_SET_IF_UNSET,
+ INTERNAL_SOM_LOC_SET_IF_WRITABLE,
+ INTERNAL_SOM_LOC_SET_SOM_REV_NFA,
+ INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET,
+ INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE,
+ INTERNAL_SOM_LOC_COPY,
+ INTERNAL_SOM_LOC_COPY_IF_WRITABLE,
+ INTERNAL_SOM_LOC_MAKE_WRITABLE,
+ EXTERNAL_CALLBACK_SOM_STORED,
+ EXTERNAL_CALLBACK_SOM_ABS,
+ EXTERNAL_CALLBACK_SOM_REV_NFA,
+ INTERNAL_SOM_LOC_SET_FROM,
+ INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE,
+ INTERNAL_ROSE_CHAIN,
+ EXTERNAL_CALLBACK_SOM_PASS
+};
+
/**
* \brief All the data we use for handling a match.
*
* Includes extparam constraints and bounds, exhaustion/dedupe keys, offset
* adjustment and SOM information.
*
- * The data in this structure eventually becomes a list of Rose programs
- * instructions.
+ * The data in this structure eventually becomes a list of Rose programs
+ * instructions.
*/
struct Report {
- Report(ReportType type_in, u32 onmatch_in)
- : type(type_in), onmatch(onmatch_in) {}
+ Report(ReportType type_in, u32 onmatch_in)
+ : type(type_in), onmatch(onmatch_in) {}
/** \brief True if this report has bounds from extended parameters, i.e.
* min offset, max offset, min length. */
@@ -86,8 +86,8 @@ struct Report {
return minOffset > 0 || maxOffset < MAX_OFFSET || minLength > 0;
}
- /** \brief Type of this report. */
- ReportType type;
+ /** \brief Type of this report. */
+ ReportType type;
/** \brief use SOM for minLength, but don't report it to user callback. */
bool quashSom = false;
@@ -177,7 +177,7 @@ bool isExternalReport(const Report &r) {
case EXTERNAL_CALLBACK_SOM_STORED:
case EXTERNAL_CALLBACK_SOM_ABS:
case EXTERNAL_CALLBACK_SOM_REV_NFA:
- case EXTERNAL_CALLBACK_SOM_PASS:
+ case EXTERNAL_CALLBACK_SOM_PASS:
return true;
default:
break; // fall through
@@ -187,11 +187,11 @@ bool isExternalReport(const Report &r) {
}
static inline
-bool isExternalSomReport(const Report &r) {
- return r.type != EXTERNAL_CALLBACK && isExternalReport(r);
-}
-
-static inline
+bool isExternalSomReport(const Report &r) {
+ return r.type != EXTERNAL_CALLBACK && isExternalReport(r);
+}
+
+static inline
bool operator<(const Report &a, const Report &b) {
ORDER_CHECK(type);
ORDER_CHECK(quashSom);
@@ -207,16 +207,16 @@ bool operator<(const Report &a, const Report &b) {
return false;
}
-inline
-bool operator==(const Report &a, const Report &b) {
- return a.type == b.type && a.quashSom == b.quashSom &&
- a.minOffset == b.minOffset && a.maxOffset == b.maxOffset &&
- a.minLength == b.minLength && a.ekey == b.ekey &&
- a.offsetAdjust == b.offsetAdjust && a.onmatch == b.onmatch &&
- a.revNfaIndex == b.revNfaIndex && a.somDistance == b.somDistance &&
- a.topSquashDistance == b.topSquashDistance;
-}
-
+inline
+bool operator==(const Report &a, const Report &b) {
+ return a.type == b.type && a.quashSom == b.quashSom &&
+ a.minOffset == b.minOffset && a.maxOffset == b.maxOffset &&
+ a.minLength == b.minLength && a.ekey == b.ekey &&
+ a.offsetAdjust == b.offsetAdjust && a.onmatch == b.onmatch &&
+ a.revNfaIndex == b.revNfaIndex && a.somDistance == b.somDistance &&
+ a.topSquashDistance == b.topSquashDistance;
+}
+
static inline
Report makeECallback(u32 report, s32 offsetAdjust, u32 ekey, bool quiet) {
Report ir(EXTERNAL_CALLBACK, report);
@@ -241,7 +241,7 @@ Report makeSomRelativeCallback(u32 report, s32 offsetAdjust, u64a distance) {
}
static inline
-Report makeMpvTrigger(u32 event, u64a squashDistance) {
+Report makeMpvTrigger(u32 event, u64a squashDistance) {
Report ir(INTERNAL_ROSE_CHAIN, event);
ir.ekey = INVALID_EKEY;
ir.topSquashDistance = squashDistance;
@@ -267,19 +267,19 @@ bool isSimpleExhaustible(const Report &ir) {
return true;
}
-} // namespace ue2
+} // namespace ue2
-namespace std {
+namespace std {
-template<>
-struct hash<ue2::Report> {
- std::size_t operator()(const ue2::Report &r) const {
- return ue2::hash_all(r.type, r.quashSom, r.minOffset, r.maxOffset,
- r.minLength, r.ekey, r.offsetAdjust, r.onmatch,
- r.revNfaIndex, r.somDistance, r.topSquashDistance);
- }
-};
+template<>
+struct hash<ue2::Report> {
+ std::size_t operator()(const ue2::Report &r) const {
+ return ue2::hash_all(r.type, r.quashSom, r.minOffset, r.maxOffset,
+ r.minLength, r.ekey, r.offsetAdjust, r.onmatch,
+ r.revNfaIndex, r.somDistance, r.topSquashDistance);
+ }
+};
-} // namespace std
+} // namespace std
#endif // UTIL_REPORT_H
diff --git a/contrib/libs/hyperscan/src/util/report_manager.cpp b/contrib/libs/hyperscan/src/util/report_manager.cpp
index c43c731775c..78b9b73dfc7 100644
--- a/contrib/libs/hyperscan/src/util/report_manager.cpp
+++ b/contrib/libs/hyperscan/src/util/report_manager.cpp
@@ -29,12 +29,12 @@
/** \file
* \brief ReportManager: tracks Report structures, exhaustion and dedupe keys.
*/
-
-#include "report_manager.h"
-
+
+#include "report_manager.h"
+
#include "grey.h"
#include "ue2common.h"
-#include "compiler/compiler.h"
+#include "compiler/compiler.h"
#include "nfagraph/ng.h"
#include "rose/rose_build.h"
#include "util/compile_error.h"
@@ -67,7 +67,7 @@ u32 ReportManager::getInternalId(const Report &ir) {
u32 size = reportIds.size();
reportIds.push_back(ir);
- reportIdToInternalMap.emplace(ir, size);
+ reportIdToInternalMap.emplace(ir, size);
DEBUG_PRINTF("new report %u\n", size);
return size;
}
@@ -170,7 +170,7 @@ vector<ReportID> ReportManager::getDkeyToReportTable() const {
void ReportManager::assignDkeys(const RoseBuild *rose) {
DEBUG_PRINTF("assigning...\n");
- map<u32, flat_set<ReportID>> ext_to_int;
+ map<u32, flat_set<ReportID>> ext_to_int;
for (u32 i = 0; i < reportIds.size(); i++) {
const Report &ir = reportIds[i];
@@ -211,9 +211,9 @@ u32 ReportManager::getDkey(const Report &r) const {
void ReportManager::registerExtReport(ReportID id,
const external_report_info &ext) {
- auto it = externalIdMap.find(id);
- if (it != externalIdMap.end()) {
- const external_report_info &eri = it->second;
+ auto it = externalIdMap.find(id);
+ if (it != externalIdMap.end()) {
+ const external_report_info &eri = it->second;
if (eri.highlander != ext.highlander) {
/* we have a problem */
ostringstream out;
@@ -242,35 +242,35 @@ void ReportManager::registerExtReport(ReportID id,
}
}
-Report ReportManager::getBasicInternalReport(const ExpressionInfo &expr,
- s32 adj) {
+Report ReportManager::getBasicInternalReport(const ExpressionInfo &expr,
+ s32 adj) {
/* validate that we are not violating highlander constraints, this will
* throw a CompileError if so. */
- registerExtReport(expr.report,
- external_report_info(expr.highlander, expr.index));
+ registerExtReport(expr.report,
+ external_report_info(expr.highlander, expr.index));
/* create the internal report */
u32 ekey = INVALID_EKEY;
- if (expr.highlander) {
+ if (expr.highlander) {
/* all patterns with the same report id share an ekey */
- ekey = getExhaustibleKey(expr.report);
+ ekey = getExhaustibleKey(expr.report);
}
return makeECallback(expr.report, adj, ekey, expr.quiet);
}
-void ReportManager::setProgramOffset(ReportID id, u32 programOffset) {
- assert(id < reportIds.size());
- assert(!contains(reportIdToProgramOffset, id));
- reportIdToProgramOffset.emplace(id, programOffset);
-}
-
-u32 ReportManager::getProgramOffset(ReportID id) const {
- assert(id < reportIds.size());
- assert(contains(reportIdToProgramOffset, id));
- return reportIdToProgramOffset.at(id);
-}
-
+void ReportManager::setProgramOffset(ReportID id, u32 programOffset) {
+ assert(id < reportIds.size());
+ assert(!contains(reportIdToProgramOffset, id));
+ reportIdToProgramOffset.emplace(id, programOffset);
+}
+
+u32 ReportManager::getProgramOffset(ReportID id) const {
+ assert(id < reportIds.size());
+ assert(contains(reportIdToProgramOffset, id));
+ return reportIdToProgramOffset.at(id);
+}
+
static
void ekeysUnion(std::set<u32> *ekeys, u32 more) {
if (!ekeys->empty()) {
diff --git a/contrib/libs/hyperscan/src/util/report_manager.h b/contrib/libs/hyperscan/src/util/report_manager.h
index 0cbf4ac5d6f..015dc9c855e 100644
--- a/contrib/libs/hyperscan/src/util/report_manager.h
+++ b/contrib/libs/hyperscan/src/util/report_manager.h
@@ -36,20 +36,20 @@
#include "ue2common.h"
#include "util/compile_error.h"
-#include "util/noncopyable.h"
+#include "util/noncopyable.h"
#include "util/report.h"
#include "parser/logical_combination.h"
#include <map>
#include <set>
-#include <unordered_map>
+#include <unordered_map>
#include <vector>
namespace ue2 {
struct Grey;
class RoseBuild;
-class ExpressionInfo;
+class ExpressionInfo;
struct external_report_info {
external_report_info(bool h, u32 fpi)
@@ -59,7 +59,7 @@ struct external_report_info {
};
/** \brief Tracks Report structures, exhaustion and dedupe keys. */
-class ReportManager : noncopyable {
+class ReportManager : noncopyable {
public:
explicit ReportManager(const Grey &g);
@@ -103,13 +103,13 @@ public:
const std::vector<Report> &reports() const { return reportIds; }
/**
- * Get a simple internal report corresponding to the expression. An ekey
- * will be setup if required.
+ * Get a simple internal report corresponding to the expression. An ekey
+ * will be setup if required.
*
* Note: this function may throw a CompileError if constraints on external
* match id are violated (mixed highlander status for example).
*/
- Report getBasicInternalReport(const ExpressionInfo &expr, s32 adj = 0);
+ Report getBasicInternalReport(const ExpressionInfo &expr, s32 adj = 0);
/** \brief Register an external report and validate that we are not
* violating highlander constraints (which will cause an exception to be
@@ -137,14 +137,14 @@ public:
* ~0U if no dkey is needed. */
u32 getDkey(const Report &r) const;
- /** \brief Register a Rose program offset with the given report. */
- void setProgramOffset(ReportID id, u32 programOffset);
-
- /** \brief Fetch the program offset for a given report. It is a fatal error
- * for this to be called with a report for which no program offset has been
- * set. */
- u32 getProgramOffset(ReportID id) const;
-
+ /** \brief Register a Rose program offset with the given report. */
+ void setProgramOffset(ReportID id, u32 programOffset);
+
+ /** \brief Fetch the program offset for a given report. It is a fatal error
+ * for this to be called with a report for which no program offset has been
+ * set. */
+ u32 getProgramOffset(ReportID id) const;
+
/** \brief Parsed logical combination structure. */
ParsedLogical pl;
@@ -156,18 +156,18 @@ private:
std::vector<Report> reportIds;
/** \brief Mapping from Report to ID (inverse of \ref reportIds
- * vector). */
- std::unordered_map<Report, size_t> reportIdToInternalMap;
+ * vector). */
+ std::unordered_map<Report, size_t> reportIdToInternalMap;
/** \brief Mapping from ReportID to dedupe key. */
- std::unordered_map<ReportID, u32> reportIdToDedupeKey;
+ std::unordered_map<ReportID, u32> reportIdToDedupeKey;
+
+ /** \brief Mapping from ReportID to Rose program offset in bytecode. */
+ std::unordered_map<ReportID, u32> reportIdToProgramOffset;
- /** \brief Mapping from ReportID to Rose program offset in bytecode. */
- std::unordered_map<ReportID, u32> reportIdToProgramOffset;
-
/** \brief Mapping from external match ids to information about that
* id. */
- std::unordered_map<ReportID, external_report_info> externalIdMap;
+ std::unordered_map<ReportID, external_report_info> externalIdMap;
/** \brief Mapping from expression index to exhaustion key. */
std::map<s64a, u32> toExhaustibleKeyMap;
diff --git a/contrib/libs/hyperscan/src/util/simd_types.h b/contrib/libs/hyperscan/src/util/simd_types.h
index 4d15b250183..962cad6c974 100644
--- a/contrib/libs/hyperscan/src/util/simd_types.h
+++ b/contrib/libs/hyperscan/src/util/simd_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,28 +30,28 @@
#define SIMD_TYPES_H
#include "config.h"
-#include "util/arch.h"
-#include "util/intrinsics.h"
+#include "util/arch.h"
+#include "util/intrinsics.h"
#include "ue2common.h"
-#if defined(HAVE_SSE2)
-typedef __m128i m128;
+#if defined(HAVE_SSE2)
+typedef __m128i m128;
#else
-typedef struct ALIGN_DIRECTIVE {u64a hi; u64a lo;} m128;
+typedef struct ALIGN_DIRECTIVE {u64a hi; u64a lo;} m128;
#endif
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
typedef __m256i m256;
#else
typedef struct ALIGN_AVX_DIRECTIVE {m128 lo; m128 hi;} m256;
#endif
typedef struct {m128 lo; m128 mid; m128 hi;} m384;
-#if defined(HAVE_AVX512)
-typedef __m512i m512;
-#else
-typedef struct ALIGN_ATTR(64) {m256 lo; m256 hi;} m512;
-#endif
+#if defined(HAVE_AVX512)
+typedef __m512i m512;
+#else
+typedef struct ALIGN_ATTR(64) {m256 lo; m256 hi;} m512;
+#endif
#endif /* SIMD_TYPES_H */
diff --git a/contrib/libs/hyperscan/src/util/simd_utils.c b/contrib/libs/hyperscan/src/util/simd_utils.c
index 0b9371fac7c..25a81412e19 100644
--- a/contrib/libs/hyperscan/src/util/simd_utils.c
+++ b/contrib/libs/hyperscan/src/util/simd_utils.c
@@ -1,62 +1,62 @@
-/*
- * Copyright (c) 2016-2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-/** \file
- * \brief Lookup tables to support SIMD operations.
- */
-
-#include "simd_utils.h"
-
-ALIGN_CL_DIRECTIVE const char vbs_mask_data[] = {
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-};
-
-#define ZEROES_8 0, 0, 0, 0, 0, 0, 0, 0
-#define ZEROES_31 ZEROES_8, ZEROES_8, ZEROES_8, 0, 0, 0, 0, 0, 0, 0
-#define ZEROES_32 ZEROES_8, ZEROES_8, ZEROES_8, ZEROES_8
-
-/** \brief LUT for the mask1bit functions. */
-ALIGN_CL_DIRECTIVE const u8 simd_onebit_masks[] = {
- ZEROES_32, ZEROES_32,
- ZEROES_31, 0x01, ZEROES_32,
- ZEROES_31, 0x02, ZEROES_32,
- ZEROES_31, 0x04, ZEROES_32,
- ZEROES_31, 0x08, ZEROES_32,
- ZEROES_31, 0x10, ZEROES_32,
- ZEROES_31, 0x20, ZEROES_32,
- ZEROES_31, 0x40, ZEROES_32,
- ZEROES_31, 0x80, ZEROES_32,
- ZEROES_32, ZEROES_32,
-};
+/*
+ * Copyright (c) 2016-2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+/** \file
+ * \brief Lookup tables to support SIMD operations.
+ */
+
+#include "simd_utils.h"
+
+ALIGN_CL_DIRECTIVE const char vbs_mask_data[] = {
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+};
+
+#define ZEROES_8 0, 0, 0, 0, 0, 0, 0, 0
+#define ZEROES_31 ZEROES_8, ZEROES_8, ZEROES_8, 0, 0, 0, 0, 0, 0, 0
+#define ZEROES_32 ZEROES_8, ZEROES_8, ZEROES_8, ZEROES_8
+
+/** \brief LUT for the mask1bit functions. */
+ALIGN_CL_DIRECTIVE const u8 simd_onebit_masks[] = {
+ ZEROES_32, ZEROES_32,
+ ZEROES_31, 0x01, ZEROES_32,
+ ZEROES_31, 0x02, ZEROES_32,
+ ZEROES_31, 0x04, ZEROES_32,
+ ZEROES_31, 0x08, ZEROES_32,
+ ZEROES_31, 0x10, ZEROES_32,
+ ZEROES_31, 0x20, ZEROES_32,
+ ZEROES_31, 0x40, ZEROES_32,
+ ZEROES_31, 0x80, ZEROES_32,
+ ZEROES_32, ZEROES_32,
+};
diff --git a/contrib/libs/hyperscan/src/util/simd_utils.h b/contrib/libs/hyperscan/src/util/simd_utils.h
index e21005c50f6..d1f060b0702 100644
--- a/contrib/libs/hyperscan/src/util/simd_utils.h
+++ b/contrib/libs/hyperscan/src/util/simd_utils.h
@@ -33,18 +33,18 @@
#ifndef SIMD_UTILS
#define SIMD_UTILS
-#if !defined(_WIN32) && !defined(__SSSE3__)
-#error SSSE3 instructions must be enabled
+#if !defined(_WIN32) && !defined(__SSSE3__)
+#error SSSE3 instructions must be enabled
#endif
-#include "config.h"
+#include "config.h"
#include "ue2common.h"
#include "simd_types.h"
-#include "unaligned.h"
-#include "util/arch.h"
-#include "util/intrinsics.h"
+#include "unaligned.h"
+#include "util/arch.h"
+#include "util/intrinsics.h"
-#include <string.h> // for memcpy
+#include <string.h> // for memcpy
// Define a common assume_aligned using an appropriate compiler built-in, if
// it's available. Note that we need to handle C or C++ compilation.
@@ -63,21 +63,21 @@
#define assume_aligned(x, y) (x)
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern const char vbs_mask_data[];
-#ifdef __cplusplus
-}
-#endif
-
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern const char vbs_mask_data[];
+#ifdef __cplusplus
+}
+#endif
+
static really_inline m128 ones128(void) {
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
- /* gcc gets this right */
- return _mm_set1_epi8(0xFF);
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+ /* gcc gets this right */
+ return _mm_set1_epi8(0xFF);
#else
- /* trick from Intel's optimization guide to generate all-ones.
- * ICC converts this to the single cmpeq instruction */
+ /* trick from Intel's optimization guide to generate all-ones.
+ * ICC converts this to the single cmpeq instruction */
return _mm_cmpeq_epi8(_mm_setzero_si128(), _mm_setzero_si128());
#endif
}
@@ -114,7 +114,7 @@ static really_inline u32 diffrich128(m128 a, m128 b) {
* returns a 4-bit mask indicating which 64-bit words contain differences.
*/
static really_inline u32 diffrich64_128(m128 a, m128 b) {
-#if defined(HAVE_SSE41)
+#if defined(HAVE_SSE41)
a = _mm_cmpeq_epi64(a, b);
return ~(_mm_movemask_ps(_mm_castsi128_ps(a))) & 0x5;
#else
@@ -123,18 +123,18 @@ static really_inline u32 diffrich64_128(m128 a, m128 b) {
#endif
}
-static really_really_inline
-m128 lshift64_m128(m128 a, unsigned b) {
-#if defined(HAVE__BUILTIN_CONSTANT_P)
- if (__builtin_constant_p(b)) {
- return _mm_slli_epi64(a, b);
- }
-#endif
- m128 x = _mm_cvtsi32_si128(b);
- return _mm_sll_epi64(a, x);
+static really_really_inline
+m128 lshift64_m128(m128 a, unsigned b) {
+#if defined(HAVE__BUILTIN_CONSTANT_P)
+ if (__builtin_constant_p(b)) {
+ return _mm_slli_epi64(a, b);
+ }
+#endif
+ m128 x = _mm_cvtsi32_si128(b);
+ return _mm_sll_epi64(a, x);
}
-#define rshift64_m128(a, b) _mm_srli_epi64((a), (b))
+#define rshift64_m128(a, b) _mm_srli_epi64((a), (b))
#define eq128(a, b) _mm_cmpeq_epi8((a), (b))
#define movemask128(a) ((u32)_mm_movemask_epi8((a)))
@@ -148,10 +148,10 @@ static really_inline m128 set16x8(u8 c) {
return _mm_set1_epi8(c);
}
-static really_inline m128 set4x32(u32 c) {
- return _mm_set1_epi32(c);
-}
-
+static really_inline m128 set4x32(u32 c) {
+ return _mm_set1_epi32(c);
+}
+
static really_inline u32 movd(const m128 in) {
return _mm_cvtsi128_si32(in);
}
@@ -180,33 +180,33 @@ static really_inline u64a movq(const m128 in) {
#endif
}
-/* another form of movq */
-static really_inline
-m128 load_m128_from_u64a(const u64a *p) {
- return _mm_set_epi64x(0LL, *p);
+/* another form of movq */
+static really_inline
+m128 load_m128_from_u64a(const u64a *p) {
+ return _mm_set_epi64x(0LL, *p);
}
-#define rshiftbyte_m128(a, count_immed) _mm_srli_si128(a, count_immed)
-#define lshiftbyte_m128(a, count_immed) _mm_slli_si128(a, count_immed)
+#define rshiftbyte_m128(a, count_immed) _mm_srli_si128(a, count_immed)
+#define lshiftbyte_m128(a, count_immed) _mm_slli_si128(a, count_immed)
-#if defined(HAVE_SSE41)
-#define extract32from128(a, imm) _mm_extract_epi32(a, imm)
-#define extract64from128(a, imm) _mm_extract_epi64(a, imm)
-#else
-#define extract32from128(a, imm) movd(_mm_srli_si128(a, imm << 2))
-#define extract64from128(a, imm) movq(_mm_srli_si128(a, imm << 3))
-#endif
+#if defined(HAVE_SSE41)
+#define extract32from128(a, imm) _mm_extract_epi32(a, imm)
+#define extract64from128(a, imm) _mm_extract_epi64(a, imm)
+#else
+#define extract32from128(a, imm) movd(_mm_srli_si128(a, imm << 2))
+#define extract64from128(a, imm) movq(_mm_srli_si128(a, imm << 3))
+#endif
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
// TODO: this entire file needs restructuring - this carveout is awful
#define extractlow64from256(a) movq(a.lo)
#define extractlow32from256(a) movd(a.lo)
-#if defined(HAVE_SSE41)
+#if defined(HAVE_SSE41)
#define extract32from256(a, imm) _mm_extract_epi32((imm >> 2) ? a.hi : a.lo, imm % 4)
-#define extract64from256(a, imm) _mm_extract_epi64((imm >> 1) ? a.hi : a.lo, imm % 2)
+#define extract64from256(a, imm) _mm_extract_epi64((imm >> 1) ? a.hi : a.lo, imm % 2)
#else
-#define extract32from256(a, imm) movd(_mm_srli_si128((imm >> 2) ? a.hi : a.lo, (imm % 4) * 4))
-#define extract64from256(a, imm) movq(_mm_srli_si128((imm >> 1) ? a.hi : a.lo, (imm % 2) * 8))
+#define extract32from256(a, imm) movd(_mm_srli_si128((imm >> 2) ? a.hi : a.lo, (imm % 4) * 4))
+#define extract64from256(a, imm) movq(_mm_srli_si128((imm >> 1) ? a.hi : a.lo, (imm % 2) * 8))
#endif
#endif // !AVX2
@@ -285,139 +285,139 @@ m128 loadbytes128(const void *ptr, unsigned int n) {
return a;
}
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern const u8 simd_onebit_masks[];
-#ifdef __cplusplus
-}
-#endif
-
-static really_inline
-m128 mask1bit128(unsigned int n) {
- assert(n < sizeof(m128) * 8);
- u32 mask_idx = ((n % 8) * 64) + 95;
- mask_idx -= n / 8;
- return loadu128(&simd_onebit_masks[mask_idx]);
-}
-
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern const u8 simd_onebit_masks[];
+#ifdef __cplusplus
+}
+#endif
+
+static really_inline
+m128 mask1bit128(unsigned int n) {
+ assert(n < sizeof(m128) * 8);
+ u32 mask_idx = ((n % 8) * 64) + 95;
+ mask_idx -= n / 8;
+ return loadu128(&simd_onebit_masks[mask_idx]);
+}
+
// switches on bit N in the given vector.
static really_inline
void setbit128(m128 *ptr, unsigned int n) {
- *ptr = or128(mask1bit128(n), *ptr);
+ *ptr = or128(mask1bit128(n), *ptr);
}
// switches off bit N in the given vector.
static really_inline
void clearbit128(m128 *ptr, unsigned int n) {
- *ptr = andnot128(mask1bit128(n), *ptr);
-}
-
-// tests bit N in the given vector.
-static really_inline
-char testbit128(m128 val, unsigned int n) {
- const m128 mask = mask1bit128(n);
-#if defined(HAVE_SSE41)
- return !_mm_testz_si128(mask, val);
-#else
- return isnonzero128(and128(mask, val));
-#endif
-}
-
-// offset must be an immediate
-#define palignr(r, l, offset) _mm_alignr_epi8(r, l, offset)
-
-static really_inline
-m128 pshufb_m128(m128 a, m128 b) {
- m128 result;
- result = _mm_shuffle_epi8(a, b);
- return result;
-}
-
-static really_inline
-m256 pshufb_m256(m256 a, m256 b) {
-#if defined(HAVE_AVX2)
- return _mm256_shuffle_epi8(a, b);
-#else
- m256 rv;
- rv.lo = pshufb_m128(a.lo, b.lo);
- rv.hi = pshufb_m128(a.hi, b.hi);
- return rv;
-#endif
-}
-
-#if defined(HAVE_AVX512)
-static really_inline
-m512 pshufb_m512(m512 a, m512 b) {
- return _mm512_shuffle_epi8(a, b);
-}
-
-static really_inline
-m512 maskz_pshufb_m512(__mmask64 k, m512 a, m512 b) {
- return _mm512_maskz_shuffle_epi8(k, a, b);
-}
+ *ptr = andnot128(mask1bit128(n), *ptr);
+}
+
+// tests bit N in the given vector.
+static really_inline
+char testbit128(m128 val, unsigned int n) {
+ const m128 mask = mask1bit128(n);
+#if defined(HAVE_SSE41)
+ return !_mm_testz_si128(mask, val);
+#else
+ return isnonzero128(and128(mask, val));
+#endif
+}
+
+// offset must be an immediate
+#define palignr(r, l, offset) _mm_alignr_epi8(r, l, offset)
+
+static really_inline
+m128 pshufb_m128(m128 a, m128 b) {
+ m128 result;
+ result = _mm_shuffle_epi8(a, b);
+ return result;
+}
+
+static really_inline
+m256 pshufb_m256(m256 a, m256 b) {
+#if defined(HAVE_AVX2)
+ return _mm256_shuffle_epi8(a, b);
+#else
+ m256 rv;
+ rv.lo = pshufb_m128(a.lo, b.lo);
+ rv.hi = pshufb_m128(a.hi, b.hi);
+ return rv;
+#endif
+}
+
+#if defined(HAVE_AVX512)
+static really_inline
+m512 pshufb_m512(m512 a, m512 b) {
+ return _mm512_shuffle_epi8(a, b);
+}
+
+static really_inline
+m512 maskz_pshufb_m512(__mmask64 k, m512 a, m512 b) {
+ return _mm512_maskz_shuffle_epi8(k, a, b);
+}
#if defined(HAVE_AVX512VBMI)
#define vpermb512(idx, a) _mm512_permutexvar_epi8(idx, a)
#define maskz_vpermb512(k, idx, a) _mm512_maskz_permutexvar_epi8(k, idx, a)
-#endif
-
-#endif
-
-static really_inline
-m128 variable_byte_shift_m128(m128 in, s32 amount) {
- assert(amount >= -16 && amount <= 16);
- m128 shift_mask = loadu128(vbs_mask_data + 16 - amount);
- return pshufb_m128(in, shift_mask);
-}
-
-static really_inline
-m128 max_u8_m128(m128 a, m128 b) {
- return _mm_max_epu8(a, b);
-}
-
-static really_inline
-m128 min_u8_m128(m128 a, m128 b) {
- return _mm_min_epu8(a, b);
-}
-
-static really_inline
-m128 sadd_u8_m128(m128 a, m128 b) {
- return _mm_adds_epu8(a, b);
-}
-
-static really_inline
-m128 sub_u8_m128(m128 a, m128 b) {
- return _mm_sub_epi8(a, b);
-}
-
-static really_inline
-m128 set64x2(u64a hi, u64a lo) {
- return _mm_set_epi64x(hi, lo);
-}
-
+#endif
+
+#endif
+
+static really_inline
+m128 variable_byte_shift_m128(m128 in, s32 amount) {
+ assert(amount >= -16 && amount <= 16);
+ m128 shift_mask = loadu128(vbs_mask_data + 16 - amount);
+ return pshufb_m128(in, shift_mask);
+}
+
+static really_inline
+m128 max_u8_m128(m128 a, m128 b) {
+ return _mm_max_epu8(a, b);
+}
+
+static really_inline
+m128 min_u8_m128(m128 a, m128 b) {
+ return _mm_min_epu8(a, b);
+}
+
+static really_inline
+m128 sadd_u8_m128(m128 a, m128 b) {
+ return _mm_adds_epu8(a, b);
+}
+
+static really_inline
+m128 sub_u8_m128(m128 a, m128 b) {
+ return _mm_sub_epi8(a, b);
+}
+
+static really_inline
+m128 set64x2(u64a hi, u64a lo) {
+ return _mm_set_epi64x(hi, lo);
+}
+
/****
**** 256-bit Primitives
****/
-#if defined(HAVE_AVX2)
-
-static really_really_inline
-m256 lshift64_m256(m256 a, unsigned b) {
-#if defined(HAVE__BUILTIN_CONSTANT_P)
- if (__builtin_constant_p(b)) {
- return _mm256_slli_epi64(a, b);
- }
-#endif
- m128 x = _mm_cvtsi32_si128(b);
- return _mm256_sll_epi64(a, x);
-}
-
-#define rshift64_m256(a, b) _mm256_srli_epi64((a), (b))
-
+#if defined(HAVE_AVX2)
+
+static really_really_inline
+m256 lshift64_m256(m256 a, unsigned b) {
+#if defined(HAVE__BUILTIN_CONSTANT_P)
+ if (__builtin_constant_p(b)) {
+ return _mm256_slli_epi64(a, b);
+ }
+#endif
+ m128 x = _mm_cvtsi32_si128(b);
+ return _mm256_sll_epi64(a, x);
+}
+
+#define rshift64_m256(a, b) _mm256_srli_epi64((a), (b))
+
static really_inline
m256 set32x8(u32 in) {
- return _mm256_set1_epi8(in);
+ return _mm256_set1_epi8(in);
}
#define eq256(a, b) _mm256_cmpeq_epi8((a), (b))
@@ -430,19 +430,19 @@ m256 set2x128(m128 a) {
#else
-static really_really_inline
-m256 lshift64_m256(m256 a, int b) {
+static really_really_inline
+m256 lshift64_m256(m256 a, int b) {
m256 rv = a;
- rv.lo = lshift64_m128(rv.lo, b);
- rv.hi = lshift64_m128(rv.hi, b);
+ rv.lo = lshift64_m128(rv.lo, b);
+ rv.hi = lshift64_m128(rv.hi, b);
return rv;
}
static really_inline
-m256 rshift64_m256(m256 a, int b) {
+m256 rshift64_m256(m256 a, int b) {
m256 rv = a;
- rv.lo = rshift64_m128(rv.lo, b);
- rv.hi = rshift64_m128(rv.hi, b);
+ rv.lo = rshift64_m128(rv.lo, b);
+ rv.hi = rshift64_m128(rv.hi, b);
return rv;
}
static really_inline
@@ -453,30 +453,30 @@ m256 set32x8(u32 in) {
return rv;
}
-static really_inline
-m256 eq256(m256 a, m256 b) {
- m256 rv;
- rv.lo = eq128(a.lo, b.lo);
- rv.hi = eq128(a.hi, b.hi);
- return rv;
-}
-
-static really_inline
-u32 movemask256(m256 a) {
- u32 lo_mask = movemask128(a.lo);
- u32 hi_mask = movemask128(a.hi);
- return lo_mask | (hi_mask << 16);
-}
-
-static really_inline
-m256 set2x128(m128 a) {
- m256 rv = {a, a};
- return rv;
-}
+static really_inline
+m256 eq256(m256 a, m256 b) {
+ m256 rv;
+ rv.lo = eq128(a.lo, b.lo);
+ rv.hi = eq128(a.hi, b.hi);
+ return rv;
+}
+
+static really_inline
+u32 movemask256(m256 a) {
+ u32 lo_mask = movemask128(a.lo);
+ u32 hi_mask = movemask128(a.hi);
+ return lo_mask | (hi_mask << 16);
+}
+
+static really_inline
+m256 set2x128(m128 a) {
+ m256 rv = {a, a};
+ return rv;
+}
#endif
static really_inline m256 zeroes256(void) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return _mm256_setzero_si256();
#else
m256 rv = {zeroes128(), zeroes128()};
@@ -485,15 +485,15 @@ static really_inline m256 zeroes256(void) {
}
static really_inline m256 ones256(void) {
-#if defined(HAVE_AVX2)
- m256 rv = _mm256_set1_epi8(0xFF);
+#if defined(HAVE_AVX2)
+ m256 rv = _mm256_set1_epi8(0xFF);
#else
m256 rv = {ones128(), ones128()};
#endif
return rv;
}
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
static really_inline m256 and256(m256 a, m256 b) {
return _mm256_and_si256(a, b);
}
@@ -506,7 +506,7 @@ static really_inline m256 and256(m256 a, m256 b) {
}
#endif
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
static really_inline m256 or256(m256 a, m256 b) {
return _mm256_or_si256(a, b);
}
@@ -519,7 +519,7 @@ static really_inline m256 or256(m256 a, m256 b) {
}
#endif
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
static really_inline m256 xor256(m256 a, m256 b) {
return _mm256_xor_si256(a, b);
}
@@ -532,7 +532,7 @@ static really_inline m256 xor256(m256 a, m256 b) {
}
#endif
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
static really_inline m256 not256(m256 a) {
return _mm256_xor_si256(a, ones256());
}
@@ -545,7 +545,7 @@ static really_inline m256 not256(m256 a) {
}
#endif
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
static really_inline m256 andnot256(m256 a, m256 b) {
return _mm256_andnot_si256(a, b);
}
@@ -559,7 +559,7 @@ static really_inline m256 andnot256(m256 a, m256 b) {
#endif
static really_inline int diff256(m256 a, m256 b) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return !!(_mm256_movemask_epi8(_mm256_cmpeq_epi8(a, b)) ^ (int)-1);
#else
return diff128(a.lo, b.lo) || diff128(a.hi, b.hi);
@@ -567,7 +567,7 @@ static really_inline int diff256(m256 a, m256 b) {
}
static really_inline int isnonzero256(m256 a) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return !!diff256(a, zeroes256());
#else
return isnonzero128(or128(a.lo, a.hi));
@@ -579,7 +579,7 @@ static really_inline int isnonzero256(m256 a) {
* mask indicating which 32-bit words contain differences.
*/
static really_inline u32 diffrich256(m256 a, m256 b) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
a = _mm256_cmpeq_epi32(a, b);
return ~(_mm256_movemask_ps(_mm256_castsi256_ps(a))) & 0xFF;
#else
@@ -603,7 +603,7 @@ static really_inline u32 diffrich64_256(m256 a, m256 b) {
// aligned load
static really_inline m256 load256(const void *ptr) {
assert(ISALIGNED_N(ptr, alignof(m256)));
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return _mm256_load_si256((const m256 *)ptr);
#else
m256 rv = { load128(ptr), load128((const char *)ptr + 16) };
@@ -613,7 +613,7 @@ static really_inline m256 load256(const void *ptr) {
// aligned load of 128-bit value to low and high part of 256-bit value
static really_inline m256 load2x128(const void *ptr) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return set2x128(load128(ptr));
#else
assert(ISALIGNED_N(ptr, alignof(m128)));
@@ -623,14 +623,14 @@ static really_inline m256 load2x128(const void *ptr) {
#endif
}
-static really_inline m256 loadu2x128(const void *ptr) {
- return set2x128(loadu128(ptr));
-}
-
+static really_inline m256 loadu2x128(const void *ptr) {
+ return set2x128(loadu128(ptr));
+}
+
// aligned store
static really_inline void store256(void *ptr, m256 a) {
assert(ISALIGNED_N(ptr, alignof(m256)));
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
_mm256_store_si256((m256 *)ptr, a);
#else
ptr = assume_aligned(ptr, 16);
@@ -640,7 +640,7 @@ static really_inline void store256(void *ptr, m256 a) {
// unaligned load
static really_inline m256 loadu256(const void *ptr) {
-#if defined(HAVE_AVX2)
+#if defined(HAVE_AVX2)
return _mm256_loadu_si256((const m256 *)ptr);
#else
m256 rv = { loadu128(ptr), loadu128((const char *)ptr + 16) };
@@ -648,13 +648,13 @@ static really_inline m256 loadu256(const void *ptr) {
#endif
}
-// unaligned store
-static really_inline void storeu256(void *ptr, m256 a) {
-#if defined(HAVE_AVX2)
- _mm256_storeu_si256((m256 *)ptr, a);
+// unaligned store
+static really_inline void storeu256(void *ptr, m256 a) {
+#if defined(HAVE_AVX2)
+ _mm256_storeu_si256((m256 *)ptr, a);
#else
- storeu128(ptr, a.lo);
- storeu128((char *)ptr + 16, a.hi);
+ storeu128(ptr, a.lo);
+ storeu128((char *)ptr + 16, a.hi);
#endif
}
@@ -674,27 +674,27 @@ m256 loadbytes256(const void *ptr, unsigned int n) {
return a;
}
-static really_inline
-m256 mask1bit256(unsigned int n) {
- assert(n < sizeof(m256) * 8);
- u32 mask_idx = ((n % 8) * 64) + 95;
- mask_idx -= n / 8;
- return loadu256(&simd_onebit_masks[mask_idx]);
-}
-
-static really_inline
-m256 set64x4(u64a hi_1, u64a hi_0, u64a lo_1, u64a lo_0) {
-#if defined(HAVE_AVX2)
- return _mm256_set_epi64x(hi_1, hi_0, lo_1, lo_0);
-#else
- m256 rv;
- rv.hi = set64x2(hi_1, hi_0);
- rv.lo = set64x2(lo_1, lo_0);
- return rv;
-#endif
-}
-
-#if !defined(HAVE_AVX2)
+static really_inline
+m256 mask1bit256(unsigned int n) {
+ assert(n < sizeof(m256) * 8);
+ u32 mask_idx = ((n % 8) * 64) + 95;
+ mask_idx -= n / 8;
+ return loadu256(&simd_onebit_masks[mask_idx]);
+}
+
+static really_inline
+m256 set64x4(u64a hi_1, u64a hi_0, u64a lo_1, u64a lo_0) {
+#if defined(HAVE_AVX2)
+ return _mm256_set_epi64x(hi_1, hi_0, lo_1, lo_0);
+#else
+ m256 rv;
+ rv.hi = set64x2(hi_1, hi_0);
+ rv.lo = set64x2(lo_1, lo_0);
+ return rv;
+#endif
+}
+
+#if !defined(HAVE_AVX2)
// switches on bit N in the given vector.
static really_inline
void setbit256(m256 *ptr, unsigned int n) {
@@ -725,52 +725,52 @@ void clearbit256(m256 *ptr, unsigned int n) {
// tests bit N in the given vector.
static really_inline
-char testbit256(m256 val, unsigned int n) {
- assert(n < sizeof(val) * 8);
- m128 sub;
+char testbit256(m256 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
+ m128 sub;
if (n < 128) {
- sub = val.lo;
+ sub = val.lo;
} else {
- sub = val.hi;
+ sub = val.hi;
n -= 128;
}
return testbit128(sub, n);
}
-static really_really_inline
-m128 movdq_hi(m256 x) {
- return x.hi;
-}
-
-static really_really_inline
-m128 movdq_lo(m256 x) {
- return x.lo;
-}
-
-static really_inline
-m256 combine2x128(m128 hi, m128 lo) {
- m256 rv = {lo, hi};
- return rv;
-}
-
+static really_really_inline
+m128 movdq_hi(m256 x) {
+ return x.hi;
+}
+
+static really_really_inline
+m128 movdq_lo(m256 x) {
+ return x.lo;
+}
+
+static really_inline
+m256 combine2x128(m128 hi, m128 lo) {
+ m256 rv = {lo, hi};
+ return rv;
+}
+
#else // AVX2
// switches on bit N in the given vector.
static really_inline
void setbit256(m256 *ptr, unsigned int n) {
- *ptr = or256(mask1bit256(n), *ptr);
+ *ptr = or256(mask1bit256(n), *ptr);
}
static really_inline
void clearbit256(m256 *ptr, unsigned int n) {
- *ptr = andnot256(mask1bit256(n), *ptr);
+ *ptr = andnot256(mask1bit256(n), *ptr);
}
// tests bit N in the given vector.
static really_inline
-char testbit256(m256 val, unsigned int n) {
- const m256 mask = mask1bit256(n);
- return !_mm256_testz_si256(mask, val);
+char testbit256(m256 val, unsigned int n) {
+ const m256 mask = mask1bit256(n);
+ return !_mm256_testz_si256(mask, val);
}
static really_really_inline
@@ -787,35 +787,35 @@ m128 movdq_lo(m256 x) {
#define cast128to256(a) _mm256_castsi128_si256(a)
#define swap128in256(a) _mm256_permute4x64_epi64(a, 0x4E)
#define insert128to256(a, b, imm) _mm256_inserti128_si256(a, b, imm)
-#define rshift128_m256(a, count_immed) _mm256_srli_si256(a, count_immed)
-#define lshift128_m256(a, count_immed) _mm256_slli_si256(a, count_immed)
+#define rshift128_m256(a, count_immed) _mm256_srli_si256(a, count_immed)
+#define lshift128_m256(a, count_immed) _mm256_slli_si256(a, count_immed)
#define extract64from256(a, imm) _mm_extract_epi64(_mm256_extracti128_si256(a, imm >> 1), imm % 2)
#define extract32from256(a, imm) _mm_extract_epi32(_mm256_extracti128_si256(a, imm >> 2), imm % 4)
#define extractlow64from256(a) _mm_cvtsi128_si64(cast256to128(a))
#define extractlow32from256(a) movd(cast256to128(a))
-#define interleave256hi(a, b) _mm256_unpackhi_epi8(a, b)
-#define interleave256lo(a, b) _mm256_unpacklo_epi8(a, b)
-#define vpalignr(r, l, offset) _mm256_alignr_epi8(r, l, offset)
-
-static really_inline
-m256 combine2x128(m128 hi, m128 lo) {
-#if defined(_mm256_set_m128i)
- return _mm256_set_m128i(hi, lo);
-#else
- return insert128to256(cast128to256(lo), hi, 1);
-#endif
-}
+#define interleave256hi(a, b) _mm256_unpackhi_epi8(a, b)
+#define interleave256lo(a, b) _mm256_unpacklo_epi8(a, b)
+#define vpalignr(r, l, offset) _mm256_alignr_epi8(r, l, offset)
+
+static really_inline
+m256 combine2x128(m128 hi, m128 lo) {
+#if defined(_mm256_set_m128i)
+ return _mm256_set_m128i(hi, lo);
+#else
+ return insert128to256(cast128to256(lo), hi, 1);
+#endif
+}
#endif //AVX2
-#if defined(HAVE_AVX512)
-#define extract128from512(a, imm) _mm512_extracti32x4_epi32(a, imm)
-#define interleave512hi(a, b) _mm512_unpackhi_epi8(a, b)
-#define interleave512lo(a, b) _mm512_unpacklo_epi8(a, b)
-#define set2x256(a) _mm512_broadcast_i64x4(a)
-#define mask_set2x256(src, k, a) _mm512_mask_broadcast_i64x4(src, k, a)
-#define vpermq512(idx, a) _mm512_permutexvar_epi64(idx, a)
-#endif
-
+#if defined(HAVE_AVX512)
+#define extract128from512(a, imm) _mm512_extracti32x4_epi32(a, imm)
+#define interleave512hi(a, b) _mm512_unpackhi_epi8(a, b)
+#define interleave512lo(a, b) _mm512_unpacklo_epi8(a, b)
+#define set2x256(a) _mm512_broadcast_i64x4(a)
+#define mask_set2x256(src, k, a) _mm512_mask_broadcast_i64x4(src, k, a)
+#define vpermq512(idx, a) _mm512_permutexvar_epi64(idx, a)
+#endif
+
/****
**** 384-bit Primitives
****/
@@ -858,12 +858,12 @@ static really_inline m384 andnot384(m384 a, m384 b) {
return rv;
}
-static really_really_inline
-m384 lshift64_m384(m384 a, unsigned b) {
+static really_really_inline
+m384 lshift64_m384(m384 a, unsigned b) {
m384 rv;
- rv.lo = lshift64_m128(a.lo, b);
- rv.mid = lshift64_m128(a.mid, b);
- rv.hi = lshift64_m128(a.hi, b);
+ rv.lo = lshift64_m128(a.lo, b);
+ rv.mid = lshift64_m128(a.mid, b);
+ rv.hi = lshift64_m128(a.hi, b);
return rv;
}
@@ -978,15 +978,15 @@ void clearbit384(m384 *ptr, unsigned int n) {
// tests bit N in the given vector.
static really_inline
-char testbit384(m384 val, unsigned int n) {
- assert(n < sizeof(val) * 8);
- m128 sub;
+char testbit384(m384 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
+ m128 sub;
if (n < 128) {
- sub = val.lo;
+ sub = val.lo;
} else if (n < 256) {
- sub = val.mid;
+ sub = val.mid;
} else {
- sub = val.hi;
+ sub = val.hi;
}
return testbit128(sub, n % 128);
}
@@ -995,63 +995,63 @@ char testbit384(m384 val, unsigned int n) {
**** 512-bit Primitives
****/
-#define eq512mask(a, b) _mm512_cmpeq_epi8_mask((a), (b))
-#define masked_eq512mask(k, a, b) _mm512_mask_cmpeq_epi8_mask((k), (a), (b))
-
-static really_inline
-m512 zeroes512(void) {
-#if defined(HAVE_AVX512)
- return _mm512_setzero_si512();
+#define eq512mask(a, b) _mm512_cmpeq_epi8_mask((a), (b))
+#define masked_eq512mask(k, a, b) _mm512_mask_cmpeq_epi8_mask((k), (a), (b))
+
+static really_inline
+m512 zeroes512(void) {
+#if defined(HAVE_AVX512)
+ return _mm512_setzero_si512();
+#else
+ m512 rv = {zeroes256(), zeroes256()};
+ return rv;
+#endif
+}
+
+static really_inline
+m512 ones512(void) {
+#if defined(HAVE_AVX512)
+ return _mm512_set1_epi8(0xFF);
+ //return _mm512_xor_si512(_mm512_setzero_si512(), _mm512_setzero_si512());
#else
- m512 rv = {zeroes256(), zeroes256()};
- return rv;
-#endif
-}
-
-static really_inline
-m512 ones512(void) {
-#if defined(HAVE_AVX512)
- return _mm512_set1_epi8(0xFF);
- //return _mm512_xor_si512(_mm512_setzero_si512(), _mm512_setzero_si512());
-#else
- m512 rv = {ones256(), ones256()};
- return rv;
-#endif
-}
-
-#if defined(HAVE_AVX512)
-static really_inline
-m512 set64x8(u8 a) {
- return _mm512_set1_epi8(a);
-}
-
-static really_inline
-m512 set8x64(u64a a) {
- return _mm512_set1_epi64(a);
-}
-
-static really_inline
+ m512 rv = {ones256(), ones256()};
+ return rv;
+#endif
+}
+
+#if defined(HAVE_AVX512)
+static really_inline
+m512 set64x8(u8 a) {
+ return _mm512_set1_epi8(a);
+}
+
+static really_inline
+m512 set8x64(u64a a) {
+ return _mm512_set1_epi64(a);
+}
+
+static really_inline
m512 set16x32(u32 a) {
return _mm512_set1_epi32(a);
}
static really_inline
-m512 set512_64(u64a hi_3, u64a hi_2, u64a hi_1, u64a hi_0,
- u64a lo_3, u64a lo_2, u64a lo_1, u64a lo_0) {
- return _mm512_set_epi64(hi_3, hi_2, hi_1, hi_0,
- lo_3, lo_2, lo_1, lo_0);
-}
-
-static really_inline
-m512 swap256in512(m512 a) {
- m512 idx = set512_64(3ULL, 2ULL, 1ULL, 0ULL, 7ULL, 6ULL, 5ULL, 4ULL);
- return vpermq512(idx, a);
-}
-
-static really_inline
-m512 set4x128(m128 a) {
- return _mm512_broadcast_i32x4(a);
-}
+m512 set512_64(u64a hi_3, u64a hi_2, u64a hi_1, u64a hi_0,
+ u64a lo_3, u64a lo_2, u64a lo_1, u64a lo_0) {
+ return _mm512_set_epi64(hi_3, hi_2, hi_1, hi_0,
+ lo_3, lo_2, lo_1, lo_0);
+}
+
+static really_inline
+m512 swap256in512(m512 a) {
+ m512 idx = set512_64(3ULL, 2ULL, 1ULL, 0ULL, 7ULL, 6ULL, 5ULL, 4ULL);
+ return vpermq512(idx, a);
+}
+
+static really_inline
+m512 set4x128(m128 a) {
+ return _mm512_broadcast_i32x4(a);
+}
static really_inline
m512 sadd_u8_m512(m512 a, m512 b) {
@@ -1072,116 +1072,116 @@ static really_inline
m512 sub_u8_m512(m512 a, m512 b) {
return _mm512_sub_epi8(a, b);
}
-#endif
-
-static really_inline
-m512 and512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return _mm512_and_si512(a, b);
-#else
+#endif
+
+static really_inline
+m512 and512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return _mm512_and_si512(a, b);
+#else
m512 rv;
rv.lo = and256(a.lo, b.lo);
rv.hi = and256(a.hi, b.hi);
return rv;
-#endif
+#endif
}
-static really_inline
-m512 or512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return _mm512_or_si512(a, b);
+static really_inline
+m512 or512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return _mm512_or_si512(a, b);
#else
m512 rv;
rv.lo = or256(a.lo, b.lo);
rv.hi = or256(a.hi, b.hi);
return rv;
-#endif
+#endif
}
-static really_inline
-m512 xor512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return _mm512_xor_si512(a, b);
+static really_inline
+m512 xor512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return _mm512_xor_si512(a, b);
#else
m512 rv;
rv.lo = xor256(a.lo, b.lo);
rv.hi = xor256(a.hi, b.hi);
return rv;
-#endif
+#endif
}
-static really_inline
-m512 not512(m512 a) {
-#if defined(HAVE_AVX512)
- return _mm512_xor_si512(a, ones512());
+static really_inline
+m512 not512(m512 a) {
+#if defined(HAVE_AVX512)
+ return _mm512_xor_si512(a, ones512());
#else
m512 rv;
rv.lo = not256(a.lo);
rv.hi = not256(a.hi);
return rv;
-#endif
+#endif
}
-static really_inline
-m512 andnot512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return _mm512_andnot_si512(a, b);
+static really_inline
+m512 andnot512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return _mm512_andnot_si512(a, b);
#else
m512 rv;
rv.lo = andnot256(a.lo, b.lo);
rv.hi = andnot256(a.hi, b.hi);
return rv;
-#endif
-}
-
-#if defined(HAVE_AVX512)
-static really_really_inline
-m512 lshift64_m512(m512 a, unsigned b) {
-#if defined(HAVE__BUILTIN_CONSTANT_P)
- if (__builtin_constant_p(b)) {
- return _mm512_slli_epi64(a, b);
- }
-#endif
- m128 x = _mm_cvtsi32_si128(b);
- return _mm512_sll_epi64(a, x);
-}
+#endif
+}
+
+#if defined(HAVE_AVX512)
+static really_really_inline
+m512 lshift64_m512(m512 a, unsigned b) {
+#if defined(HAVE__BUILTIN_CONSTANT_P)
+ if (__builtin_constant_p(b)) {
+ return _mm512_slli_epi64(a, b);
+ }
+#endif
+ m128 x = _mm_cvtsi32_si128(b);
+ return _mm512_sll_epi64(a, x);
+}
#else
-static really_really_inline
-m512 lshift64_m512(m512 a, unsigned b) {
+static really_really_inline
+m512 lshift64_m512(m512 a, unsigned b) {
m512 rv;
- rv.lo = lshift64_m256(a.lo, b);
- rv.hi = lshift64_m256(a.hi, b);
+ rv.lo = lshift64_m256(a.lo, b);
+ rv.hi = lshift64_m256(a.hi, b);
return rv;
}
#endif
-#if defined(HAVE_AVX512)
-#define rshift64_m512(a, b) _mm512_srli_epi64((a), (b))
-#define rshift128_m512(a, count_immed) _mm512_bsrli_epi128(a, count_immed)
-#define lshift128_m512(a, count_immed) _mm512_bslli_epi128(a, count_immed)
-#endif
+#if defined(HAVE_AVX512)
+#define rshift64_m512(a, b) _mm512_srli_epi64((a), (b))
+#define rshift128_m512(a, count_immed) _mm512_bsrli_epi128(a, count_immed)
+#define lshift128_m512(a, count_immed) _mm512_bslli_epi128(a, count_immed)
+#endif
-#if !defined(_MM_CMPINT_NE)
-#define _MM_CMPINT_NE 0x4
-#endif
+#if !defined(_MM_CMPINT_NE)
+#define _MM_CMPINT_NE 0x4
+#endif
-static really_inline
-int diff512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return !!_mm512_cmp_epi8_mask(a, b, _MM_CMPINT_NE);
-#else
+static really_inline
+int diff512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return !!_mm512_cmp_epi8_mask(a, b, _MM_CMPINT_NE);
+#else
return diff256(a.lo, b.lo) || diff256(a.hi, b.hi);
-#endif
+#endif
}
-static really_inline
-int isnonzero512(m512 a) {
-#if defined(HAVE_AVX512)
- return diff512(a, zeroes512());
-#elif defined(HAVE_AVX2)
- m256 x = or256(a.lo, a.hi);
- return !!diff256(x, zeroes256());
-#else
+static really_inline
+int isnonzero512(m512 a) {
+#if defined(HAVE_AVX512)
+ return diff512(a, zeroes512());
+#elif defined(HAVE_AVX2)
+ m256 x = or256(a.lo, a.hi);
+ return !!diff256(x, zeroes256());
+#else
m128 x = or128(a.lo.lo, a.lo.hi);
m128 y = or128(a.hi.lo, a.hi.hi);
return isnonzero128(or128(x, y));
@@ -1192,11 +1192,11 @@ int isnonzero512(m512 a) {
* "Rich" version of diff512(). Takes two vectors a and b and returns a 16-bit
* mask indicating which 32-bit words contain differences.
*/
-static really_inline
-u32 diffrich512(m512 a, m512 b) {
-#if defined(HAVE_AVX512)
- return _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_NE);
-#elif defined(HAVE_AVX2)
+static really_inline
+u32 diffrich512(m512 a, m512 b) {
+#if defined(HAVE_AVX512)
+ return _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_NE);
+#elif defined(HAVE_AVX2)
return diffrich256(a.lo, b.lo) | (diffrich256(a.hi, b.hi) << 8);
#else
a.lo.lo = _mm_cmpeq_epi32(a.lo.lo, b.lo.lo);
@@ -1213,32 +1213,32 @@ u32 diffrich512(m512 a, m512 b) {
* "Rich" version of diffrich(), 64-bit variant. Takes two vectors a and b and
* returns a 16-bit mask indicating which 64-bit words contain differences.
*/
-static really_inline
-u32 diffrich64_512(m512 a, m512 b) {
- //TODO: cmp_epi64?
+static really_inline
+u32 diffrich64_512(m512 a, m512 b) {
+ //TODO: cmp_epi64?
u32 d = diffrich512(a, b);
return (d | (d >> 1)) & 0x55555555;
}
// aligned load
-static really_inline
-m512 load512(const void *ptr) {
-#if defined(HAVE_AVX512)
- return _mm512_load_si512(ptr);
-#else
- assert(ISALIGNED_N(ptr, alignof(m256)));
+static really_inline
+m512 load512(const void *ptr) {
+#if defined(HAVE_AVX512)
+ return _mm512_load_si512(ptr);
+#else
+ assert(ISALIGNED_N(ptr, alignof(m256)));
m512 rv = { load256(ptr), load256((const char *)ptr + 32) };
return rv;
-#endif
+#endif
}
// aligned store
-static really_inline
-void store512(void *ptr, m512 a) {
- assert(ISALIGNED_N(ptr, alignof(m512)));
-#if defined(HAVE_AVX512)
- return _mm512_store_si512(ptr, a);
-#elif defined(HAVE_AVX2)
+static really_inline
+void store512(void *ptr, m512 a) {
+ assert(ISALIGNED_N(ptr, alignof(m512)));
+#if defined(HAVE_AVX512)
+ return _mm512_store_si512(ptr, a);
+#elif defined(HAVE_AVX2)
m512 *x = (m512 *)ptr;
store256(&x->lo, a.lo);
store256(&x->hi, a.hi);
@@ -1249,20 +1249,20 @@ void store512(void *ptr, m512 a) {
}
// unaligned load
-static really_inline
-m512 loadu512(const void *ptr) {
-#if defined(HAVE_AVX512)
- return _mm512_loadu_si512(ptr);
-#else
+static really_inline
+m512 loadu512(const void *ptr) {
+#if defined(HAVE_AVX512)
+ return _mm512_loadu_si512(ptr);
+#else
m512 rv = { loadu256(ptr), loadu256((const char *)ptr + 32) };
return rv;
-#endif
+#endif
}
// unaligned store
static really_inline
void storeu512(void *ptr, m512 a) {
-#if defined(HAVE_AVX512)
+#if defined(HAVE_AVX512)
_mm512_storeu_si512((m512 *)ptr, a);
#elif defined(HAVE_AVX2)
storeu256(ptr, a.lo);
@@ -1276,32 +1276,32 @@ void storeu512(void *ptr, m512 a) {
}
#if defined(HAVE_AVX512)
-static really_inline
-m512 loadu_maskz_m512(__mmask64 k, const void *ptr) {
- return _mm512_maskz_loadu_epi8(k, ptr);
-}
-
-static really_inline
-m512 loadu_mask_m512(m512 src, __mmask64 k, const void *ptr) {
- return _mm512_mask_loadu_epi8(src, k, ptr);
-}
-
-static really_inline
+static really_inline
+m512 loadu_maskz_m512(__mmask64 k, const void *ptr) {
+ return _mm512_maskz_loadu_epi8(k, ptr);
+}
+
+static really_inline
+m512 loadu_mask_m512(m512 src, __mmask64 k, const void *ptr) {
+ return _mm512_mask_loadu_epi8(src, k, ptr);
+}
+
+static really_inline
void storeu_mask_m512(void *ptr, __mmask64 k, m512 a) {
_mm512_mask_storeu_epi8(ptr, k, a);
}
static really_inline
-m512 set_mask_m512(__mmask64 k) {
- return _mm512_movm_epi8(k);
-}
+m512 set_mask_m512(__mmask64 k) {
+ return _mm512_movm_epi8(k);
+}
static really_inline
m256 loadu_maskz_m256(__mmask32 k, const void *ptr) {
return _mm256_maskz_loadu_epi8(k, ptr);
}
-#endif
-
+#endif
+
// packed unaligned store of first N bytes
static really_inline
void storebytes512(void *ptr, m512 a, unsigned int n) {
@@ -1318,19 +1318,19 @@ m512 loadbytes512(const void *ptr, unsigned int n) {
return a;
}
-static really_inline
-m512 mask1bit512(unsigned int n) {
- assert(n < sizeof(m512) * 8);
- u32 mask_idx = ((n % 8) * 64) + 95;
- mask_idx -= n / 8;
- return loadu512(&simd_onebit_masks[mask_idx]);
-}
-
+static really_inline
+m512 mask1bit512(unsigned int n) {
+ assert(n < sizeof(m512) * 8);
+ u32 mask_idx = ((n % 8) * 64) + 95;
+ mask_idx -= n / 8;
+ return loadu512(&simd_onebit_masks[mask_idx]);
+}
+
// switches on bit N in the given vector.
static really_inline
void setbit512(m512 *ptr, unsigned int n) {
assert(n < sizeof(*ptr) * 8);
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
m128 *sub;
if (n < 128) {
sub = &ptr->lo.lo;
@@ -1342,8 +1342,8 @@ void setbit512(m512 *ptr, unsigned int n) {
sub = &ptr->hi.hi;
}
setbit128(sub, n % 128);
-#elif defined(HAVE_AVX512)
- *ptr = or512(mask1bit512(n), *ptr);
+#elif defined(HAVE_AVX512)
+ *ptr = or512(mask1bit512(n), *ptr);
#else
m256 *sub;
if (n < 256) {
@@ -1360,7 +1360,7 @@ void setbit512(m512 *ptr, unsigned int n) {
static really_inline
void clearbit512(m512 *ptr, unsigned int n) {
assert(n < sizeof(*ptr) * 8);
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
m128 *sub;
if (n < 128) {
sub = &ptr->lo.lo;
@@ -1372,8 +1372,8 @@ void clearbit512(m512 *ptr, unsigned int n) {
sub = &ptr->hi.hi;
}
clearbit128(sub, n % 128);
-#elif defined(HAVE_AVX512)
- *ptr = andnot512(mask1bit512(n), *ptr);
+#elif defined(HAVE_AVX512)
+ *ptr = andnot512(mask1bit512(n), *ptr);
#else
m256 *sub;
if (n < 256) {
@@ -1388,29 +1388,29 @@ void clearbit512(m512 *ptr, unsigned int n) {
// tests bit N in the given vector.
static really_inline
-char testbit512(m512 val, unsigned int n) {
- assert(n < sizeof(val) * 8);
-#if !defined(HAVE_AVX2)
- m128 sub;
+char testbit512(m512 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
+#if !defined(HAVE_AVX2)
+ m128 sub;
if (n < 128) {
- sub = val.lo.lo;
+ sub = val.lo.lo;
} else if (n < 256) {
- sub = val.lo.hi;
+ sub = val.lo.hi;
} else if (n < 384) {
- sub = val.hi.lo;
+ sub = val.hi.lo;
} else {
- sub = val.hi.hi;
+ sub = val.hi.hi;
}
return testbit128(sub, n % 128);
-#elif defined(HAVE_AVX512)
- const m512 mask = mask1bit512(n);
- return !!_mm512_test_epi8_mask(mask, val);
+#elif defined(HAVE_AVX512)
+ const m512 mask = mask1bit512(n);
+ return !!_mm512_test_epi8_mask(mask, val);
#else
- m256 sub;
+ m256 sub;
if (n < 256) {
- sub = val.lo;
+ sub = val.lo;
} else {
- sub = val.hi;
+ sub = val.hi;
n -= 256;
}
return testbit256(sub, n);
diff --git a/contrib/libs/hyperscan/src/util/small_vector.h b/contrib/libs/hyperscan/src/util/small_vector.h
index c5f11915d5a..0f54bbf6bf6 100644
--- a/contrib/libs/hyperscan/src/util/small_vector.h
+++ b/contrib/libs/hyperscan/src/util/small_vector.h
@@ -1,70 +1,70 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UTIL_SMALL_VECTOR_H
-#define UTIL_SMALL_VECTOR_H
-
-#include <vector>
-
-#include <boost/version.hpp>
-
-/*
- * We use the small_vector constructors introduced in Boost 1.61 (trac bug
- * #11866, github commit b436c91). If the Boost version is too old, we fall
- * back to using std::vector.
- */
-#if BOOST_VERSION >= 106100
-# define HAVE_BOOST_CONTAINER_SMALL_VECTOR
-#endif
-
-#if defined(HAVE_BOOST_CONTAINER_SMALL_VECTOR)
-# include <boost/container/small_vector.hpp>
-#endif
-
-namespace ue2 {
-
-#if defined(HAVE_BOOST_CONTAINER_SMALL_VECTOR)
-
-template <class T, std::size_t N,
- typename Allocator = boost::container::new_allocator<T>>
-using small_vector = boost::container::small_vector<T, N, Allocator>;
-
-#else
-
-// Boost version isn't new enough, fall back to just using std::vector.
-template <class T, std::size_t N, typename Allocator = std::allocator<T>>
-using small_vector = std::vector<T, Allocator>;
-
-// Support workarounds for flat_set/flat_map and GCC 4.8.
-#define SMALL_VECTOR_IS_STL_VECTOR 1
-
-#endif // HAVE_BOOST_CONTAINER_SMALL_VECTOR
-
-} // namespace ue2
-
-#endif // UTIL_SMALL_VECTOR_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UTIL_SMALL_VECTOR_H
+#define UTIL_SMALL_VECTOR_H
+
+#include <vector>
+
+#include <boost/version.hpp>
+
+/*
+ * We use the small_vector constructors introduced in Boost 1.61 (trac bug
+ * #11866, github commit b436c91). If the Boost version is too old, we fall
+ * back to using std::vector.
+ */
+#if BOOST_VERSION >= 106100
+# define HAVE_BOOST_CONTAINER_SMALL_VECTOR
+#endif
+
+#if defined(HAVE_BOOST_CONTAINER_SMALL_VECTOR)
+# include <boost/container/small_vector.hpp>
+#endif
+
+namespace ue2 {
+
+#if defined(HAVE_BOOST_CONTAINER_SMALL_VECTOR)
+
+template <class T, std::size_t N,
+ typename Allocator = boost::container::new_allocator<T>>
+using small_vector = boost::container::small_vector<T, N, Allocator>;
+
+#else
+
+// Boost version isn't new enough, fall back to just using std::vector.
+template <class T, std::size_t N, typename Allocator = std::allocator<T>>
+using small_vector = std::vector<T, Allocator>;
+
+// Support workarounds for flat_set/flat_map and GCC 4.8.
+#define SMALL_VECTOR_IS_STL_VECTOR 1
+
+#endif // HAVE_BOOST_CONTAINER_SMALL_VECTOR
+
+} // namespace ue2
+
+#endif // UTIL_SMALL_VECTOR_H
diff --git a/contrib/libs/hyperscan/src/util/state_compress.c b/contrib/libs/hyperscan/src/util/state_compress.c
index acc0a476678..7238849e7f8 100644
--- a/contrib/libs/hyperscan/src/util/state_compress.c
+++ b/contrib/libs/hyperscan/src/util/state_compress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,7 @@
*/
#include "config.h"
#include "ue2common.h"
-#include "arch.h"
+#include "arch.h"
#include "bitutils.h"
#include "unaligned.h"
#include "pack_bits.h"
@@ -263,7 +263,7 @@ m256 loadcompressed256_32bit(const void *ptr, m256 mvec) {
expand32(v[4], m[4]), expand32(v[5], m[5]),
expand32(v[6], m[6]), expand32(v[7], m[7]) };
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
m256 xvec = { .lo = _mm_set_epi32(x[3], x[2], x[1], x[0]),
.hi = _mm_set_epi32(x[7], x[6], x[5], x[4]) };
#else
@@ -290,7 +290,7 @@ m256 loadcompressed256_64bit(const void *ptr, m256 mvec) {
u64a x[4] = { expand64(v[0], m[0]), expand64(v[1], m[1]),
expand64(v[2], m[2]), expand64(v[3], m[3]) };
-#if !defined(HAVE_AVX2)
+#if !defined(HAVE_AVX2)
m256 xvec = { .lo = _mm_set_epi64x(x[1], x[0]),
.hi = _mm_set_epi64x(x[3], x[2]) };
#else
@@ -547,17 +547,17 @@ m512 loadcompressed512_32bit(const void *ptr, m512 mvec) {
expand32(v[14], m[14]), expand32(v[15], m[15]) };
m512 xvec;
-#if defined(HAVE_AVX512)
- xvec = _mm512_set_epi32(x[15], x[14], x[13], x[12],
- x[11], x[10], x[9], x[8],
- x[7], x[6], x[5], x[4],
- x[3], x[2], x[1], x[0]);
-#elif defined(HAVE_AVX2)
- xvec.lo = _mm256_set_epi32(x[7], x[6], x[5], x[4],
- x[3], x[2], x[1], x[0]);
- xvec.hi = _mm256_set_epi32(x[15], x[14], x[13], x[12],
- x[11], x[10], x[9], x[8]);
-#else
+#if defined(HAVE_AVX512)
+ xvec = _mm512_set_epi32(x[15], x[14], x[13], x[12],
+ x[11], x[10], x[9], x[8],
+ x[7], x[6], x[5], x[4],
+ x[3], x[2], x[1], x[0]);
+#elif defined(HAVE_AVX2)
+ xvec.lo = _mm256_set_epi32(x[7], x[6], x[5], x[4],
+ x[3], x[2], x[1], x[0]);
+ xvec.hi = _mm256_set_epi32(x[15], x[14], x[13], x[12],
+ x[11], x[10], x[9], x[8]);
+#else
xvec.lo.lo = _mm_set_epi32(x[3], x[2], x[1], x[0]);
xvec.lo.hi = _mm_set_epi32(x[7], x[6], x[5], x[4]);
xvec.hi.lo = _mm_set_epi32(x[11], x[10], x[9], x[8]);
@@ -587,13 +587,13 @@ m512 loadcompressed512_64bit(const void *ptr, m512 mvec) {
expand64(v[4], m[4]), expand64(v[5], m[5]),
expand64(v[6], m[6]), expand64(v[7], m[7]) };
-#if defined(HAVE_AVX512)
- m512 xvec = _mm512_set_epi64(x[7], x[6], x[5], x[4],
- x[3], x[2], x[1], x[0]);
-#elif defined(HAVE_AVX2)
- m512 xvec = { .lo = _mm256_set_epi64x(x[3], x[2], x[1], x[0]),
- .hi = _mm256_set_epi64x(x[7], x[6], x[5], x[4])};
-#else
+#if defined(HAVE_AVX512)
+ m512 xvec = _mm512_set_epi64(x[7], x[6], x[5], x[4],
+ x[3], x[2], x[1], x[0]);
+#elif defined(HAVE_AVX2)
+ m512 xvec = { .lo = _mm256_set_epi64x(x[3], x[2], x[1], x[0]),
+ .hi = _mm256_set_epi64x(x[7], x[6], x[5], x[4])};
+#else
m512 xvec = { .lo = { _mm_set_epi64x(x[1], x[0]),
_mm_set_epi64x(x[3], x[2]) },
.hi = { _mm_set_epi64x(x[5], x[4]),
diff --git a/contrib/libs/hyperscan/src/util/target_info.cpp b/contrib/libs/hyperscan/src/util/target_info.cpp
index ccd8945d4cf..66ba5f5acc5 100644
--- a/contrib/libs/hyperscan/src/util/target_info.cpp
+++ b/contrib/libs/hyperscan/src/util/target_info.cpp
@@ -46,10 +46,10 @@ bool target_t::can_run_on_code_built_for(const target_t &code_target) const {
return false;
}
- if (!has_avx512() && code_target.has_avx512()) {
- return false;
- }
-
+ if (!has_avx512() && code_target.has_avx512()) {
+ return false;
+ }
+
if (!has_avx512vbmi() && code_target.has_avx512vbmi()) {
return false;
}
@@ -61,19 +61,19 @@ target_t::target_t(const hs_platform_info &p)
: tune(p.tune), cpu_features(p.cpu_features) {}
bool target_t::has_avx2(void) const {
- return cpu_features & HS_CPU_FEATURES_AVX2;
+ return cpu_features & HS_CPU_FEATURES_AVX2;
+}
+
+bool target_t::has_avx512(void) const {
+ return cpu_features & HS_CPU_FEATURES_AVX512;
}
-bool target_t::has_avx512(void) const {
- return cpu_features & HS_CPU_FEATURES_AVX512;
-}
-
bool target_t::has_avx512vbmi(void) const {
return cpu_features & HS_CPU_FEATURES_AVX512VBMI;
}
bool target_t::is_atom_class(void) const {
- return tune == HS_TUNE_FAMILY_SLM || tune == HS_TUNE_FAMILY_GLM;
+ return tune == HS_TUNE_FAMILY_SLM || tune == HS_TUNE_FAMILY_GLM;
}
} // namespace ue2
diff --git a/contrib/libs/hyperscan/src/util/target_info.h b/contrib/libs/hyperscan/src/util/target_info.h
index 15aa4d61b81..f64573aedad 100644
--- a/contrib/libs/hyperscan/src/util/target_info.h
+++ b/contrib/libs/hyperscan/src/util/target_info.h
@@ -40,8 +40,8 @@ struct target_t {
bool has_avx2(void) const;
- bool has_avx512(void) const;
-
+ bool has_avx512(void) const;
+
bool has_avx512vbmi(void) const;
bool is_atom_class(void) const;
diff --git a/contrib/libs/hyperscan/src/util/ue2_graph.h b/contrib/libs/hyperscan/src/util/ue2_graph.h
index 72a525374b8..aa9718d73a6 100644
--- a/contrib/libs/hyperscan/src/util/ue2_graph.h
+++ b/contrib/libs/hyperscan/src/util/ue2_graph.h
@@ -1,1032 +1,1032 @@
-/*
+/*
* Copyright (c) 2016-2018, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UE2_GRAPH_H
-#define UE2_GRAPH_H
-
-#include "ue2common.h"
-#include "util/graph_range.h"
-#include "util/noncopyable.h"
-#include "util/operators.h"
-
-#include <boost/graph/properties.hpp> /* vertex_index_t, ... */
-#include <boost/pending/property.hpp> /* no_property */
-#include <boost/property_map/property_map.hpp>
-#include <boost/intrusive/list.hpp>
-#include <boost/iterator/iterator_adaptor.hpp>
-#include <boost/iterator/iterator_facade.hpp>
-
-#include <functional> /* hash */
-#include <tuple> /* tie */
-#include <type_traits> /* is_same, etc */
-#include <utility> /* pair, declval */
-
-/*
- * Basic design of ue2_graph:
- *
- * Fairly standard adjacency list type graph structure. The main internal
- * structures are vertex_node and edge_node.
- *
- * Each vertex_node maintains lists of incoming and outgoing edge_nodes, a
- * serial number and the vertex properties.
- *
- * Each edge_node contains pointers to the source and target vertex as well as
- * the serial number and edge properties.
- *
- * Every time an edge_node or vertex_node is created in the graph, it is given a
- * unique serial number by increasing a private counter in the graph.
- *
- * The main thing to note is that the in and out edge lists are intrusive lists
- * with the edge_node containing the necessary hooks. This means that we can
- * easily convert the edge_node to iterators of the in_edge_list and
- * out_edge_list and remove them from the lists.
- *
- * vertex_descriptor and edge_descriptor structures both just wrap pointers to
- * the relevant node structure along with the serial number. operator<() for the
- * descriptors is overridden to look at the serial member of the node.
- * We do not use:
- * - the address of the node structure as this would lead to an unstable
- * ordering of vertices between runs.
- * - the index field as this would mean that the generation of new index
- * values (during say renumbering of vertex nodes after removing some
- * vertices) would potentially reorder vertices and corrupt containers
- * such as std::set<>.
- * The serial number is copied into the descriptors so that we can still have
- * descriptors in a container (such as set or unordered_set) after removing the
- * underlying node.
- *
- * Hashing of descriptors is based on the serial field for similar reasons.
- *
- *
- *
- * Main differences from boost::adjacency_list<> with listS:
- *
- * (1) Deterministic ordering for vertices and edges
- * boost::adjacency_list<> uses pointer ordering for vertex_descriptors. As
- * a result, ordering of vertices and edges between runs is
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UE2_GRAPH_H
+#define UE2_GRAPH_H
+
+#include "ue2common.h"
+#include "util/graph_range.h"
+#include "util/noncopyable.h"
+#include "util/operators.h"
+
+#include <boost/graph/properties.hpp> /* vertex_index_t, ... */
+#include <boost/pending/property.hpp> /* no_property */
+#include <boost/property_map/property_map.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <functional> /* hash */
+#include <tuple> /* tie */
+#include <type_traits> /* is_same, etc */
+#include <utility> /* pair, declval */
+
+/*
+ * Basic design of ue2_graph:
+ *
+ * Fairly standard adjacency list type graph structure. The main internal
+ * structures are vertex_node and edge_node.
+ *
+ * Each vertex_node maintains lists of incoming and outgoing edge_nodes, a
+ * serial number and the vertex properties.
+ *
+ * Each edge_node contains pointers to the source and target vertex as well as
+ * the serial number and edge properties.
+ *
+ * Every time an edge_node or vertex_node is created in the graph, it is given a
+ * unique serial number by increasing a private counter in the graph.
+ *
+ * The main thing to note is that the in and out edge lists are intrusive lists
+ * with the edge_node containing the necessary hooks. This means that we can
+ * easily convert the edge_node to iterators of the in_edge_list and
+ * out_edge_list and remove them from the lists.
+ *
+ * vertex_descriptor and edge_descriptor structures both just wrap pointers to
+ * the relevant node structure along with the serial number. operator<() for the
+ * descriptors is overridden to look at the serial member of the node.
+ * We do not use:
+ * - the address of the node structure as this would lead to an unstable
+ * ordering of vertices between runs.
+ * - the index field as this would mean that the generation of new index
+ * values (during say renumbering of vertex nodes after removing some
+ * vertices) would potentially reorder vertices and corrupt containers
+ * such as std::set<>.
+ * The serial number is copied into the descriptors so that we can still have
+ * descriptors in a container (such as set or unordered_set) after removing the
+ * underlying node.
+ *
+ * Hashing of descriptors is based on the serial field for similar reasons.
+ *
+ *
+ *
+ * Main differences from boost::adjacency_list<> with listS:
+ *
+ * (1) Deterministic ordering for vertices and edges
+ * boost::adjacency_list<> uses pointer ordering for vertex_descriptors. As
+ * a result, ordering of vertices and edges between runs is
* non-deterministic unless containers, etc use custom comparators.
- *
- * (2) Proper types for descriptors, etc.
- * No more void * for vertex_descriptors and trying to use it for the wrong
- * graph type.
- *
- * (3) Constant time num_edges(), num_vertices(), degree(), in_degree() and
- * out_degree()
- * std::list is meant to have constant time in C++11 ::size(), but this is
- * not always implemented as people want to keep ABI compatibility with
- * existing C++98 standard libraries (gcc 4.8). As ue2_graph_h uses
- * intrusive lists rather than std::list this is not an issue for us.
- *
- * (4) Constant time remove_edge(e, g)
- * ue2_graph uses boost::intrusive_lists internally so we can easily unlink
- * an edge from the in and out edgelist of its source and target.
- *
- * (5) More efficient edge(u, v, g) and remove_edge(u, v, g)
- * ue2_graph will check which of u and v has the smallest relevant degree
- * and use that to search for the edge(s).
- *
- * (6) Automatically populate the index field of vertex and edge bundles.
- * Saves us from doing it manually. Naturally there is nothing to prevent
- * the user from stuffing up the index properties later.
- *
- * (7) Different edge iteration order
- * ue2_graph does not maintain an explicit global edge list, so the
- * edge_iterator is constructed out of vertex_iterator and
- * out_edge_iterators by iterating the out_edges of each vertices. This
- * means that edge iteration order is not insertion order like for
- * adjacency_list.
- *
- * (8) null_edge()
- * Because why not?
- *
- * (9) vertex and edge properties must have an index field.
- * We generally need them so the effort has not been put into specialising
- * for when they are not present.
- *
- *
- *
- * Possible Future Work:
- *
- * (1) Improve edge(u, v, g) performance
- * This function sees a fair amount of use and is O(n) in the smallest of
- * the source out_degree or target in_degree. This could be improved by
- * changes on of the edge containers to be something similar to a multiset.
- *
- * (2) 'Lie' about the number of edges / vertices
- *
- * One of the main uses of num_edges() and num_vertices() is to allocate a
- * vector, etc so that it can be indexed by edge or vertex index. If
- * num_edges() and num_vertices() returned the appropriate size for such a
- * vector (at least one more than the largest index), we would be able to
- * avoid some renumbering operations. Functions would have to be provided to
- * get the real number of vertices and edges. Having num_vertices() and
- * num_edges() return an over-estimate is not without precedence in the BGL
- * - the filtered_graph adaptor does the same thing and is compatible with
- * various (all?) BGL algorithms. It is not clear that this was done
- * deliberately for the same reason or because it is difficult for
- * filtered_graph to get the true counts.
- *
- * (3) Investigate slab/pooled allocation schemes for nodes.
- */
-
-namespace ue2 {
-
-namespace graph_detail {
-
-class graph_base : noncopyable {
-};
-
-struct default_edge_property {
- size_t index;
-};
-
-struct default_vertex_property {
- size_t index;
-};
-
-template<typename Graph>
-class vertex_descriptor : totally_ordered<vertex_descriptor<Graph>> {
- using vertex_node = typename Graph::vertex_node;
-public:
- vertex_descriptor() : p(nullptr), serial(0) {}
- explicit vertex_descriptor(vertex_node *pp) : p(pp), serial(pp->serial) {}
-
+ *
+ * (2) Proper types for descriptors, etc.
+ * No more void * for vertex_descriptors and trying to use it for the wrong
+ * graph type.
+ *
+ * (3) Constant time num_edges(), num_vertices(), degree(), in_degree() and
+ * out_degree()
+ * std::list is meant to have constant time in C++11 ::size(), but this is
+ * not always implemented as people want to keep ABI compatibility with
+ * existing C++98 standard libraries (gcc 4.8). As ue2_graph_h uses
+ * intrusive lists rather than std::list this is not an issue for us.
+ *
+ * (4) Constant time remove_edge(e, g)
+ * ue2_graph uses boost::intrusive_lists internally so we can easily unlink
+ * an edge from the in and out edgelist of its source and target.
+ *
+ * (5) More efficient edge(u, v, g) and remove_edge(u, v, g)
+ * ue2_graph will check which of u and v has the smallest relevant degree
+ * and use that to search for the edge(s).
+ *
+ * (6) Automatically populate the index field of vertex and edge bundles.
+ * Saves us from doing it manually. Naturally there is nothing to prevent
+ * the user from stuffing up the index properties later.
+ *
+ * (7) Different edge iteration order
+ * ue2_graph does not maintain an explicit global edge list, so the
+ * edge_iterator is constructed out of vertex_iterator and
+ * out_edge_iterators by iterating the out_edges of each vertices. This
+ * means that edge iteration order is not insertion order like for
+ * adjacency_list.
+ *
+ * (8) null_edge()
+ * Because why not?
+ *
+ * (9) vertex and edge properties must have an index field.
+ * We generally need them so the effort has not been put into specialising
+ * for when they are not present.
+ *
+ *
+ *
+ * Possible Future Work:
+ *
+ * (1) Improve edge(u, v, g) performance
+ * This function sees a fair amount of use and is O(n) in the smallest of
+ * the source out_degree or target in_degree. This could be improved by
+ * changes on of the edge containers to be something similar to a multiset.
+ *
+ * (2) 'Lie' about the number of edges / vertices
+ *
+ * One of the main uses of num_edges() and num_vertices() is to allocate a
+ * vector, etc so that it can be indexed by edge or vertex index. If
+ * num_edges() and num_vertices() returned the appropriate size for such a
+ * vector (at least one more than the largest index), we would be able to
+ * avoid some renumbering operations. Functions would have to be provided to
+ * get the real number of vertices and edges. Having num_vertices() and
+ * num_edges() return an over-estimate is not without precedence in the BGL
+ * - the filtered_graph adaptor does the same thing and is compatible with
+ * various (all?) BGL algorithms. It is not clear that this was done
+ * deliberately for the same reason or because it is difficult for
+ * filtered_graph to get the true counts.
+ *
+ * (3) Investigate slab/pooled allocation schemes for nodes.
+ */
+
+namespace ue2 {
+
+namespace graph_detail {
+
+class graph_base : noncopyable {
+};
+
+struct default_edge_property {
+ size_t index;
+};
+
+struct default_vertex_property {
+ size_t index;
+};
+
+template<typename Graph>
+class vertex_descriptor : totally_ordered<vertex_descriptor<Graph>> {
+ using vertex_node = typename Graph::vertex_node;
+public:
+ vertex_descriptor() : p(nullptr), serial(0) {}
+ explicit vertex_descriptor(vertex_node *pp) : p(pp), serial(pp->serial) {}
+
explicit operator bool() const { return p; }
- bool operator<(const vertex_descriptor b) const {
- if (p && b.p) {
- /* no vertices in the same graph can have the same serial */
- assert(p == b.p || serial != b.serial);
- return serial < b.serial;
- } else {
- return p < b.p;
- }
- }
- bool operator==(const vertex_descriptor b) const { return p == b.p; }
-
- size_t hash() const {
- return std::hash<u64a>()(serial);
- }
-
-private:
- vertex_node *raw(void) { return p; }
- vertex_node *p;
- u64a serial;
- friend Graph;
-};
-
-template<typename Graph>
-class edge_descriptor : totally_ordered<edge_descriptor<Graph>> {
- using edge_node = typename Graph::edge_node;
-public:
- edge_descriptor() : p(nullptr), serial(0) {}
- explicit edge_descriptor(edge_node *pp) : p(pp), serial(pp->serial) {}
-
- /* Convenience ctor to allow us to directly get an edge_descriptor from
- * edge() and add_edge(). As we have null_edges and we always allow
- * parallel edges, the bool component of the return from these functions is
- * not required. */
- edge_descriptor(const std::pair<edge_descriptor, bool> &tup)
- : p(tup.first.p), serial(tup.first.serial) {
- assert(tup.second == (bool)tup.first);
- }
-
- operator bool() const { return p; }
- bool operator<(const edge_descriptor b) const {
- if (p && b.p) {
- /* no edges in the same graph can have the same serial */
- assert(p == b.p || serial != b.serial);
- return serial < b.serial;
- } else {
- return p < b.p;
- }
- }
- bool operator==(const edge_descriptor b) const { return p == b.p; }
-
- size_t hash() const {
- return std::hash<u64a>()(serial);
- }
-
-private:
- edge_node *raw(void) { return p; }
- edge_node *p;
- u64a serial;
- friend Graph;
-};
-
-} // namespace graph_detail
-
-template<typename Graph,
- typename VertexPropertyType = graph_detail::default_vertex_property,
- typename EdgePropertyType = graph_detail::default_edge_property>
-class ue2_graph : graph_detail::graph_base {
-private:
- struct in_edge_tag { };
- struct out_edge_tag { };
-
- struct vertex_node;
-
- using out_edge_hook
- = boost::intrusive::list_base_hook<boost::intrusive::tag<out_edge_tag> >;
-
- /* in_edge_hook does not use safe mode as during graph destruction we do not
- * maintain the in edge lists */
- using in_edge_hook
- = boost::intrusive::list_base_hook<boost::intrusive::tag<in_edge_tag>,
- boost::intrusive::link_mode<boost::intrusive::normal_link> >;
-
- struct edge_node : public out_edge_hook, public in_edge_hook {
- explicit edge_node(u64a serial_in) : serial(serial_in) { }
-
- vertex_node *source = nullptr;
- vertex_node *target = nullptr;
- const u64a serial; /*< used to order edges. We do not use props.index so
- * that there is no danger of invalidating sets or
- * other containers by changing the index due to
- * renumbering */
- EdgePropertyType props;
- };
-
- template<typename hook_type> using vertex_edge_list
- = boost::intrusive::list<edge_node,
- boost::intrusive::base_hook<hook_type> >;
-
- struct vertex_node : public boost::intrusive::list_base_hook<> {
- explicit vertex_node(u64a serial_in) : serial(serial_in) { }
-
- VertexPropertyType props;
- const u64a serial; /*< used to order vertices. We do not use props.index
- * so that there is no danger of invalidating sets or
- * other containers by changing the index due to
- * renumbering */
-
- /* The incoming edges are not considered owned by the vertex */
- vertex_edge_list<in_edge_hook> in_edge_list;
-
- /* The out going edges are considered owned by the vertex and
+ bool operator<(const vertex_descriptor b) const {
+ if (p && b.p) {
+ /* no vertices in the same graph can have the same serial */
+ assert(p == b.p || serial != b.serial);
+ return serial < b.serial;
+ } else {
+ return p < b.p;
+ }
+ }
+ bool operator==(const vertex_descriptor b) const { return p == b.p; }
+
+ size_t hash() const {
+ return std::hash<u64a>()(serial);
+ }
+
+private:
+ vertex_node *raw(void) { return p; }
+ vertex_node *p;
+ u64a serial;
+ friend Graph;
+};
+
+template<typename Graph>
+class edge_descriptor : totally_ordered<edge_descriptor<Graph>> {
+ using edge_node = typename Graph::edge_node;
+public:
+ edge_descriptor() : p(nullptr), serial(0) {}
+ explicit edge_descriptor(edge_node *pp) : p(pp), serial(pp->serial) {}
+
+ /* Convenience ctor to allow us to directly get an edge_descriptor from
+ * edge() and add_edge(). As we have null_edges and we always allow
+ * parallel edges, the bool component of the return from these functions is
+ * not required. */
+ edge_descriptor(const std::pair<edge_descriptor, bool> &tup)
+ : p(tup.first.p), serial(tup.first.serial) {
+ assert(tup.second == (bool)tup.first);
+ }
+
+ operator bool() const { return p; }
+ bool operator<(const edge_descriptor b) const {
+ if (p && b.p) {
+ /* no edges in the same graph can have the same serial */
+ assert(p == b.p || serial != b.serial);
+ return serial < b.serial;
+ } else {
+ return p < b.p;
+ }
+ }
+ bool operator==(const edge_descriptor b) const { return p == b.p; }
+
+ size_t hash() const {
+ return std::hash<u64a>()(serial);
+ }
+
+private:
+ edge_node *raw(void) { return p; }
+ edge_node *p;
+ u64a serial;
+ friend Graph;
+};
+
+} // namespace graph_detail
+
+template<typename Graph,
+ typename VertexPropertyType = graph_detail::default_vertex_property,
+ typename EdgePropertyType = graph_detail::default_edge_property>
+class ue2_graph : graph_detail::graph_base {
+private:
+ struct in_edge_tag { };
+ struct out_edge_tag { };
+
+ struct vertex_node;
+
+ using out_edge_hook
+ = boost::intrusive::list_base_hook<boost::intrusive::tag<out_edge_tag> >;
+
+ /* in_edge_hook does not use safe mode as during graph destruction we do not
+ * maintain the in edge lists */
+ using in_edge_hook
+ = boost::intrusive::list_base_hook<boost::intrusive::tag<in_edge_tag>,
+ boost::intrusive::link_mode<boost::intrusive::normal_link> >;
+
+ struct edge_node : public out_edge_hook, public in_edge_hook {
+ explicit edge_node(u64a serial_in) : serial(serial_in) { }
+
+ vertex_node *source = nullptr;
+ vertex_node *target = nullptr;
+ const u64a serial; /*< used to order edges. We do not use props.index so
+ * that there is no danger of invalidating sets or
+ * other containers by changing the index due to
+ * renumbering */
+ EdgePropertyType props;
+ };
+
+ template<typename hook_type> using vertex_edge_list
+ = boost::intrusive::list<edge_node,
+ boost::intrusive::base_hook<hook_type> >;
+
+ struct vertex_node : public boost::intrusive::list_base_hook<> {
+ explicit vertex_node(u64a serial_in) : serial(serial_in) { }
+
+ VertexPropertyType props;
+ const u64a serial; /*< used to order vertices. We do not use props.index
+ * so that there is no danger of invalidating sets or
+ * other containers by changing the index due to
+ * renumbering */
+
+ /* The incoming edges are not considered owned by the vertex */
+ vertex_edge_list<in_edge_hook> in_edge_list;
+
+ /* The out going edges are considered owned by the vertex and
* need to be freed when the graph is being destroyed */
- vertex_edge_list<out_edge_hook> out_edge_list;
-
- /* The destructor only frees memory owned by the vertex and will leave
- * the neighbour's edges in a bad state. If a vertex is being removed
- * (rather than the graph being destroyed), then the more gentle clean
- * up of clear_vertex() is required to be called first */
- ~vertex_node() {
- out_edge_list.clear_and_dispose(delete_disposer());
- }
- };
-
- struct delete_disposer {
- template<typename T> void operator()(const T *d) const { delete d; }
- };
-
- struct in_edge_disposer {
- void operator()(edge_node *e) const {
- /* remove from source's out edge list before deleting */
- vertex_node *u = e->source;
- u->out_edge_list.erase(u->out_edge_list.iterator_to(*e));
- delete e;
- }
- };
-
- struct out_edge_disposer {
- void operator()(edge_node *e) const {
- /* remove from target's in edge list before deleting */
- vertex_node *v = e->target;
- v->in_edge_list.erase(v->in_edge_list.iterator_to(*e));
- delete e;
- }
- };
-
- using vertices_list_type
- = boost::intrusive::list<vertex_node,
- boost::intrusive::base_hook<boost::intrusive::list_base_hook<> > >;
-
- vertices_list_type vertices_list;
-
-protected: /* to allow renumbering */
- static const size_t N_SPECIAL_VERTICES = 0; /* override in derived class */
- size_t next_vertex_index = 0;
- size_t next_edge_index = 0;
-
-private:
- size_t graph_edge_count = 0; /* maintained explicitly as we have no global
- edge list */
-
- u64a next_serial = 0;
- u64a new_serial() {
- u64a serial = next_serial++;
- if (!next_serial) {
- /* if we have created enough graph edges/vertices to overflow a u64a
- * we must have spent close to an eternity adding to this graph so
- * something must have gone very wrong and we will not be producing
- * a final bytecode in a reasonable amount of time. Or, more likely,
- * the next_serial value has become corrupt. */
- throw std::overflow_error("too many graph edges/vertices created");
- }
- return serial;
- }
-public:
- using vertex_descriptor = graph_detail::vertex_descriptor<ue2_graph>;
- using edge_descriptor = graph_detail::edge_descriptor<ue2_graph>;
- friend vertex_descriptor;
- friend edge_descriptor;
-
- using vertices_size_type = typename vertices_list_type::size_type;
- using degree_size_type
- = typename vertex_edge_list<out_edge_hook>::size_type;
- using edges_size_type = size_t;
-
- using vertex_property_type = VertexPropertyType;
- using edge_property_type = EdgePropertyType;
-
- using graph_bundled = boost::no_property;
- using vertex_bundled = VertexPropertyType;
- using edge_bundled = EdgePropertyType;
-
-private:
- /* Note: apparently, nested class templates cannot be fully specialised but
- * they can be partially specialised. Sigh, ... */
- template<typename BundleType, typename dummy = void>
- struct bundle_key_type {
- };
-
- template<typename dummy>
- struct bundle_key_type<VertexPropertyType, dummy> {
- using type = vertex_descriptor;
- };
-
- template<typename dummy>
- struct bundle_key_type<EdgePropertyType, dummy> {
- using type = edge_descriptor;
- };
-
-public:
- class out_edge_iterator : public boost::iterator_adaptor<
- out_edge_iterator,
- typename vertex_edge_list<out_edge_hook>::const_iterator,
- edge_descriptor,
- boost::bidirectional_traversal_tag,
- edge_descriptor> {
- using super = typename out_edge_iterator::iterator_adaptor_;
- public:
- out_edge_iterator() : super() { }
- explicit out_edge_iterator(
- typename vertex_edge_list<out_edge_hook>::const_iterator it)
- : super(it) { }
- edge_descriptor dereference() const {
- /* :( const_cast makes me sad but constness is defined by the graph
- * parameter of bgl api calls */
- return edge_descriptor(const_cast<edge_node *>(&*super::base()));
- }
- };
-
- class in_edge_iterator : public boost::iterator_adaptor<
- in_edge_iterator,
- typename vertex_edge_list<in_edge_hook>::const_iterator,
- edge_descriptor,
- boost::bidirectional_traversal_tag,
- edge_descriptor> {
- using super = typename in_edge_iterator::iterator_adaptor_;
- public:
- in_edge_iterator() : super() { }
- explicit in_edge_iterator(
- typename vertex_edge_list<in_edge_hook>::const_iterator it)
- : super(it) { }
- edge_descriptor dereference() const {
- /* :( const_cast makes me sad but constness is defined by the graph
- * parameter of bgl api calls */
- return edge_descriptor(const_cast<edge_node *>(&*super::base()));
- }
- };
-
- class adjacency_iterator : public boost::iterator_adaptor<
- adjacency_iterator,
- out_edge_iterator,
- vertex_descriptor,
- boost::bidirectional_traversal_tag,
- vertex_descriptor> {
- using super = typename adjacency_iterator::iterator_adaptor_;
- public:
- adjacency_iterator(out_edge_iterator a) : super(std::move(a)) { }
- adjacency_iterator() { }
-
- vertex_descriptor dereference() const {
- return vertex_descriptor(super::base()->p->target);
- }
- };
-
- class inv_adjacency_iterator : public boost::iterator_adaptor<
- inv_adjacency_iterator,
- in_edge_iterator,
- vertex_descriptor,
- boost::bidirectional_traversal_tag,
- vertex_descriptor> {
- using super = typename inv_adjacency_iterator::iterator_adaptor_;
- public:
- inv_adjacency_iterator(in_edge_iterator a) : super(std::move(a)) { }
- inv_adjacency_iterator() { }
-
- vertex_descriptor dereference() const {
- return vertex_descriptor(super::base()->p->source);
- }
- };
-
- class vertex_iterator : public boost::iterator_adaptor<
- vertex_iterator,
- typename vertices_list_type::const_iterator,
- vertex_descriptor,
- boost::bidirectional_traversal_tag,
- vertex_descriptor> {
- using super = typename vertex_iterator::iterator_adaptor_;
- public:
- vertex_iterator() : super() { }
- explicit vertex_iterator(typename vertices_list_type::const_iterator it)
- : super(it) { }
- vertex_descriptor dereference() const {
- /* :( const_cast makes me sad but constness is defined by the graph
- * parameter of bgl api calls */
- return vertex_descriptor(
- const_cast<vertex_node *>(&*super::base()));
- }
- };
-
- class edge_iterator : public boost::iterator_facade<
- edge_iterator,
- edge_descriptor,
- boost::forward_traversal_tag, /* TODO: make bidi */
- edge_descriptor> {
- public:
- using main_base_iter_type = vertex_iterator;
- using aux_base_iter_type = out_edge_iterator;
-
- edge_iterator(main_base_iter_type b, main_base_iter_type e)
- : main(std::move(b)), main_end(std::move(e)) {
- if (main == main_end) {
- return;
- }
- std::tie(aux, aux_end) = out_edges_impl(*main);
- while (aux == aux_end) {
- ++main;
- if (main == main_end) {
- break;
- }
- std::tie(aux, aux_end) = out_edges_impl(*main);
- }
- }
- edge_iterator() { }
-
- friend class boost::iterator_core_access;
- void increment() {
- ++aux;
- while (aux == aux_end) {
- ++main;
- if (main == main_end) {
- break;
- }
- std::tie(aux, aux_end) = out_edges_impl(*main);
- }
- }
- bool equal(const edge_iterator &other) const {
- return main == other.main && (main == main_end || aux == other.aux);
- }
- edge_descriptor dereference() const {
- return *aux;
- }
-
- main_base_iter_type main;
- main_base_iter_type main_end;
- aux_base_iter_type aux;
- aux_base_iter_type aux_end;
- };
-
-public:
- static
- vertex_descriptor null_vertex() { return vertex_descriptor(); }
-
- vertex_descriptor add_vertex_impl() {
- vertex_node *v = new vertex_node(new_serial());
- v->props.index = next_vertex_index++;
- vertices_list.push_back(*v);
- return vertex_descriptor(v);
- }
-
- void remove_vertex_impl(vertex_descriptor v) {
- vertex_node *vv = v.raw();
- assert(vv->in_edge_list.empty());
- assert(vv->out_edge_list.empty());
- vertices_list.erase_and_dispose(vertices_list.iterator_to(*vv),
- delete_disposer());
- }
-
- void clear_in_edges_impl(vertex_descriptor v) {
- graph_edge_count -= v.raw()->in_edge_list.size();
- v.raw()->in_edge_list.clear_and_dispose(in_edge_disposer());
- }
-
- void clear_out_edges_impl(vertex_descriptor v) {
- graph_edge_count -= v.raw()->out_edge_list.size();
- v.raw()->out_edge_list.clear_and_dispose(out_edge_disposer());
- }
-
- /* IncidenceGraph concept functions */
-
- static
- vertex_descriptor source_impl(edge_descriptor e) {
- return vertex_descriptor(e.raw()->source);
- }
-
- static
- vertex_descriptor target_impl(edge_descriptor e) {
- return vertex_descriptor(e.raw()->target);
- }
-
- static
- degree_size_type out_degree_impl(vertex_descriptor v) {
- return v.raw()->out_edge_list.size();
- }
-
- static
- std::pair<out_edge_iterator, out_edge_iterator>
- out_edges_impl(vertex_descriptor v) {
- return {out_edge_iterator(v.raw()->out_edge_list.begin()),
- out_edge_iterator(v.raw()->out_edge_list.end())};
- }
-
- /* BidirectionalGraph concept functions */
-
- static
- degree_size_type in_degree_impl(vertex_descriptor v) {
- return v.raw()->in_edge_list.size();
- }
-
- static
- std::pair<in_edge_iterator, in_edge_iterator>
- in_edges_impl(vertex_descriptor v) {
- return {in_edge_iterator(v.raw()->in_edge_list.begin()),
- in_edge_iterator(v.raw()->in_edge_list.end())};
- }
-
- /* Note: this is defined so that self loops are counted twice - which may or
- * may not be what you want. Actually, you probably don't want this at
- * all. */
- static
- degree_size_type degree_impl(vertex_descriptor v) {
- return in_degree_impl(v) + out_degree_impl(v);
- }
-
- /* AdjacencyList concept functions */
-
- static
- std::pair<adjacency_iterator, adjacency_iterator>
- adjacent_vertices_impl(vertex_descriptor v) {
- auto out_edge_its = out_edges_impl(v);
- return {adjacency_iterator(out_edge_its.first),
- adjacency_iterator(out_edge_its.second)};
- }
-
- /* AdjacencyMatrix concept functions
- * (Note: complexity guarantee is not met) */
-
- std::pair<edge_descriptor, bool> edge_impl(vertex_descriptor u,
- vertex_descriptor v) const {
- if (in_degree_impl(v) < out_degree_impl(u)) {
- for (const edge_descriptor &e : in_edges_range(v, *this)) {
- if (source_impl(e) == u) {
- return {e, true};
- }
- }
- } else {
- for (const edge_descriptor &e : out_edges_range(u, *this)) {
- if (target_impl(e) == v) {
- return {e, true};
- }
- }
- }
-
- return {edge_descriptor(), false};
- }
-
- /* Misc functions that don't actually seem to belong to a formal BGL
- concept. */
- static
- edge_descriptor null_edge() { return edge_descriptor(); }
-
- static
- std::pair<inv_adjacency_iterator, inv_adjacency_iterator>
- inv_adjacent_vertices_impl(vertex_descriptor v) {
- auto in_edge_its = in_edges_impl(v);
- return {inv_adjacency_iterator(in_edge_its.first),
- inv_adjacency_iterator(in_edge_its.second)};
- }
-
- /* MutableGraph concept functions */
-
- std::pair<edge_descriptor, bool>
- add_edge_impl(vertex_descriptor u, vertex_descriptor v) {
- bool added = true; /* we always allow parallel edges */
- edge_node *e = new edge_node(new_serial());
- e->source = u.raw();
- e->target = v.raw();
- e->props.index = next_edge_index++;
-
- u.raw()->out_edge_list.push_back(*e);
- v.raw()->in_edge_list.push_back(*e);
-
- graph_edge_count++;
- return {edge_descriptor(e), added};
- }
-
- void remove_edge_impl(edge_descriptor e) {
- graph_edge_count--;
-
- vertex_node *u = e.raw()->source;
- vertex_node *v = e.raw()->target;
-
- v->in_edge_list.erase(v->in_edge_list.iterator_to(*e.raw()));
- u->out_edge_list.erase(u->out_edge_list.iterator_to(*e.raw()));
-
- delete e.raw();
- }
-
- template<class Predicate>
- void remove_out_edge_if_impl(vertex_descriptor v, Predicate pred) {
- out_edge_iterator it, ite;
- std::tie(it, ite) = out_edges_impl(v);
- while (it != ite) {
- auto jt = it;
- ++it;
- if (pred(*jt)) {
- this->remove_edge_impl(*jt);
- }
- }
- }
-
- template<class Predicate>
- void remove_in_edge_if_impl(vertex_descriptor v, Predicate pred) {
- in_edge_iterator it, ite;
- std::tie(it, ite) = in_edges_impl(v);
- while (it != ite) {
- auto jt = it;
- ++it;
- if (pred(*jt)) {
- remove_edge_impl(*jt);
- }
- }
- }
-
- template<class Predicate>
- void remove_edge_if_impl(Predicate pred) {
- edge_iterator it, ite;
- std::tie(it, ite) = edges_impl();
- while (it != ite) {
- auto jt = it;
- ++it;
- if (pred(*jt)) {
- remove_edge_impl(*jt);
- }
- }
- }
-
-private:
- /* GCC 4.8 has bugs with lambdas in templated friend functions, so: */
- struct source_match {
- explicit source_match(const vertex_descriptor &uu) : u(uu) { }
- bool operator()(edge_descriptor e) const { return source_impl(e) == u; }
- const vertex_descriptor &u;
- };
-
- struct target_match {
- explicit target_match(const vertex_descriptor &vv) : v(vv) { }
- bool operator()(edge_descriptor e) const { return target_impl(e) == v; }
- const vertex_descriptor &v;
- };
-public:
- /* Note: (u,v) variant needs to remove all (parallel) edges between (u,v).
- *
- * The edge_descriptor version should be strongly preferred if the
- * edge_descriptor is available.
- */
- void remove_edge_impl(const vertex_descriptor &u,
- const vertex_descriptor &v) {
- if (in_degree_impl(v) < out_degree_impl(u)) {
- remove_in_edge_if_impl(v, source_match(u));
- } else {
- remove_out_edge_if_impl(u, target_match(v));
- }
- }
-
- /* VertexListGraph concept functions */
- vertices_size_type num_vertices_impl() const {
- return vertices_list.size();
- }
-
- std::pair<vertex_iterator, vertex_iterator> vertices_impl() const {
- return {vertex_iterator(vertices_list.begin()),
- vertex_iterator(vertices_list.end())};
- }
-
- /* EdgeListGraph concept functions (aside from those in IncidenceGraph) */
-
- edges_size_type num_edges_impl() const {
- return graph_edge_count;
- }
-
- std::pair<edge_iterator, edge_iterator> edges_impl() const {
- vertex_iterator vi, ve;
- std::tie(vi, ve) = vertices_impl();
-
- return {edge_iterator(vi, ve), edge_iterator(ve, ve)};
- }
-
- /* bundled properties functions */
-
- vertex_property_type &operator[](vertex_descriptor v) {
- return v.raw()->props;
- }
-
- const vertex_property_type &operator[](vertex_descriptor v) const {
- return v.raw()->props;
- }
-
- edge_property_type &operator[](edge_descriptor e) {
- return e.raw()->props;
- }
-
- const edge_property_type &operator[](edge_descriptor e) const {
- return e.raw()->props;
- }
-
- /* PropertyGraph concept functions & helpers */
-
- template<typename R, typename P_of>
- struct prop_map : public boost::put_get_helper<R, prop_map<R, P_of> > {
- using value_type = typename std::decay<R>::type;
- using reference = R;
- using key_type = typename bundle_key_type<P_of>::type;
-
- typedef typename boost::lvalue_property_map_tag category;
-
- prop_map(value_type P_of::*m_in) : member(m_in) { }
-
- reference operator[](key_type k) const {
- return k.raw()->props.*member;
- }
- reference operator()(key_type k) const { return (*this)[k]; }
-
- private:
- value_type P_of::*member;
- };
-
- template<typename R>
- struct prop_map_all : public boost::put_get_helper<R, prop_map_all<R> > {
- using value_type = typename std::decay<R>::type;
- using reference = R;
- using key_type = typename bundle_key_type<value_type>::type;
-
- typedef typename boost::lvalue_property_map_tag category;
-
- reference operator[](key_type k) const {
- return k.raw()->props;
- }
- reference operator()(key_type k) const { return (*this)[k]; }
- };
-
- template<typename P_type, typename P_of>
- friend
- prop_map<P_type &, P_of> get(P_type P_of::*t, Graph &) {
- return prop_map<P_type &, P_of>(t);
- }
-
- template<typename P_type, typename P_of>
- friend
- prop_map<const P_type &, P_of> get(P_type P_of::*t, const Graph &) {
- return prop_map<const P_type &, P_of>(t);
- }
-
- /* We can't seem to use auto/decltype returns here as it seems that the
- * templated member functions are not yet visible when the compile is
- * evaluating the decltype for the return value. We could probably work
- * around it by making this a dummy templated function. */
- friend
- prop_map<size_t &, VertexPropertyType>
- get(boost::vertex_index_t, Graph &g) {
- return get(&VertexPropertyType::index, g);
- }
-
- friend
- prop_map<const size_t &, VertexPropertyType>
- get(boost::vertex_index_t, const Graph &g) {
- return get(&VertexPropertyType::index, g);
- }
-
- friend
- prop_map<size_t &, EdgePropertyType>
- get(boost::edge_index_t, Graph &g) {
- return get(&EdgePropertyType::index, g);
- }
-
- friend
- prop_map<const size_t &, EdgePropertyType>
- get(boost::edge_index_t, const Graph &g) {
- return get(&EdgePropertyType::index, g);
- }
-
- friend
- prop_map_all<VertexPropertyType &> get(boost::vertex_all_t, Graph &) {
- return {};
- }
-
- friend
- prop_map_all<const VertexPropertyType &> get(boost::vertex_all_t,
- const Graph &) {
- return {};
- }
-
- friend
- prop_map_all<EdgePropertyType &> get(boost::edge_all_t, Graph &) {
- return {};
- }
-
- friend
- prop_map_all<const EdgePropertyType &> get(boost::edge_all_t,
- const Graph &) {
- return {};
- }
-
- friend
- prop_map_all<VertexPropertyType &> get(boost::vertex_bundle_t, Graph &) {
- return {};
- }
-
- friend
- prop_map_all<const VertexPropertyType &> get(boost::vertex_bundle_t,
- const Graph &) {
- return {};
- }
-
- friend
- prop_map_all<EdgePropertyType &> get(boost::edge_bundle_t, Graph &) {
- return {};
- }
-
- friend
- prop_map_all<const EdgePropertyType &> get(boost::edge_bundle_t,
- const Graph &) {
- return {};
- }
-
- template<typename Prop, typename K>
- friend
- auto get(Prop p, Graph &g, K key) -> decltype(get(p, g)[key]) {
- return get(p, g)[key];
- }
-
- template<typename Prop, typename K>
- friend
- auto get(Prop p, const Graph &g, K key) -> decltype(get(p, g)[key]) {
- return get(p, g)[key];
- }
-
- template<typename Prop, typename K, typename V>
- friend
- void put(Prop p, Graph &g, K key, const V &value) {
- get(p, g)[key] = value;
- }
-
- /* MutablePropertyGraph concept functions */
-
- /* Note: add_vertex(g, vp) allocates a next index value for the vertex
- * rather than using the index in vp. i.e., except for in rare coincidences:
- * g[add_vertex(g, vp)].index != vp.index
- */
- vertex_descriptor add_vertex_impl(const VertexPropertyType &vp) {
- vertex_descriptor v = add_vertex_impl();
- auto i = (*this)[v].index;
- (*this)[v] = vp;
- (*this)[v].index = i;
-
- return v;
- }
-
- /* Note: add_edge(u, v, g, vp) allocates a next index value for the edge
- * rather than using the index in ep. i.e., except for in rare coincidences:
- * g[add_edge(u, v, g, ep)].index != ep.index
- */
- std::pair<edge_descriptor, bool>
- add_edge_impl(vertex_descriptor u, vertex_descriptor v,
- const EdgePropertyType &ep) {
- auto e = add_edge_impl(u, v);
- auto i = (*this)[e.first].index;
- (*this)[e.first] = ep;
- (*this)[e.first].index = i;
-
- return e;
- }
-
- /* End MutablePropertyGraph */
-
- /** Pack the edge index into a contiguous range [ 0, num_edges(g) ). */
- void renumber_edges_impl() {
- next_edge_index = 0;
- edge_iterator it;
- edge_iterator ite;
- for (std::tie(it, ite) = edges_impl(); it != ite; ++it) {
- (*this)[*it].index = next_edge_index++;
- }
- }
-
- /** Pack the vertex index into a contiguous range [ 0, num_vertices(g) ).
- * Vertices with indices less than N_SPECIAL_VERTICES are not renumbered.
- */
- void renumber_vertices_impl() {
- DEBUG_PRINTF("renumbering above %zu\n", Graph::N_SPECIAL_VERTICES);
- next_vertex_index = Graph::N_SPECIAL_VERTICES;
- vertex_iterator it;
- vertex_iterator ite;
- for (std::tie(it, ite) = vertices_impl(); it != ite; ++it) {
- if ((*this)[*it].index < Graph::N_SPECIAL_VERTICES) {
- continue;
- }
-
- (*this)[*it].index = next_vertex_index++;
- }
- }
-
- /** Returns what the next allocated vertex index will be. This is an upper
- * on the values of index for vertices (vertex removal means that there may
- * be gaps). */
- vertices_size_type vertex_index_upper_bound_impl() const {
- return next_vertex_index;
- }
-
- /** Returns what the next allocated edge index will be. This is an upper on
- * the values of index for edges (edge removal means that there may be
- * gaps). */
- vertices_size_type edge_index_upper_bound_impl() const {
- return next_edge_index;
- }
-
- using directed_category = boost::directed_tag;
- using edge_parallel_category = boost::allow_parallel_edge_tag;
- struct traversal_category :
- public virtual boost::bidirectional_graph_tag,
- public virtual boost::adjacency_graph_tag,
- public virtual boost::vertex_list_graph_tag,
- public virtual boost::edge_list_graph_tag { };
-
- ue2_graph() = default;
-
- ue2_graph(ue2_graph &&old)
- : next_vertex_index(old.next_vertex_index),
- next_edge_index(old.next_edge_index),
- graph_edge_count(old.graph_edge_count),
- next_serial(old.next_serial) {
- using std::swap;
- swap(vertices_list, old.vertices_list);
- }
-
- ue2_graph &operator=(ue2_graph &&old) {
- next_vertex_index = old.next_vertex_index;
- next_edge_index = old.next_edge_index;
- graph_edge_count = old.graph_edge_count;
- next_serial = old.next_serial;
- using std::swap;
- swap(vertices_list, old.vertices_list);
- return *this;
- }
-
- ~ue2_graph() {
- vertices_list.clear_and_dispose(delete_disposer());
- }
-};
-
+ vertex_edge_list<out_edge_hook> out_edge_list;
+
+ /* The destructor only frees memory owned by the vertex and will leave
+ * the neighbour's edges in a bad state. If a vertex is being removed
+ * (rather than the graph being destroyed), then the more gentle clean
+ * up of clear_vertex() is required to be called first */
+ ~vertex_node() {
+ out_edge_list.clear_and_dispose(delete_disposer());
+ }
+ };
+
+ struct delete_disposer {
+ template<typename T> void operator()(const T *d) const { delete d; }
+ };
+
+ struct in_edge_disposer {
+ void operator()(edge_node *e) const {
+ /* remove from source's out edge list before deleting */
+ vertex_node *u = e->source;
+ u->out_edge_list.erase(u->out_edge_list.iterator_to(*e));
+ delete e;
+ }
+ };
+
+ struct out_edge_disposer {
+ void operator()(edge_node *e) const {
+ /* remove from target's in edge list before deleting */
+ vertex_node *v = e->target;
+ v->in_edge_list.erase(v->in_edge_list.iterator_to(*e));
+ delete e;
+ }
+ };
+
+ using vertices_list_type
+ = boost::intrusive::list<vertex_node,
+ boost::intrusive::base_hook<boost::intrusive::list_base_hook<> > >;
+
+ vertices_list_type vertices_list;
+
+protected: /* to allow renumbering */
+ static const size_t N_SPECIAL_VERTICES = 0; /* override in derived class */
+ size_t next_vertex_index = 0;
+ size_t next_edge_index = 0;
+
+private:
+ size_t graph_edge_count = 0; /* maintained explicitly as we have no global
+ edge list */
+
+ u64a next_serial = 0;
+ u64a new_serial() {
+ u64a serial = next_serial++;
+ if (!next_serial) {
+ /* if we have created enough graph edges/vertices to overflow a u64a
+ * we must have spent close to an eternity adding to this graph so
+ * something must have gone very wrong and we will not be producing
+ * a final bytecode in a reasonable amount of time. Or, more likely,
+ * the next_serial value has become corrupt. */
+ throw std::overflow_error("too many graph edges/vertices created");
+ }
+ return serial;
+ }
+public:
+ using vertex_descriptor = graph_detail::vertex_descriptor<ue2_graph>;
+ using edge_descriptor = graph_detail::edge_descriptor<ue2_graph>;
+ friend vertex_descriptor;
+ friend edge_descriptor;
+
+ using vertices_size_type = typename vertices_list_type::size_type;
+ using degree_size_type
+ = typename vertex_edge_list<out_edge_hook>::size_type;
+ using edges_size_type = size_t;
+
+ using vertex_property_type = VertexPropertyType;
+ using edge_property_type = EdgePropertyType;
+
+ using graph_bundled = boost::no_property;
+ using vertex_bundled = VertexPropertyType;
+ using edge_bundled = EdgePropertyType;
+
+private:
+ /* Note: apparently, nested class templates cannot be fully specialised but
+ * they can be partially specialised. Sigh, ... */
+ template<typename BundleType, typename dummy = void>
+ struct bundle_key_type {
+ };
+
+ template<typename dummy>
+ struct bundle_key_type<VertexPropertyType, dummy> {
+ using type = vertex_descriptor;
+ };
+
+ template<typename dummy>
+ struct bundle_key_type<EdgePropertyType, dummy> {
+ using type = edge_descriptor;
+ };
+
+public:
+ class out_edge_iterator : public boost::iterator_adaptor<
+ out_edge_iterator,
+ typename vertex_edge_list<out_edge_hook>::const_iterator,
+ edge_descriptor,
+ boost::bidirectional_traversal_tag,
+ edge_descriptor> {
+ using super = typename out_edge_iterator::iterator_adaptor_;
+ public:
+ out_edge_iterator() : super() { }
+ explicit out_edge_iterator(
+ typename vertex_edge_list<out_edge_hook>::const_iterator it)
+ : super(it) { }
+ edge_descriptor dereference() const {
+ /* :( const_cast makes me sad but constness is defined by the graph
+ * parameter of bgl api calls */
+ return edge_descriptor(const_cast<edge_node *>(&*super::base()));
+ }
+ };
+
+ class in_edge_iterator : public boost::iterator_adaptor<
+ in_edge_iterator,
+ typename vertex_edge_list<in_edge_hook>::const_iterator,
+ edge_descriptor,
+ boost::bidirectional_traversal_tag,
+ edge_descriptor> {
+ using super = typename in_edge_iterator::iterator_adaptor_;
+ public:
+ in_edge_iterator() : super() { }
+ explicit in_edge_iterator(
+ typename vertex_edge_list<in_edge_hook>::const_iterator it)
+ : super(it) { }
+ edge_descriptor dereference() const {
+ /* :( const_cast makes me sad but constness is defined by the graph
+ * parameter of bgl api calls */
+ return edge_descriptor(const_cast<edge_node *>(&*super::base()));
+ }
+ };
+
+ class adjacency_iterator : public boost::iterator_adaptor<
+ adjacency_iterator,
+ out_edge_iterator,
+ vertex_descriptor,
+ boost::bidirectional_traversal_tag,
+ vertex_descriptor> {
+ using super = typename adjacency_iterator::iterator_adaptor_;
+ public:
+ adjacency_iterator(out_edge_iterator a) : super(std::move(a)) { }
+ adjacency_iterator() { }
+
+ vertex_descriptor dereference() const {
+ return vertex_descriptor(super::base()->p->target);
+ }
+ };
+
+ class inv_adjacency_iterator : public boost::iterator_adaptor<
+ inv_adjacency_iterator,
+ in_edge_iterator,
+ vertex_descriptor,
+ boost::bidirectional_traversal_tag,
+ vertex_descriptor> {
+ using super = typename inv_adjacency_iterator::iterator_adaptor_;
+ public:
+ inv_adjacency_iterator(in_edge_iterator a) : super(std::move(a)) { }
+ inv_adjacency_iterator() { }
+
+ vertex_descriptor dereference() const {
+ return vertex_descriptor(super::base()->p->source);
+ }
+ };
+
+ class vertex_iterator : public boost::iterator_adaptor<
+ vertex_iterator,
+ typename vertices_list_type::const_iterator,
+ vertex_descriptor,
+ boost::bidirectional_traversal_tag,
+ vertex_descriptor> {
+ using super = typename vertex_iterator::iterator_adaptor_;
+ public:
+ vertex_iterator() : super() { }
+ explicit vertex_iterator(typename vertices_list_type::const_iterator it)
+ : super(it) { }
+ vertex_descriptor dereference() const {
+ /* :( const_cast makes me sad but constness is defined by the graph
+ * parameter of bgl api calls */
+ return vertex_descriptor(
+ const_cast<vertex_node *>(&*super::base()));
+ }
+ };
+
+ class edge_iterator : public boost::iterator_facade<
+ edge_iterator,
+ edge_descriptor,
+ boost::forward_traversal_tag, /* TODO: make bidi */
+ edge_descriptor> {
+ public:
+ using main_base_iter_type = vertex_iterator;
+ using aux_base_iter_type = out_edge_iterator;
+
+ edge_iterator(main_base_iter_type b, main_base_iter_type e)
+ : main(std::move(b)), main_end(std::move(e)) {
+ if (main == main_end) {
+ return;
+ }
+ std::tie(aux, aux_end) = out_edges_impl(*main);
+ while (aux == aux_end) {
+ ++main;
+ if (main == main_end) {
+ break;
+ }
+ std::tie(aux, aux_end) = out_edges_impl(*main);
+ }
+ }
+ edge_iterator() { }
+
+ friend class boost::iterator_core_access;
+ void increment() {
+ ++aux;
+ while (aux == aux_end) {
+ ++main;
+ if (main == main_end) {
+ break;
+ }
+ std::tie(aux, aux_end) = out_edges_impl(*main);
+ }
+ }
+ bool equal(const edge_iterator &other) const {
+ return main == other.main && (main == main_end || aux == other.aux);
+ }
+ edge_descriptor dereference() const {
+ return *aux;
+ }
+
+ main_base_iter_type main;
+ main_base_iter_type main_end;
+ aux_base_iter_type aux;
+ aux_base_iter_type aux_end;
+ };
+
+public:
+ static
+ vertex_descriptor null_vertex() { return vertex_descriptor(); }
+
+ vertex_descriptor add_vertex_impl() {
+ vertex_node *v = new vertex_node(new_serial());
+ v->props.index = next_vertex_index++;
+ vertices_list.push_back(*v);
+ return vertex_descriptor(v);
+ }
+
+ void remove_vertex_impl(vertex_descriptor v) {
+ vertex_node *vv = v.raw();
+ assert(vv->in_edge_list.empty());
+ assert(vv->out_edge_list.empty());
+ vertices_list.erase_and_dispose(vertices_list.iterator_to(*vv),
+ delete_disposer());
+ }
+
+ void clear_in_edges_impl(vertex_descriptor v) {
+ graph_edge_count -= v.raw()->in_edge_list.size();
+ v.raw()->in_edge_list.clear_and_dispose(in_edge_disposer());
+ }
+
+ void clear_out_edges_impl(vertex_descriptor v) {
+ graph_edge_count -= v.raw()->out_edge_list.size();
+ v.raw()->out_edge_list.clear_and_dispose(out_edge_disposer());
+ }
+
+ /* IncidenceGraph concept functions */
+
+ static
+ vertex_descriptor source_impl(edge_descriptor e) {
+ return vertex_descriptor(e.raw()->source);
+ }
+
+ static
+ vertex_descriptor target_impl(edge_descriptor e) {
+ return vertex_descriptor(e.raw()->target);
+ }
+
+ static
+ degree_size_type out_degree_impl(vertex_descriptor v) {
+ return v.raw()->out_edge_list.size();
+ }
+
+ static
+ std::pair<out_edge_iterator, out_edge_iterator>
+ out_edges_impl(vertex_descriptor v) {
+ return {out_edge_iterator(v.raw()->out_edge_list.begin()),
+ out_edge_iterator(v.raw()->out_edge_list.end())};
+ }
+
+ /* BidirectionalGraph concept functions */
+
+ static
+ degree_size_type in_degree_impl(vertex_descriptor v) {
+ return v.raw()->in_edge_list.size();
+ }
+
+ static
+ std::pair<in_edge_iterator, in_edge_iterator>
+ in_edges_impl(vertex_descriptor v) {
+ return {in_edge_iterator(v.raw()->in_edge_list.begin()),
+ in_edge_iterator(v.raw()->in_edge_list.end())};
+ }
+
+ /* Note: this is defined so that self loops are counted twice - which may or
+ * may not be what you want. Actually, you probably don't want this at
+ * all. */
+ static
+ degree_size_type degree_impl(vertex_descriptor v) {
+ return in_degree_impl(v) + out_degree_impl(v);
+ }
+
+ /* AdjacencyList concept functions */
+
+ static
+ std::pair<adjacency_iterator, adjacency_iterator>
+ adjacent_vertices_impl(vertex_descriptor v) {
+ auto out_edge_its = out_edges_impl(v);
+ return {adjacency_iterator(out_edge_its.first),
+ adjacency_iterator(out_edge_its.second)};
+ }
+
+ /* AdjacencyMatrix concept functions
+ * (Note: complexity guarantee is not met) */
+
+ std::pair<edge_descriptor, bool> edge_impl(vertex_descriptor u,
+ vertex_descriptor v) const {
+ if (in_degree_impl(v) < out_degree_impl(u)) {
+ for (const edge_descriptor &e : in_edges_range(v, *this)) {
+ if (source_impl(e) == u) {
+ return {e, true};
+ }
+ }
+ } else {
+ for (const edge_descriptor &e : out_edges_range(u, *this)) {
+ if (target_impl(e) == v) {
+ return {e, true};
+ }
+ }
+ }
+
+ return {edge_descriptor(), false};
+ }
+
+ /* Misc functions that don't actually seem to belong to a formal BGL
+ concept. */
+ static
+ edge_descriptor null_edge() { return edge_descriptor(); }
+
+ static
+ std::pair<inv_adjacency_iterator, inv_adjacency_iterator>
+ inv_adjacent_vertices_impl(vertex_descriptor v) {
+ auto in_edge_its = in_edges_impl(v);
+ return {inv_adjacency_iterator(in_edge_its.first),
+ inv_adjacency_iterator(in_edge_its.second)};
+ }
+
+ /* MutableGraph concept functions */
+
+ std::pair<edge_descriptor, bool>
+ add_edge_impl(vertex_descriptor u, vertex_descriptor v) {
+ bool added = true; /* we always allow parallel edges */
+ edge_node *e = new edge_node(new_serial());
+ e->source = u.raw();
+ e->target = v.raw();
+ e->props.index = next_edge_index++;
+
+ u.raw()->out_edge_list.push_back(*e);
+ v.raw()->in_edge_list.push_back(*e);
+
+ graph_edge_count++;
+ return {edge_descriptor(e), added};
+ }
+
+ void remove_edge_impl(edge_descriptor e) {
+ graph_edge_count--;
+
+ vertex_node *u = e.raw()->source;
+ vertex_node *v = e.raw()->target;
+
+ v->in_edge_list.erase(v->in_edge_list.iterator_to(*e.raw()));
+ u->out_edge_list.erase(u->out_edge_list.iterator_to(*e.raw()));
+
+ delete e.raw();
+ }
+
+ template<class Predicate>
+ void remove_out_edge_if_impl(vertex_descriptor v, Predicate pred) {
+ out_edge_iterator it, ite;
+ std::tie(it, ite) = out_edges_impl(v);
+ while (it != ite) {
+ auto jt = it;
+ ++it;
+ if (pred(*jt)) {
+ this->remove_edge_impl(*jt);
+ }
+ }
+ }
+
+ template<class Predicate>
+ void remove_in_edge_if_impl(vertex_descriptor v, Predicate pred) {
+ in_edge_iterator it, ite;
+ std::tie(it, ite) = in_edges_impl(v);
+ while (it != ite) {
+ auto jt = it;
+ ++it;
+ if (pred(*jt)) {
+ remove_edge_impl(*jt);
+ }
+ }
+ }
+
+ template<class Predicate>
+ void remove_edge_if_impl(Predicate pred) {
+ edge_iterator it, ite;
+ std::tie(it, ite) = edges_impl();
+ while (it != ite) {
+ auto jt = it;
+ ++it;
+ if (pred(*jt)) {
+ remove_edge_impl(*jt);
+ }
+ }
+ }
+
+private:
+ /* GCC 4.8 has bugs with lambdas in templated friend functions, so: */
+ struct source_match {
+ explicit source_match(const vertex_descriptor &uu) : u(uu) { }
+ bool operator()(edge_descriptor e) const { return source_impl(e) == u; }
+ const vertex_descriptor &u;
+ };
+
+ struct target_match {
+ explicit target_match(const vertex_descriptor &vv) : v(vv) { }
+ bool operator()(edge_descriptor e) const { return target_impl(e) == v; }
+ const vertex_descriptor &v;
+ };
+public:
+ /* Note: (u,v) variant needs to remove all (parallel) edges between (u,v).
+ *
+ * The edge_descriptor version should be strongly preferred if the
+ * edge_descriptor is available.
+ */
+ void remove_edge_impl(const vertex_descriptor &u,
+ const vertex_descriptor &v) {
+ if (in_degree_impl(v) < out_degree_impl(u)) {
+ remove_in_edge_if_impl(v, source_match(u));
+ } else {
+ remove_out_edge_if_impl(u, target_match(v));
+ }
+ }
+
+ /* VertexListGraph concept functions */
+ vertices_size_type num_vertices_impl() const {
+ return vertices_list.size();
+ }
+
+ std::pair<vertex_iterator, vertex_iterator> vertices_impl() const {
+ return {vertex_iterator(vertices_list.begin()),
+ vertex_iterator(vertices_list.end())};
+ }
+
+ /* EdgeListGraph concept functions (aside from those in IncidenceGraph) */
+
+ edges_size_type num_edges_impl() const {
+ return graph_edge_count;
+ }
+
+ std::pair<edge_iterator, edge_iterator> edges_impl() const {
+ vertex_iterator vi, ve;
+ std::tie(vi, ve) = vertices_impl();
+
+ return {edge_iterator(vi, ve), edge_iterator(ve, ve)};
+ }
+
+ /* bundled properties functions */
+
+ vertex_property_type &operator[](vertex_descriptor v) {
+ return v.raw()->props;
+ }
+
+ const vertex_property_type &operator[](vertex_descriptor v) const {
+ return v.raw()->props;
+ }
+
+ edge_property_type &operator[](edge_descriptor e) {
+ return e.raw()->props;
+ }
+
+ const edge_property_type &operator[](edge_descriptor e) const {
+ return e.raw()->props;
+ }
+
+ /* PropertyGraph concept functions & helpers */
+
+ template<typename R, typename P_of>
+ struct prop_map : public boost::put_get_helper<R, prop_map<R, P_of> > {
+ using value_type = typename std::decay<R>::type;
+ using reference = R;
+ using key_type = typename bundle_key_type<P_of>::type;
+
+ typedef typename boost::lvalue_property_map_tag category;
+
+ prop_map(value_type P_of::*m_in) : member(m_in) { }
+
+ reference operator[](key_type k) const {
+ return k.raw()->props.*member;
+ }
+ reference operator()(key_type k) const { return (*this)[k]; }
+
+ private:
+ value_type P_of::*member;
+ };
+
+ template<typename R>
+ struct prop_map_all : public boost::put_get_helper<R, prop_map_all<R> > {
+ using value_type = typename std::decay<R>::type;
+ using reference = R;
+ using key_type = typename bundle_key_type<value_type>::type;
+
+ typedef typename boost::lvalue_property_map_tag category;
+
+ reference operator[](key_type k) const {
+ return k.raw()->props;
+ }
+ reference operator()(key_type k) const { return (*this)[k]; }
+ };
+
+ template<typename P_type, typename P_of>
+ friend
+ prop_map<P_type &, P_of> get(P_type P_of::*t, Graph &) {
+ return prop_map<P_type &, P_of>(t);
+ }
+
+ template<typename P_type, typename P_of>
+ friend
+ prop_map<const P_type &, P_of> get(P_type P_of::*t, const Graph &) {
+ return prop_map<const P_type &, P_of>(t);
+ }
+
+ /* We can't seem to use auto/decltype returns here as it seems that the
+ * templated member functions are not yet visible when the compile is
+ * evaluating the decltype for the return value. We could probably work
+ * around it by making this a dummy templated function. */
+ friend
+ prop_map<size_t &, VertexPropertyType>
+ get(boost::vertex_index_t, Graph &g) {
+ return get(&VertexPropertyType::index, g);
+ }
+
+ friend
+ prop_map<const size_t &, VertexPropertyType>
+ get(boost::vertex_index_t, const Graph &g) {
+ return get(&VertexPropertyType::index, g);
+ }
+
+ friend
+ prop_map<size_t &, EdgePropertyType>
+ get(boost::edge_index_t, Graph &g) {
+ return get(&EdgePropertyType::index, g);
+ }
+
+ friend
+ prop_map<const size_t &, EdgePropertyType>
+ get(boost::edge_index_t, const Graph &g) {
+ return get(&EdgePropertyType::index, g);
+ }
+
+ friend
+ prop_map_all<VertexPropertyType &> get(boost::vertex_all_t, Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<const VertexPropertyType &> get(boost::vertex_all_t,
+ const Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<EdgePropertyType &> get(boost::edge_all_t, Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<const EdgePropertyType &> get(boost::edge_all_t,
+ const Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<VertexPropertyType &> get(boost::vertex_bundle_t, Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<const VertexPropertyType &> get(boost::vertex_bundle_t,
+ const Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<EdgePropertyType &> get(boost::edge_bundle_t, Graph &) {
+ return {};
+ }
+
+ friend
+ prop_map_all<const EdgePropertyType &> get(boost::edge_bundle_t,
+ const Graph &) {
+ return {};
+ }
+
+ template<typename Prop, typename K>
+ friend
+ auto get(Prop p, Graph &g, K key) -> decltype(get(p, g)[key]) {
+ return get(p, g)[key];
+ }
+
+ template<typename Prop, typename K>
+ friend
+ auto get(Prop p, const Graph &g, K key) -> decltype(get(p, g)[key]) {
+ return get(p, g)[key];
+ }
+
+ template<typename Prop, typename K, typename V>
+ friend
+ void put(Prop p, Graph &g, K key, const V &value) {
+ get(p, g)[key] = value;
+ }
+
+ /* MutablePropertyGraph concept functions */
+
+ /* Note: add_vertex(g, vp) allocates a next index value for the vertex
+ * rather than using the index in vp. i.e., except for in rare coincidences:
+ * g[add_vertex(g, vp)].index != vp.index
+ */
+ vertex_descriptor add_vertex_impl(const VertexPropertyType &vp) {
+ vertex_descriptor v = add_vertex_impl();
+ auto i = (*this)[v].index;
+ (*this)[v] = vp;
+ (*this)[v].index = i;
+
+ return v;
+ }
+
+ /* Note: add_edge(u, v, g, vp) allocates a next index value for the edge
+ * rather than using the index in ep. i.e., except for in rare coincidences:
+ * g[add_edge(u, v, g, ep)].index != ep.index
+ */
+ std::pair<edge_descriptor, bool>
+ add_edge_impl(vertex_descriptor u, vertex_descriptor v,
+ const EdgePropertyType &ep) {
+ auto e = add_edge_impl(u, v);
+ auto i = (*this)[e.first].index;
+ (*this)[e.first] = ep;
+ (*this)[e.first].index = i;
+
+ return e;
+ }
+
+ /* End MutablePropertyGraph */
+
+ /** Pack the edge index into a contiguous range [ 0, num_edges(g) ). */
+ void renumber_edges_impl() {
+ next_edge_index = 0;
+ edge_iterator it;
+ edge_iterator ite;
+ for (std::tie(it, ite) = edges_impl(); it != ite; ++it) {
+ (*this)[*it].index = next_edge_index++;
+ }
+ }
+
+ /** Pack the vertex index into a contiguous range [ 0, num_vertices(g) ).
+ * Vertices with indices less than N_SPECIAL_VERTICES are not renumbered.
+ */
+ void renumber_vertices_impl() {
+ DEBUG_PRINTF("renumbering above %zu\n", Graph::N_SPECIAL_VERTICES);
+ next_vertex_index = Graph::N_SPECIAL_VERTICES;
+ vertex_iterator it;
+ vertex_iterator ite;
+ for (std::tie(it, ite) = vertices_impl(); it != ite; ++it) {
+ if ((*this)[*it].index < Graph::N_SPECIAL_VERTICES) {
+ continue;
+ }
+
+ (*this)[*it].index = next_vertex_index++;
+ }
+ }
+
+ /** Returns what the next allocated vertex index will be. This is an upper
+ * on the values of index for vertices (vertex removal means that there may
+ * be gaps). */
+ vertices_size_type vertex_index_upper_bound_impl() const {
+ return next_vertex_index;
+ }
+
+ /** Returns what the next allocated edge index will be. This is an upper on
+ * the values of index for edges (edge removal means that there may be
+ * gaps). */
+ vertices_size_type edge_index_upper_bound_impl() const {
+ return next_edge_index;
+ }
+
+ using directed_category = boost::directed_tag;
+ using edge_parallel_category = boost::allow_parallel_edge_tag;
+ struct traversal_category :
+ public virtual boost::bidirectional_graph_tag,
+ public virtual boost::adjacency_graph_tag,
+ public virtual boost::vertex_list_graph_tag,
+ public virtual boost::edge_list_graph_tag { };
+
+ ue2_graph() = default;
+
+ ue2_graph(ue2_graph &&old)
+ : next_vertex_index(old.next_vertex_index),
+ next_edge_index(old.next_edge_index),
+ graph_edge_count(old.graph_edge_count),
+ next_serial(old.next_serial) {
+ using std::swap;
+ swap(vertices_list, old.vertices_list);
+ }
+
+ ue2_graph &operator=(ue2_graph &&old) {
+ next_vertex_index = old.next_vertex_index;
+ next_edge_index = old.next_edge_index;
+ graph_edge_count = old.graph_edge_count;
+ next_serial = old.next_serial;
+ using std::swap;
+ swap(vertices_list, old.vertices_list);
+ return *this;
+ }
+
+ ~ue2_graph() {
+ vertices_list.clear_and_dispose(delete_disposer());
+ }
+};
+
/** \brief Type trait to enable on whether the Graph is an ue2_graph. */
-template<typename Graph>
+template<typename Graph>
struct is_ue2_graph
: public ::std::integral_constant<
bool, std::is_base_of<graph_detail::graph_base, Graph>::value> {};
@@ -1034,231 +1034,231 @@ struct is_ue2_graph
template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertex_descriptor>::type
-add_vertex(Graph &g) {
- return g.add_vertex_impl();
-}
-
-template<typename Graph>
+add_vertex(Graph &g) {
+ return g.add_vertex_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_vertex(typename Graph::vertex_descriptor v, Graph &g) {
- g.remove_vertex_impl(v);
-}
-
-template<typename Graph>
+remove_vertex(typename Graph::vertex_descriptor v, Graph &g) {
+ g.remove_vertex_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-clear_in_edges(typename Graph::vertex_descriptor v, Graph &g) {
- g.clear_in_edges_impl(v);
-}
-
-template<typename Graph>
+clear_in_edges(typename Graph::vertex_descriptor v, Graph &g) {
+ g.clear_in_edges_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-clear_out_edges(typename Graph::vertex_descriptor v, Graph &g) {
- g.clear_out_edges_impl(v);
-}
-
-template<typename Graph>
+clear_out_edges(typename Graph::vertex_descriptor v, Graph &g) {
+ g.clear_out_edges_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-clear_vertex(typename Graph::vertex_descriptor v, Graph &g) {
- g.clear_in_edges_impl(v);
- g.clear_out_edges_impl(v);
-}
-
-template<typename Graph>
+clear_vertex(typename Graph::vertex_descriptor v, Graph &g) {
+ g.clear_in_edges_impl(v);
+ g.clear_out_edges_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertex_descriptor>::type
-source(typename Graph::edge_descriptor e, const Graph &) {
- return Graph::source_impl(e);
-}
-
-template<typename Graph>
+source(typename Graph::edge_descriptor e, const Graph &) {
+ return Graph::source_impl(e);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertex_descriptor>::type
-target(typename Graph::edge_descriptor e, const Graph &) {
- return Graph::target_impl(e);
-}
-
-template<typename Graph>
+target(typename Graph::edge_descriptor e, const Graph &) {
+ return Graph::target_impl(e);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::degree_size_type>::type
-out_degree(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::out_degree_impl(v);
-}
-
-template<typename Graph>
+out_degree(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::out_degree_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::out_edge_iterator,
typename Graph::out_edge_iterator>>::type
-out_edges(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::out_edges_impl(v);
-}
-
-template<typename Graph>
+out_edges(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::out_edges_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::degree_size_type>::type
-in_degree(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::in_degree_impl(v);
-}
-
-template<typename Graph>
+in_degree(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::in_degree_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::in_edge_iterator,
typename Graph::in_edge_iterator>>::type
-in_edges(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::in_edges_impl(v);
-}
-
-template<typename Graph>
+in_edges(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::in_edges_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::degree_size_type>::type
-degree(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::degree_impl(v);
-}
-
-template<typename Graph>
+degree(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::degree_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::adjacency_iterator,
typename Graph::adjacency_iterator>>::type
-adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::adjacent_vertices_impl(v);
-}
-
-template<typename Graph>
+adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::adjacent_vertices_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::edge_descriptor, bool>>::type
-edge(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v,
- const Graph &g) {
- return g.edge_impl(u, v);
-}
-
-template<typename Graph>
+edge(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v,
+ const Graph &g) {
+ return g.edge_impl(u, v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::inv_adjacency_iterator,
typename Graph::inv_adjacency_iterator>>::type
-inv_adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) {
- return Graph::inv_adjacent_vertices_impl(v);
-}
-
-template<typename Graph>
+inv_adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) {
+ return Graph::inv_adjacent_vertices_impl(v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::edge_descriptor, bool>>::type
-add_edge(typename Graph::vertex_descriptor u,
- typename Graph::vertex_descriptor v, Graph &g) {
- return g.add_edge_impl(u, v);
-}
-
-template<typename Graph>
+add_edge(typename Graph::vertex_descriptor u,
+ typename Graph::vertex_descriptor v, Graph &g) {
+ return g.add_edge_impl(u, v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_edge(typename Graph::edge_descriptor e, Graph &g) {
- g.remove_edge_impl(e);
-}
-
-template<typename Graph, typename Iter>
-typename std::enable_if<
+remove_edge(typename Graph::edge_descriptor e, Graph &g) {
+ g.remove_edge_impl(e);
+}
+
+template<typename Graph, typename Iter>
+typename std::enable_if<
!std::is_convertible<Iter, typename Graph::edge_descriptor>::value &&
is_ue2_graph<Graph>::value>::type
-remove_edge(Iter it, Graph &g) {
- g.remove_edge_impl(*it);
-}
-
-template<typename Graph, typename Predicate>
+remove_edge(Iter it, Graph &g) {
+ g.remove_edge_impl(*it);
+}
+
+template<typename Graph, typename Predicate>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_out_edge_if(typename Graph::vertex_descriptor v, Predicate pred,
- Graph &g) {
- g.remove_out_edge_if_impl(v, pred);
-}
-
-template<typename Graph, typename Predicate>
+remove_out_edge_if(typename Graph::vertex_descriptor v, Predicate pred,
+ Graph &g) {
+ g.remove_out_edge_if_impl(v, pred);
+}
+
+template<typename Graph, typename Predicate>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_in_edge_if(typename Graph::vertex_descriptor v, Predicate pred,
- Graph &g) {
- g.remove_in_edge_if_impl(v, pred);
-}
-
-template<typename Graph, typename Predicate>
+remove_in_edge_if(typename Graph::vertex_descriptor v, Predicate pred,
+ Graph &g) {
+ g.remove_in_edge_if_impl(v, pred);
+}
+
+template<typename Graph, typename Predicate>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_edge_if(Predicate pred, Graph &g) {
- g.remove_edge_if_impl(pred);
-}
-
-template<typename Graph>
+remove_edge_if(Predicate pred, Graph &g) {
+ g.remove_edge_if_impl(pred);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-remove_edge(const typename Graph::vertex_descriptor &u,
- const typename Graph::vertex_descriptor &v, Graph &g) {
- g.remove_edge_impl(u, v);
-}
-
-template<typename Graph>
+remove_edge(const typename Graph::vertex_descriptor &u,
+ const typename Graph::vertex_descriptor &v, Graph &g) {
+ g.remove_edge_impl(u, v);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertices_size_type>::type
-num_vertices(const Graph &g) {
- return g.num_vertices_impl();
-}
-
-template<typename Graph>
+num_vertices(const Graph &g) {
+ return g.num_vertices_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::vertex_iterator,
typename Graph::vertex_iterator>>::type
-vertices(const Graph &g) {
- return g.vertices_impl();
-}
-
-template<typename Graph>
+vertices(const Graph &g) {
+ return g.vertices_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::edges_size_type>::type
-num_edges(const Graph &g) {
- return g.num_edges_impl();
-}
-
-template<typename Graph>
+num_edges(const Graph &g) {
+ return g.num_edges_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::edge_iterator,
typename Graph::edge_iterator>>::type
-edges(const Graph &g) {
- return g.edges_impl();
-}
-
-template<typename Graph>
+edges(const Graph &g) {
+ return g.edges_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertex_descriptor>::type
-add_vertex(const typename Graph::vertex_property_type &vp, Graph &g) {
- return g.add_vertex_impl(vp);
-}
-
-template<typename Graph>
+add_vertex(const typename Graph::vertex_property_type &vp, Graph &g) {
+ return g.add_vertex_impl(vp);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
std::pair<typename Graph::edge_descriptor, bool>>::type
-add_edge(typename Graph::vertex_descriptor u,
- typename Graph::vertex_descriptor v,
- const typename Graph::edge_property_type &ep, Graph &g) {
- return g.add_edge_impl(u, v, ep);
-}
-
-template<typename Graph>
+add_edge(typename Graph::vertex_descriptor u,
+ typename Graph::vertex_descriptor v,
+ const typename Graph::edge_property_type &ep, Graph &g) {
+ return g.add_edge_impl(u, v, ep);
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-renumber_edges(Graph &g) {
- g.renumber_edges_impl();
-}
-
-template<typename Graph>
+renumber_edges(Graph &g) {
+ g.renumber_edges_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value>::type
-renumber_vertices(Graph &g) {
- g.renumber_vertices_impl();
-}
-
-template<typename Graph>
+renumber_vertices(Graph &g) {
+ g.renumber_vertices_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::vertices_size_type>::type
-vertex_index_upper_bound(const Graph &g) {
- return g.vertex_index_upper_bound_impl();
-}
-
-template<typename Graph>
+vertex_index_upper_bound(const Graph &g) {
+ return g.vertex_index_upper_bound_impl();
+}
+
+template<typename Graph>
typename std::enable_if<is_ue2_graph<Graph>::value,
typename Graph::edges_size_type>::type
-edge_index_upper_bound(const Graph &g) {
- return g.edge_index_upper_bound_impl();
-}
-
+edge_index_upper_bound(const Graph &g) {
+ return g.edge_index_upper_bound_impl();
+}
+
template<typename T> struct pointer_to_member_traits {};
template<typename Return, typename Class>
@@ -1287,17 +1287,17 @@ public:
std::is_same<class_type, edge_type>::value;
};
-using boost::vertex_index;
-using boost::edge_index;
-
-} // namespace ue2
-
-namespace boost {
-
-/* Install partial specialisation of property_map - this is required for
- * adaptors (like filtered_graph) to know the type of the property maps */
-template<typename Graph, typename Prop>
-struct property_map<Graph, Prop,
+using boost::vertex_index;
+using boost::edge_index;
+
+} // namespace ue2
+
+namespace boost {
+
+/* Install partial specialisation of property_map - this is required for
+ * adaptors (like filtered_graph) to know the type of the property maps */
+template<typename Graph, typename Prop>
+struct property_map<Graph, Prop,
typename std::enable_if<ue2::is_ue2_graph<Graph>::value &&
ue2::is_ue2_vertex_or_edge_property<
Graph, Prop>::value>::type> {
@@ -1309,8 +1309,8 @@ public:
using type = typename Graph::template prop_map<member_type &, class_type>;
using const_type = typename Graph::template prop_map<const member_type &,
class_type>;
-};
-
+};
+
template<typename Graph>
struct property_map<Graph, vertex_index_t,
typename std::enable_if<ue2::is_ue2_graph<Graph>::value>::type> {
@@ -1347,29 +1347,29 @@ struct property_map<Graph, edge_all_t,
typename Graph::template prop_map_all<const e_prop_type &>;
};
-} // namespace boost
-
-namespace std {
-
-/* Specialization of std::hash so that vertex_descriptor can be used in
- * unordered containers. */
-template<typename Graph>
-struct hash<ue2::graph_detail::vertex_descriptor<Graph>> {
- using vertex_descriptor = ue2::graph_detail::vertex_descriptor<Graph>;
- std::size_t operator()(const vertex_descriptor &v) const {
- return v.hash();
- }
-};
-
-/* Specialization of std::hash so that edge_descriptor can be used in
- * unordered containers. */
-template<typename Graph>
-struct hash<ue2::graph_detail::edge_descriptor<Graph>> {
- using edge_descriptor = ue2::graph_detail::edge_descriptor<Graph>;
- std::size_t operator()(const edge_descriptor &e) const {
- return e.hash();
- }
-};
-
-} // namespace std
-#endif
+} // namespace boost
+
+namespace std {
+
+/* Specialization of std::hash so that vertex_descriptor can be used in
+ * unordered containers. */
+template<typename Graph>
+struct hash<ue2::graph_detail::vertex_descriptor<Graph>> {
+ using vertex_descriptor = ue2::graph_detail::vertex_descriptor<Graph>;
+ std::size_t operator()(const vertex_descriptor &v) const {
+ return v.hash();
+ }
+};
+
+/* Specialization of std::hash so that edge_descriptor can be used in
+ * unordered containers. */
+template<typename Graph>
+struct hash<ue2::graph_detail::edge_descriptor<Graph>> {
+ using edge_descriptor = ue2::graph_detail::edge_descriptor<Graph>;
+ std::size_t operator()(const edge_descriptor &e) const {
+ return e.hash();
+ }
+};
+
+} // namespace std
+#endif
diff --git a/contrib/libs/hyperscan/src/util/ue2string.cpp b/contrib/libs/hyperscan/src/util/ue2string.cpp
index 213d3d104e8..50b2bbcc89a 100644
--- a/contrib/libs/hyperscan/src/util/ue2string.cpp
+++ b/contrib/libs/hyperscan/src/util/ue2string.cpp
@@ -29,15 +29,15 @@
/** \file
* \brief Tools for string manipulation, ue2_literal definition.
*/
-
-#include "ue2string.h"
-
+
+#include "ue2string.h"
+
#include "charreach.h"
#include "compare.h"
-#include "hash_dynamic_bitset.h"
+#include "hash_dynamic_bitset.h"
#include <algorithm>
-#include <cstring>
+#include <cstring>
#include <iomanip>
#include <sstream>
#include <string>
@@ -133,9 +133,9 @@ string dumpString(const ue2_literal &lit) {
#endif
void upperString(string &s) {
- for (auto &c : s) {
- c = mytoupper(c);
- }
+ for (auto &c : s) {
+ c = mytoupper(c);
+ }
}
size_t maxStringOverlap(const string &a, const string &b, bool nocase) {
@@ -179,16 +179,16 @@ size_t maxStringSelfOverlap(const string &a, bool nocase) {
}
u32 cmp(const char *a, const char *b, size_t len, bool nocase) {
- if (!nocase) {
- return memcmp(a, b, len);
- }
-
- for (const auto *a_end = a + len; a < a_end; a++, b++) {
- if (mytoupper(*a) != mytoupper(*b)) {
- return 1;
- }
- }
- return 0;
+ if (!nocase) {
+ return memcmp(a, b, len);
+ }
+
+ for (const auto *a_end = a + len; a < a_end; a++, b++) {
+ if (mytoupper(*a) != mytoupper(*b)) {
+ return 1;
+ }
+ }
+ return 0;
}
case_iter::case_iter(const ue2_literal &ss) : s(ss.get_string()),
@@ -237,15 +237,15 @@ ue2_literal::elem::operator CharReach () const {
}
}
-const ue2_literal::size_type ue2_literal::npos = std::string::npos;
-
+const ue2_literal::size_type ue2_literal::npos = std::string::npos;
+
ue2_literal::ue2_literal(const std::string &s_in, bool nc_in)
- : s(nc_in ? toUpperString(s_in) : s_in), nocase(s_in.size()) {
+ : s(nc_in ? toUpperString(s_in) : s_in), nocase(s_in.size()) {
if (nc_in) {
- // Switch on nocase bit for all alpha characters.
+ // Switch on nocase bit for all alpha characters.
for (size_t i = 0; i < s.length(); i++) {
- if (ourisalpha(s[i])) {
- nocase.set(i);
+ if (ourisalpha(s[i])) {
+ nocase.set(i);
}
}
}
@@ -258,27 +258,27 @@ ue2_literal ue2_literal::substr(size_type pos, size_type n) const {
ue2_literal rv;
rv.s = s.substr(pos, n);
size_type upper = nocase.size();
- if (n != npos && n + pos < nocase.size()) {
+ if (n != npos && n + pos < nocase.size()) {
upper = n + pos;
}
-
- rv.nocase.resize(upper - pos, false);
- for (size_t i = pos; i < upper; i++) {
- rv.nocase.set(i - pos, nocase.test(i));
- }
- assert(s.size() == nocase.size());
+
+ rv.nocase.resize(upper - pos, false);
+ for (size_t i = pos; i < upper; i++) {
+ rv.nocase.set(i - pos, nocase.test(i));
+ }
+ assert(s.size() == nocase.size());
return rv;
}
ue2_literal &ue2_literal::erase(size_type pos, size_type n) {
s.erase(pos, n);
-
- if (n != npos) {
- for (size_type i = pos + n; i < nocase.size(); i++) {
- nocase.set(i - n, nocase.test(i));
- }
+
+ if (n != npos) {
+ for (size_type i = pos + n; i < nocase.size(); i++) {
+ nocase.set(i - n, nocase.test(i));
+ }
}
- nocase.resize(s.size());
+ nocase.resize(s.size());
return *this;
}
@@ -290,26 +290,26 @@ void ue2_literal::push_back(char c, bool nc) {
s.push_back(c);
}
-void ue2_literal::reverse() {
- std::reverse(s.begin(), s.end());
+void ue2_literal::reverse() {
+ std::reverse(s.begin(), s.end());
- const size_t len = nocase.size();
- for (size_t i = 0; i < len / 2; i++) {
- size_t j = len - i - 1;
- bool a = nocase.test(i);
- bool b = nocase.test(j);
- nocase.set(i, b);
- nocase.set(j, a);
+ const size_t len = nocase.size();
+ for (size_t i = 0; i < len / 2; i++) {
+ size_t j = len - i - 1;
+ bool a = nocase.test(i);
+ bool b = nocase.test(j);
+ nocase.set(i, b);
+ nocase.set(j, a);
}
}
-// Return a copy of this literal in reverse order.
-ue2_literal reverse_literal(const ue2_literal &in) {
- auto out = in;
- out.reverse();
- return out;
-}
-
+// Return a copy of this literal in reverse order.
+ue2_literal reverse_literal(const ue2_literal &in) {
+ auto out = in;
+ out.reverse();
+ return out;
+}
+
bool ue2_literal::operator<(const ue2_literal &b) const {
if (s < b.s) {
return true;
@@ -322,26 +322,26 @@ bool ue2_literal::operator<(const ue2_literal &b) const {
void ue2_literal::operator+=(const ue2_literal &b) {
s += b.s;
- size_t prefix = nocase.size();
- nocase.resize(prefix + b.nocase.size());
- for (size_t i = 0; i < b.nocase.size(); i++) {
- nocase.set(prefix + i, b.nocase[i]);
- }
+ size_t prefix = nocase.size();
+ nocase.resize(prefix + b.nocase.size());
+ for (size_t i = 0; i < b.nocase.size(); i++) {
+ nocase.set(prefix + i, b.nocase[i]);
+ }
}
bool ue2_literal::any_nocase() const {
- return nocase.any();
+ return nocase.any();
}
-size_t ue2_literal::hash() const {
- return hash_all(s, hash_dynamic_bitset()(nocase));
+size_t ue2_literal::hash() const {
+ return hash_all(s, hash_dynamic_bitset()(nocase));
}
void make_nocase(ue2_literal *lit) {
ue2_literal rv;
- for (const auto &elem: *lit) {
- rv.push_back(elem.c, ourisalpha(elem.c));
+ for (const auto &elem: *lit) {
+ rv.push_back(elem.c, ourisalpha(elem.c));
}
lit->swap(rv);
diff --git a/contrib/libs/hyperscan/src/util/ue2string.h b/contrib/libs/hyperscan/src/util/ue2string.h
index 08c3735ab94..0aa846896ef 100644
--- a/contrib/libs/hyperscan/src/util/ue2string.h
+++ b/contrib/libs/hyperscan/src/util/ue2string.h
@@ -35,15 +35,15 @@
#include "ue2common.h"
#include "util/charreach.h"
-#include "util/compare.h"
-#include "util/hash.h"
-#include "util/operators.h"
+#include "util/compare.h"
+#include "util/hash.h"
+#include "util/operators.h"
#include <iterator>
#include <string>
#include <vector>
-#include <boost/dynamic_bitset.hpp>
+#include <boost/dynamic_bitset.hpp>
#include <boost/iterator/iterator_facade.hpp>
namespace ue2 {
@@ -59,30 +59,30 @@ size_t maxStringSelfOverlap(const std::string &a, bool nocase);
/// Compares two strings, returns non-zero if they're different.
u32 cmp(const char *a, const char *b, size_t len, bool nocase);
-/**
- * \brief String type that also records whether the whole string is caseful or
- * caseless.
- *
- * You should use \ref ue2_literal if you need to represent a mixed-case
- * literal.
- */
-struct ue2_case_string {
- ue2_case_string(std::string s_in, bool nocase_in)
- : s(std::move(s_in)), nocase(nocase_in) {
- if (nocase) {
- upperString(s);
- }
- }
-
- bool operator==(const ue2_case_string &other) const {
- return s == other.s && nocase == other.nocase;
- }
-
- std::string s;
- bool nocase;
-};
-
-struct ue2_literal : totally_ordered<ue2_literal> {
+/**
+ * \brief String type that also records whether the whole string is caseful or
+ * caseless.
+ *
+ * You should use \ref ue2_literal if you need to represent a mixed-case
+ * literal.
+ */
+struct ue2_case_string {
+ ue2_case_string(std::string s_in, bool nocase_in)
+ : s(std::move(s_in)), nocase(nocase_in) {
+ if (nocase) {
+ upperString(s);
+ }
+ }
+
+ bool operator==(const ue2_case_string &other) const {
+ return s == other.s && nocase == other.nocase;
+ }
+
+ std::string s;
+ bool nocase;
+};
+
+struct ue2_literal : totally_ordered<ue2_literal> {
public:
/// Single element proxy, pointed to by our const_iterator.
struct elem {
@@ -110,38 +110,38 @@ public:
private:
friend class boost::iterator_core_access;
void increment() {
- ++idx;
+ ++idx;
}
void decrement() {
- --idx;
+ --idx;
}
void advance(size_t n) {
- idx += n;
+ idx += n;
}
difference_type distance_to(const const_iterator &other) const {
- return other.idx - idx;
+ return other.idx - idx;
}
bool equal(const const_iterator &other) const {
- return idx == other.idx && lit == other.lit;
+ return idx == other.idx && lit == other.lit;
}
const elem dereference() const {
- return elem(lit->s[idx], lit->nocase[idx]);
+ return elem(lit->s[idx], lit->nocase[idx]);
}
friend struct ue2_literal;
- const_iterator(const ue2_literal &lit_in, size_t idx_in)
- : lit(&lit_in), idx(idx_in) {}
+ const_iterator(const ue2_literal &lit_in, size_t idx_in)
+ : lit(&lit_in), idx(idx_in) {}
- const ue2_literal *lit = nullptr;
- size_t idx;
+ const ue2_literal *lit = nullptr;
+ size_t idx;
};
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using size_type = std::string::size_type;
+ using size_type = std::string::size_type;
- static const size_type npos;
+ static const size_type npos;
- ue2_literal() = default;
+ ue2_literal() = default;
ue2_literal(const std::string &s_in, bool nc_in);
ue2_literal(char c, bool nc_in);
ue2_literal(const ue2_literal &) = default;
@@ -149,25 +149,25 @@ public:
ue2_literal &operator=(const ue2_literal &) = default;
ue2_literal &operator=(ue2_literal &&) = default;
- template<typename InputIt>
- ue2_literal(InputIt b, InputIt e) {
- for (; b != e; ++b) {
- push_back(*b);
- }
- }
-
+ template<typename InputIt>
+ ue2_literal(InputIt b, InputIt e) {
+ for (; b != e; ++b) {
+ push_back(*b);
+ }
+ }
+
size_type length() const { return s.length(); }
bool empty() const { return s.empty(); }
- ue2_literal substr(size_type pos, size_type n = npos) const;
+ ue2_literal substr(size_type pos, size_type n = npos) const;
const char *c_str() const { return s.c_str(); }
bool any_nocase() const;
const_iterator begin() const {
- return const_iterator(*this, 0);
+ return const_iterator(*this, 0);
}
const_iterator end() const {
- return const_iterator(*this, s.size());
+ return const_iterator(*this, s.size());
}
const_reverse_iterator rbegin() const {
@@ -178,22 +178,22 @@ public:
return const_reverse_iterator(begin());
}
- ue2_literal &erase(size_type pos = 0, size_type n = npos);
+ ue2_literal &erase(size_type pos = 0, size_type n = npos);
void push_back(const elem &e) {
push_back(e.c, e.nocase);
}
void push_back(char c, bool nc);
- const elem back() const { return *rbegin(); }
-
- friend ue2_literal operator+(ue2_literal a, const ue2_literal &b) {
- a += b;
- return a;
- }
-
- /// Reverse this literal in-place.
- void reverse();
-
+ const elem back() const { return *rbegin(); }
+
+ friend ue2_literal operator+(ue2_literal a, const ue2_literal &b) {
+ a += b;
+ return a;
+ }
+
+ /// Reverse this literal in-place.
+ void reverse();
+
void operator+=(const ue2_literal &b);
bool operator==(const ue2_literal &b) const {
return s == b.s && nocase == b.nocase;
@@ -209,12 +209,12 @@ public:
nocase.swap(other.nocase);
}
- size_t hash() const;
-
+ size_t hash() const;
+
private:
- friend const_iterator;
+ friend const_iterator;
std::string s;
- boost::dynamic_bitset<> nocase;
+ boost::dynamic_bitset<> nocase;
};
/// Return a reversed copy of this literal.
@@ -228,37 +228,37 @@ size_t maxStringSelfOverlap(const ue2_literal &a);
size_t minStringPeriod(const ue2_literal &a);
size_t maxStringOverlap(const ue2_literal &a, const ue2_literal &b);
-/**
- * \brief True iff the range of a literal given cannot be considered entirely
- * case-sensitive nor entirely case-insensitive.
- */
-template<class Iter>
-bool mixed_sensitivity_in(Iter begin, Iter end) {
- bool cs = false;
- bool nc = false;
- for (auto it = begin; it != end; ++it) {
- if (!ourisalpha(it->c)) {
- continue;
- }
- if (it->nocase) {
- nc = true;
- } else {
- cs = true;
- }
- }
-
- return cs && nc;
-}
-
-/**
- * \brief True iff the literal cannot be considered entirely case-sensitive
- * nor entirely case-insensitive.
- */
-inline
-bool mixed_sensitivity(const ue2_literal &s) {
- return mixed_sensitivity_in(s.begin(), s.end());
-}
-
+/**
+ * \brief True iff the range of a literal given cannot be considered entirely
+ * case-sensitive nor entirely case-insensitive.
+ */
+template<class Iter>
+bool mixed_sensitivity_in(Iter begin, Iter end) {
+ bool cs = false;
+ bool nc = false;
+ for (auto it = begin; it != end; ++it) {
+ if (!ourisalpha(it->c)) {
+ continue;
+ }
+ if (it->nocase) {
+ nc = true;
+ } else {
+ cs = true;
+ }
+ }
+
+ return cs && nc;
+}
+
+/**
+ * \brief True iff the literal cannot be considered entirely case-sensitive
+ * nor entirely case-insensitive.
+ */
+inline
+bool mixed_sensitivity(const ue2_literal &s) {
+ return mixed_sensitivity_in(s.begin(), s.end());
+}
+
void make_nocase(ue2_literal *lit);
struct case_iter {
@@ -315,22 +315,22 @@ std::string escapeString(const ue2_literal &lit);
} // namespace ue2
-namespace std {
-
-template<>
-struct hash<ue2::ue2_literal::elem> {
- size_t operator()(const ue2::ue2_literal::elem &elem) const {
- return ue2::hash_all(elem.c, elem.nocase);
- }
-};
-
-template<>
-struct hash<ue2::ue2_literal> {
- size_t operator()(const ue2::ue2_literal &lit) const {
- return lit.hash();
- }
-};
-
-} // namespace std
-
+namespace std {
+
+template<>
+struct hash<ue2::ue2_literal::elem> {
+ size_t operator()(const ue2::ue2_literal::elem &elem) const {
+ return ue2::hash_all(elem.c, elem.nocase);
+ }
+};
+
+template<>
+struct hash<ue2::ue2_literal> {
+ size_t operator()(const ue2::ue2_literal &lit) const {
+ return lit.hash();
+ }
+};
+
+} // namespace std
+
#endif
diff --git a/contrib/libs/hyperscan/src/util/uniform_ops.h b/contrib/libs/hyperscan/src/util/uniform_ops.h
index 72a3c4b9e01..262104aca2d 100644
--- a/contrib/libs/hyperscan/src/util/uniform_ops.h
+++ b/contrib/libs/hyperscan/src/util/uniform_ops.h
@@ -137,12 +137,12 @@
#define andnot_m384(a, b) (andnot384(a, b))
#define andnot_m512(a, b) (andnot512(a, b))
-#define lshift_u32(a, b) ((a) << (b))
-#define lshift_u64a(a, b) ((a) << (b))
-#define lshift_m128(a, b) (lshift64_m128(a, b))
-#define lshift_m256(a, b) (lshift64_m256(a, b))
-#define lshift_m384(a, b) (lshift64_m384(a, b))
-#define lshift_m512(a, b) (lshift64_m512(a, b))
+#define lshift_u32(a, b) ((a) << (b))
+#define lshift_u64a(a, b) ((a) << (b))
+#define lshift_m128(a, b) (lshift64_m128(a, b))
+#define lshift_m256(a, b) (lshift64_m256(a, b))
+#define lshift_m384(a, b) (lshift64_m384(a, b))
+#define lshift_m512(a, b) (lshift64_m512(a, b))
#define isZero_u8(a) ((a) == 0)
#define isZero_u32(a) ((a) == 0)
@@ -192,52 +192,52 @@
#define partial_load_m384(ptr, sz) loadbytes384(ptr, sz)
#define partial_load_m512(ptr, sz) loadbytes512(ptr, sz)
-#define store_compressed_u32(ptr, x, m, len) storecompressed32(ptr, x, m, len)
-#define store_compressed_u64a(ptr, x, m, len) storecompressed64(ptr, x, m, len)
-#define store_compressed_m128(ptr, x, m, len) storecompressed128(ptr, x, m, len)
-#define store_compressed_m256(ptr, x, m, len) storecompressed256(ptr, x, m, len)
-#define store_compressed_m384(ptr, x, m, len) storecompressed384(ptr, x, m, len)
-#define store_compressed_m512(ptr, x, m, len) storecompressed512(ptr, x, m, len)
-
-#define load_compressed_u32(x, ptr, m, len) loadcompressed32(x, ptr, m, len)
-#define load_compressed_u64a(x, ptr, m, len) loadcompressed64(x, ptr, m, len)
-#define load_compressed_m128(x, ptr, m, len) loadcompressed128(x, ptr, m, len)
-#define load_compressed_m256(x, ptr, m, len) loadcompressed256(x, ptr, m, len)
-#define load_compressed_m384(x, ptr, m, len) loadcompressed384(x, ptr, m, len)
-#define load_compressed_m512(x, ptr, m, len) loadcompressed512(x, ptr, m, len)
-
-static really_inline
-void clearbit_u32(u32 *p, u32 n) {
+#define store_compressed_u32(ptr, x, m, len) storecompressed32(ptr, x, m, len)
+#define store_compressed_u64a(ptr, x, m, len) storecompressed64(ptr, x, m, len)
+#define store_compressed_m128(ptr, x, m, len) storecompressed128(ptr, x, m, len)
+#define store_compressed_m256(ptr, x, m, len) storecompressed256(ptr, x, m, len)
+#define store_compressed_m384(ptr, x, m, len) storecompressed384(ptr, x, m, len)
+#define store_compressed_m512(ptr, x, m, len) storecompressed512(ptr, x, m, len)
+
+#define load_compressed_u32(x, ptr, m, len) loadcompressed32(x, ptr, m, len)
+#define load_compressed_u64a(x, ptr, m, len) loadcompressed64(x, ptr, m, len)
+#define load_compressed_m128(x, ptr, m, len) loadcompressed128(x, ptr, m, len)
+#define load_compressed_m256(x, ptr, m, len) loadcompressed256(x, ptr, m, len)
+#define load_compressed_m384(x, ptr, m, len) loadcompressed384(x, ptr, m, len)
+#define load_compressed_m512(x, ptr, m, len) loadcompressed512(x, ptr, m, len)
+
+static really_inline
+void clearbit_u32(u32 *p, u32 n) {
assert(n < sizeof(*p) * 8);
*p &= ~(1U << n);
}
-
-static really_inline
-void clearbit_u64a(u64a *p, u32 n) {
+
+static really_inline
+void clearbit_u64a(u64a *p, u32 n) {
assert(n < sizeof(*p) * 8);
*p &= ~(1ULL << n);
}
-
+
#define clearbit_m128(ptr, n) (clearbit128(ptr, n))
#define clearbit_m256(ptr, n) (clearbit256(ptr, n))
#define clearbit_m384(ptr, n) (clearbit384(ptr, n))
#define clearbit_m512(ptr, n) (clearbit512(ptr, n))
-static really_inline
-char testbit_u32(u32 val, u32 n) {
- assert(n < sizeof(val) * 8);
- return !!(val & (1U << n));
+static really_inline
+char testbit_u32(u32 val, u32 n) {
+ assert(n < sizeof(val) * 8);
+ return !!(val & (1U << n));
}
-
-static really_inline
-char testbit_u64a(u64a val, u32 n) {
- assert(n < sizeof(val) * 8);
- return !!(val & (1ULL << n));
+
+static really_inline
+char testbit_u64a(u64a val, u32 n) {
+ assert(n < sizeof(val) * 8);
+ return !!(val & (1ULL << n));
}
-#define testbit_m128(val, n) (testbit128(val, n))
-#define testbit_m256(val, n) (testbit256(val, n))
-#define testbit_m384(val, n) (testbit384(val, n))
-#define testbit_m512(val, n) (testbit512(val, n))
-
+#define testbit_m128(val, n) (testbit128(val, n))
+#define testbit_m256(val, n) (testbit256(val, n))
+#define testbit_m384(val, n) (testbit384(val, n))
+#define testbit_m512(val, n) (testbit512(val, n))
+
#endif
diff --git a/contrib/libs/hyperscan/src/util/unordered.h b/contrib/libs/hyperscan/src/util/unordered.h
index e4de5031dc5..a8aa61cd041 100644
--- a/contrib/libs/hyperscan/src/util/unordered.h
+++ b/contrib/libs/hyperscan/src/util/unordered.h
@@ -1,53 +1,53 @@
-/*
- * Copyright (c) 2017, Intel Corporation
- *
- * 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 Intel Corporation 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.
- */
-
-#ifndef UTIL_UNORDERED_H
-#define UTIL_UNORDERED_H
-
-/**
- * \file
- * \brief Unordered set and map containers that default to using our own hasher.
- */
-
-#include "hash.h"
-
-#include <unordered_set>
-#include <unordered_map>
-
-namespace ue2 {
-
-template<class Key, class Hash = ue2_hasher>
-using ue2_unordered_set = std::unordered_set<Key, Hash>;
-
-template<class Key, class T, class Hash = ue2_hasher>
-using ue2_unordered_map = std::unordered_map<Key, T, Hash>;
-
-} // namespace ue2
-
-
-#endif // UTIL_UNORDERED_H
+/*
+ * Copyright (c) 2017, Intel Corporation
+ *
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef UTIL_UNORDERED_H
+#define UTIL_UNORDERED_H
+
+/**
+ * \file
+ * \brief Unordered set and map containers that default to using our own hasher.
+ */
+
+#include "hash.h"
+
+#include <unordered_set>
+#include <unordered_map>
+
+namespace ue2 {
+
+template<class Key, class Hash = ue2_hasher>
+using ue2_unordered_set = std::unordered_set<Key, Hash>;
+
+template<class Key, class T, class Hash = ue2_hasher>
+using ue2_unordered_map = std::unordered_map<Key, T, Hash>;
+
+} // namespace ue2
+
+
+#endif // UTIL_UNORDERED_H
diff --git a/contrib/libs/hyperscan/src/util/verify_types.h b/contrib/libs/hyperscan/src/util/verify_types.h
index 2cde6f87797..5833d5ec62f 100644
--- a/contrib/libs/hyperscan/src/util/verify_types.h
+++ b/contrib/libs/hyperscan/src/util/verify_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,61 +30,61 @@
#define UTIL_VERIFY_TYPES
#include "ue2common.h"
-#include "util/compile_error.h"
+#include "util/compile_error.h"
#include <cassert>
-#include <type_traits>
+#include <type_traits>
namespace ue2 {
-template<typename To_T, typename From_T>
-To_T verify_cast(From_T val) {
- static_assert(std::is_integral<To_T>::value,
- "Output type must be integral.");
- static_assert(std::is_integral<From_T>::value ||
- std::is_enum<From_T>::value ||
- std::is_convertible<From_T, To_T>::value,
- "Must be integral or enum type, or convertible to output.");
-
- To_T conv_val = static_cast<To_T>(val);
- if (static_cast<From_T>(conv_val) != val) {
- assert(0);
- throw ResourceLimitError();
- }
-
- return conv_val;
+template<typename To_T, typename From_T>
+To_T verify_cast(From_T val) {
+ static_assert(std::is_integral<To_T>::value,
+ "Output type must be integral.");
+ static_assert(std::is_integral<From_T>::value ||
+ std::is_enum<From_T>::value ||
+ std::is_convertible<From_T, To_T>::value,
+ "Must be integral or enum type, or convertible to output.");
+
+ To_T conv_val = static_cast<To_T>(val);
+ if (static_cast<From_T>(conv_val) != val) {
+ assert(0);
+ throw ResourceLimitError();
+ }
+
+ return conv_val;
+}
+
+template<typename T>
+s8 verify_s8(T val) {
+ return verify_cast<s8>(val);
}
-template<typename T>
-s8 verify_s8(T val) {
- return verify_cast<s8>(val);
+template<typename T>
+u8 verify_u8(T val) {
+ return verify_cast<u8>(val);
}
-template<typename T>
-u8 verify_u8(T val) {
- return verify_cast<u8>(val);
+template<typename T>
+s16 verify_s16(T val) {
+ return verify_cast<s16>(val);
}
-template<typename T>
-s16 verify_s16(T val) {
- return verify_cast<s16>(val);
+template<typename T>
+u16 verify_u16(T val) {
+ return verify_cast<u16>(val);
}
-template<typename T>
-u16 verify_u16(T val) {
- return verify_cast<u16>(val);
+template<typename T>
+s32 verify_s32(T val) {
+ return verify_cast<s32>(val);
}
-template<typename T>
-s32 verify_s32(T val) {
- return verify_cast<s32>(val);
+template<typename T>
+u32 verify_u32(T val) {
+ return verify_cast<u32>(val);
}
-template<typename T>
-u32 verify_u32(T val) {
- return verify_cast<u32>(val);
-}
-
} // namespace ue2
#endif // UTIL_VERIFY_TYPES
diff --git a/contrib/libs/hyperscan/ya.make b/contrib/libs/hyperscan/ya.make
index 7b62af4f0fb..7783969e4a2 100644
--- a/contrib/libs/hyperscan/ya.make
+++ b/contrib/libs/hyperscan/ya.make
@@ -26,7 +26,7 @@ PEERDIR(
)
ADDINCL(
- contrib/libs/hyperscan
+ contrib/libs/hyperscan
contrib/libs/hyperscan/include
contrib/libs/hyperscan/src
)
@@ -40,7 +40,7 @@ CFLAGS(
)
SRCS(
- src/alloc.c
+ src/alloc.c
src/compiler/asserts.cpp
src/compiler/compiler.cpp
src/compiler/error.cpp
@@ -57,8 +57,8 @@ SRCS(
src/fdr/teddy_avx2.c
src/fdr/teddy_compile.cpp
src/fdr/teddy_engine_description.cpp
- src/grey.cpp
- src/hs.cpp
+ src/grey.cpp
+ src/hs.cpp
src/hs_valid_platform.c
src/hs_version.c
src/hwlm/hwlm.c
@@ -71,11 +71,11 @@ SRCS(
src/nfa/accelcompile.cpp
src/nfa/castle.c
src/nfa/castlecompile.cpp
- src/nfa/dfa_build_strat.cpp
+ src/nfa/dfa_build_strat.cpp
src/nfa/dfa_min.cpp
src/nfa/gough.c
src/nfa/goughcompile.cpp
- src/nfa/goughcompile_accel.cpp
+ src/nfa/goughcompile_accel.cpp
src/nfa/goughcompile_reg.cpp
src/nfa/lbr.c
src/nfa/limex_64.c
@@ -124,13 +124,13 @@ SRCS(
src/nfagraph/ng_expr_info.cpp
src/nfagraph/ng_extparam.cpp
src/nfagraph/ng_fixed_width.cpp
- src/nfagraph/ng_fuzzy.cpp
+ src/nfagraph/ng_fuzzy.cpp
src/nfagraph/ng_haig.cpp
src/nfagraph/ng_holder.cpp
src/nfagraph/ng_is_equal.cpp
src/nfagraph/ng_lbr.cpp
src/nfagraph/ng_limex.cpp
- src/nfagraph/ng_limex_accel.cpp
+ src/nfagraph/ng_limex_accel.cpp
src/nfagraph/ng_literal_analysis.cpp
src/nfagraph/ng_literal_component.cpp
src/nfagraph/ng_literal_decorated.cpp
@@ -150,7 +150,7 @@ SRCS(
src/nfagraph/ng_sep.cpp
src/nfagraph/ng_small_literal_set.cpp
src/nfagraph/ng_som.cpp
- src/nfagraph/ng_som_add_redundancy.cpp
+ src/nfagraph/ng_som_add_redundancy.cpp
src/nfagraph/ng_som_util.cpp
src/nfagraph/ng_split.cpp
src/nfagraph/ng_squash.cpp
@@ -159,7 +159,7 @@ SRCS(
src/nfagraph/ng_utf8.cpp
src/nfagraph/ng_util.cpp
src/nfagraph/ng_vacuous.cpp
- src/nfagraph/ng_violet.cpp
+ src/nfagraph/ng_violet.cpp
src/nfagraph/ng_width.cpp
src/parser/AsciiComponentClass.cpp
src/parser/Component.cpp
@@ -172,7 +172,7 @@ SRCS(
src/parser/ComponentClass.cpp
src/parser/ComponentCondReference.cpp
src/parser/ComponentEUS.cpp
- src/parser/ComponentEmpty.cpp
+ src/parser/ComponentEmpty.cpp
src/parser/ComponentRepeat.cpp
src/parser/ComponentSequence.cpp
src/parser/ComponentVisitor.cpp
@@ -200,22 +200,22 @@ SRCS(
src/rose/rose_build_add_mask.cpp
src/rose/rose_build_anchored.cpp
src/rose/rose_build_bytecode.cpp
- src/rose/rose_build_castle.cpp
+ src/rose/rose_build_castle.cpp
src/rose/rose_build_compile.cpp
src/rose/rose_build_convert.cpp
- src/rose/rose_build_dedupe.cpp
- src/rose/rose_build_engine_blob.cpp
- src/rose/rose_build_exclusive.cpp
- src/rose/rose_build_groups.cpp
+ src/rose/rose_build_dedupe.cpp
+ src/rose/rose_build_engine_blob.cpp
+ src/rose/rose_build_exclusive.cpp
+ src/rose/rose_build_groups.cpp
src/rose/rose_build_infix.cpp
- src/rose/rose_build_instructions.cpp
- src/rose/rose_build_lit_accel.cpp
- src/rose/rose_build_long_lit.cpp
+ src/rose/rose_build_instructions.cpp
+ src/rose/rose_build_lit_accel.cpp
+ src/rose/rose_build_long_lit.cpp
src/rose/rose_build_lookaround.cpp
- src/rose/rose_build_matchers.cpp
+ src/rose/rose_build_matchers.cpp
src/rose/rose_build_merge.cpp
src/rose/rose_build_misc.cpp
- src/rose/rose_build_program.cpp
+ src/rose/rose_build_program.cpp
src/rose/rose_build_role_aliasing.cpp
src/rose/rose_build_scatter.cpp
src/rose/rose_build_width.cpp
@@ -223,20 +223,20 @@ SRCS(
src/rose/stream.c
src/runtime.c
src/scratch.c
- src/smallwrite/smallwrite_build.cpp
- src/som/slot_manager.cpp
+ src/smallwrite/smallwrite_build.cpp
+ src/som/slot_manager.cpp
src/som/som_runtime.c
src/som/som_stream.c
src/stream_compress.c
src/util/alloc.cpp
src/util/charreach.cpp
- src/util/clique.cpp
+ src/util/clique.cpp
src/util/compile_context.cpp
src/util/compile_error.cpp
src/util/cpuid_flags.c
src/util/depth.cpp
src/util/dump_mask.cpp
- src/util/fatbit_build.cpp
+ src/util/fatbit_build.cpp
src/util/masked_move.c
src/util/multibit.c
src/util/multibit_build.cpp
diff --git a/contrib/libs/ya.make b/contrib/libs/ya.make
index 29784d7c602..9c4640fdcf2 100644
--- a/contrib/libs/ya.make
+++ b/contrib/libs/ya.make
@@ -202,7 +202,7 @@ RECURSE(
libxslt
libyang
libyuv
- linenoise
+ linenoise
linux-headers
linuxvdso
liquidfun
diff --git a/contrib/python/ipython/ya.make b/contrib/python/ipython/ya.make
index a9bb790aaa1..b1dd8c5e235 100644
--- a/contrib/python/ipython/ya.make
+++ b/contrib/python/ipython/ya.make
@@ -1,4 +1,4 @@
-PY23_LIBRARY()
+PY23_LIBRARY()
LICENSE(Service-Py23-Proxy)
diff --git a/contrib/python/jedi/ya.make b/contrib/python/jedi/ya.make
index 806cc8f4834..eff2fef2a7b 100644
--- a/contrib/python/jedi/ya.make
+++ b/contrib/python/jedi/ya.make
@@ -1,4 +1,4 @@
-PY23_LIBRARY(jedi)
+PY23_LIBRARY(jedi)
LICENSE(MIT)
diff --git a/contrib/python/pickleshare/ya.make b/contrib/python/pickleshare/ya.make
index 44ffbaa9c53..e24c2cdad7b 100644
--- a/contrib/python/pickleshare/ya.make
+++ b/contrib/python/pickleshare/ya.make
@@ -25,6 +25,6 @@ RESOURCE_FILES(
PREFIX contrib/python/pickleshare/
.dist-info/METADATA
.dist-info/top_level.txt
-)
-
+)
+
END()
diff --git a/contrib/python/prompt-toolkit/py2/LICENSE b/contrib/python/prompt-toolkit/py2/LICENSE
index 4632fefd7fd..e1720e0fb70 100644
--- a/contrib/python/prompt-toolkit/py2/LICENSE
+++ b/contrib/python/prompt-toolkit/py2/LICENSE
@@ -1,27 +1,27 @@
-Copyright (c) 2014, Jonathan Slenders
-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 {organization} 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 HOLDER 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.
+Copyright (c) 2014, Jonathan Slenders
+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 {organization} 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 HOLDER 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.
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py
index 357270cbb01..6478ba4f9ac 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/__init__.py
@@ -1,22 +1,22 @@
-"""
-prompt_toolkit
-==============
-
-Author: Jonathan Slenders
-
-Description: prompt_toolkit is a Library for building powerful interactive
- command lines in Python. It can be a replacement for GNU
- readline, but it can be much more than that.
-
-See the examples directory to learn about the usage.
-
-Probably, to get started, you meight also want to have a look at
-`prompt_toolkit.shortcuts.prompt`.
-"""
-from .interface import CommandLineInterface
-from .application import AbortAction, Application
+"""
+prompt_toolkit
+==============
+
+Author: Jonathan Slenders
+
+Description: prompt_toolkit is a Library for building powerful interactive
+ command lines in Python. It can be a replacement for GNU
+ readline, but it can be much more than that.
+
+See the examples directory to learn about the usage.
+
+Probably, to get started, you meight also want to have a look at
+`prompt_toolkit.shortcuts.prompt`.
+"""
+from .interface import CommandLineInterface
+from .application import AbortAction, Application
from .shortcuts import prompt, prompt_async
-
-
+
+
# Don't forget to update in `docs/conf.py`!
__version__ = '1.0.18'
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py
index ea6c485f9d6..272d8bbcbb0 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/application.py
@@ -1,126 +1,126 @@
-from __future__ import unicode_literals
-
-from .buffer import Buffer, AcceptAction
-from .buffer_mapping import BufferMapping
-from .clipboard import Clipboard, InMemoryClipboard
+from __future__ import unicode_literals
+
+from .buffer import Buffer, AcceptAction
+from .buffer_mapping import BufferMapping
+from .clipboard import Clipboard, InMemoryClipboard
from .enums import DEFAULT_BUFFER, EditingMode
-from .filters import CLIFilter, to_cli_filter
-from .key_binding.bindings.basic import load_basic_bindings
-from .key_binding.bindings.emacs import load_emacs_bindings
+from .filters import CLIFilter, to_cli_filter
+from .key_binding.bindings.basic import load_basic_bindings
+from .key_binding.bindings.emacs import load_emacs_bindings
from .key_binding.bindings.vi import load_vi_bindings
from .key_binding.registry import BaseRegistry
from .key_binding.defaults import load_key_bindings
-from .layout import Window
-from .layout.containers import Container
-from .layout.controls import BufferControl
-from .styles import DEFAULT_STYLE, Style
+from .layout import Window
+from .layout.containers import Container
+from .layout.controls import BufferControl
+from .styles import DEFAULT_STYLE, Style
import six
-
-__all__ = (
- 'AbortAction',
- 'Application',
-)
-
-
-class AbortAction(object):
- """
- Actions to take on an Exit or Abort exception.
- """
- RETRY = 'retry'
- RAISE_EXCEPTION = 'raise-exception'
- RETURN_NONE = 'return-none'
-
- _all = (RETRY, RAISE_EXCEPTION, RETURN_NONE)
-
-
-class Application(object):
- """
- Application class to be passed to a
- :class:`~prompt_toolkit.interface.CommandLineInterface`.
-
- This contains all customizable logic that is not I/O dependent.
- (So, what is independent of event loops, input and output.)
-
- This way, such an :class:`.Application` can run easily on several
- :class:`~prompt_toolkit.interface.CommandLineInterface` instances, each
- with a different I/O backends. that runs for instance over telnet, SSH or
- any other I/O backend.
-
- :param layout: A :class:`~prompt_toolkit.layout.containers.Container` instance.
- :param buffer: A :class:`~prompt_toolkit.buffer.Buffer` instance for the default buffer.
- :param initial_focussed_buffer: Name of the buffer that is focussed during start-up.
- :param key_bindings_registry:
+
+__all__ = (
+ 'AbortAction',
+ 'Application',
+)
+
+
+class AbortAction(object):
+ """
+ Actions to take on an Exit or Abort exception.
+ """
+ RETRY = 'retry'
+ RAISE_EXCEPTION = 'raise-exception'
+ RETURN_NONE = 'return-none'
+
+ _all = (RETRY, RAISE_EXCEPTION, RETURN_NONE)
+
+
+class Application(object):
+ """
+ Application class to be passed to a
+ :class:`~prompt_toolkit.interface.CommandLineInterface`.
+
+ This contains all customizable logic that is not I/O dependent.
+ (So, what is independent of event loops, input and output.)
+
+ This way, such an :class:`.Application` can run easily on several
+ :class:`~prompt_toolkit.interface.CommandLineInterface` instances, each
+ with a different I/O backends. that runs for instance over telnet, SSH or
+ any other I/O backend.
+
+ :param layout: A :class:`~prompt_toolkit.layout.containers.Container` instance.
+ :param buffer: A :class:`~prompt_toolkit.buffer.Buffer` instance for the default buffer.
+ :param initial_focussed_buffer: Name of the buffer that is focussed during start-up.
+ :param key_bindings_registry:
:class:`~prompt_toolkit.key_binding.registry.BaseRegistry` instance for
the key bindings.
- :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` to use.
- :param on_abort: What to do when Control-C is pressed.
- :param on_exit: What to do when Control-D is pressed.
- :param use_alternate_screen: When True, run the application on the alternate screen buffer.
- :param get_title: Callable that returns the current title to be displayed in the terminal.
+ :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` to use.
+ :param on_abort: What to do when Control-C is pressed.
+ :param on_exit: What to do when Control-D is pressed.
+ :param use_alternate_screen: When True, run the application on the alternate screen buffer.
+ :param get_title: Callable that returns the current title to be displayed in the terminal.
:param erase_when_done: (bool) Clear the application output when it finishes.
:param reverse_vi_search_direction: Normally, in Vi mode, a '/' searches
forward and a '?' searches backward. In readline mode, this is usually
reversed.
-
- Filters:
-
- :param mouse_support: (:class:`~prompt_toolkit.filters.CLIFilter` or
- boolean). When True, enable mouse support.
- :param paste_mode: :class:`~prompt_toolkit.filters.CLIFilter` or boolean.
- :param ignore_case: :class:`~prompt_toolkit.filters.CLIFilter` or boolean.
+
+ Filters:
+
+ :param mouse_support: (:class:`~prompt_toolkit.filters.CLIFilter` or
+ boolean). When True, enable mouse support.
+ :param paste_mode: :class:`~prompt_toolkit.filters.CLIFilter` or boolean.
+ :param ignore_case: :class:`~prompt_toolkit.filters.CLIFilter` or boolean.
:param editing_mode: :class:`~prompt_toolkit.enums.EditingMode`.
-
+
Callbacks (all of these should accept a
:class:`~prompt_toolkit.interface.CommandLineInterface` object as input.)
-
- :param on_input_timeout: Called when there is no input for x seconds.
- (Fired when any eventloop.onInputTimeout is fired.)
- :param on_start: Called when reading input starts.
- :param on_stop: Called when reading input ends.
- :param on_reset: Called during reset.
- :param on_buffer_changed: Called when the content of a buffer has been changed.
- :param on_initialize: Called after the
- :class:`~prompt_toolkit.interface.CommandLineInterface` initializes.
+
+ :param on_input_timeout: Called when there is no input for x seconds.
+ (Fired when any eventloop.onInputTimeout is fired.)
+ :param on_start: Called when reading input starts.
+ :param on_stop: Called when reading input ends.
+ :param on_reset: Called during reset.
+ :param on_buffer_changed: Called when the content of a buffer has been changed.
+ :param on_initialize: Called after the
+ :class:`~prompt_toolkit.interface.CommandLineInterface` initializes.
:param on_render: Called right after rendering.
:param on_invalidate: Called when the UI has been invalidated.
- """
- def __init__(self, layout=None, buffer=None, buffers=None,
- initial_focussed_buffer=DEFAULT_BUFFER,
- style=None,
- key_bindings_registry=None, clipboard=None,
- on_abort=AbortAction.RAISE_EXCEPTION, on_exit=AbortAction.RAISE_EXCEPTION,
- use_alternate_screen=False, mouse_support=False,
- get_title=None,
-
+ """
+ def __init__(self, layout=None, buffer=None, buffers=None,
+ initial_focussed_buffer=DEFAULT_BUFFER,
+ style=None,
+ key_bindings_registry=None, clipboard=None,
+ on_abort=AbortAction.RAISE_EXCEPTION, on_exit=AbortAction.RAISE_EXCEPTION,
+ use_alternate_screen=False, mouse_support=False,
+ get_title=None,
+
paste_mode=False, ignore_case=False, editing_mode=EditingMode.EMACS,
erase_when_done=False,
reverse_vi_search_direction=False,
-
- on_input_timeout=None, on_start=None, on_stop=None,
+
+ on_input_timeout=None, on_start=None, on_stop=None,
on_reset=None, on_initialize=None, on_buffer_changed=None,
on_render=None, on_invalidate=None):
-
- paste_mode = to_cli_filter(paste_mode)
- ignore_case = to_cli_filter(ignore_case)
- mouse_support = to_cli_filter(mouse_support)
+
+ paste_mode = to_cli_filter(paste_mode)
+ ignore_case = to_cli_filter(ignore_case)
+ mouse_support = to_cli_filter(mouse_support)
reverse_vi_search_direction = to_cli_filter(reverse_vi_search_direction)
-
- assert layout is None or isinstance(layout, Container)
- assert buffer is None or isinstance(buffer, Buffer)
- assert buffers is None or isinstance(buffers, (dict, BufferMapping))
+
+ assert layout is None or isinstance(layout, Container)
+ assert buffer is None or isinstance(buffer, Buffer)
+ assert buffers is None or isinstance(buffers, (dict, BufferMapping))
assert key_bindings_registry is None or isinstance(key_bindings_registry, BaseRegistry)
- assert clipboard is None or isinstance(clipboard, Clipboard)
- assert on_abort in AbortAction._all
- assert on_exit in AbortAction._all
- assert isinstance(use_alternate_screen, bool)
- assert get_title is None or callable(get_title)
- assert isinstance(paste_mode, CLIFilter)
- assert isinstance(ignore_case, CLIFilter)
+ assert clipboard is None or isinstance(clipboard, Clipboard)
+ assert on_abort in AbortAction._all
+ assert on_exit in AbortAction._all
+ assert isinstance(use_alternate_screen, bool)
+ assert get_title is None or callable(get_title)
+ assert isinstance(paste_mode, CLIFilter)
+ assert isinstance(ignore_case, CLIFilter)
assert isinstance(editing_mode, six.string_types)
assert on_input_timeout is None or callable(on_input_timeout)
- assert style is None or isinstance(style, Style)
+ assert style is None or isinstance(style, Style)
assert isinstance(erase_when_done, bool)
-
+
assert on_start is None or callable(on_start)
assert on_stop is None or callable(on_stop)
assert on_reset is None or callable(on_reset)
@@ -129,47 +129,47 @@ class Application(object):
assert on_render is None or callable(on_render)
assert on_invalidate is None or callable(on_invalidate)
- self.layout = layout or Window(BufferControl())
-
- # Make sure that the 'buffers' dictionary is a BufferMapping.
+ self.layout = layout or Window(BufferControl())
+
+ # Make sure that the 'buffers' dictionary is a BufferMapping.
# NOTE: If no buffer is given, we create a default Buffer, with IGNORE as
# default accept_action. This is what makes sense for most users
# creating full screen applications. Doing nothing is the obvious
# default. Those creating a REPL would use the shortcuts module that
# passes in RETURN_DOCUMENT.
self.buffer = buffer or Buffer(accept_action=AcceptAction.IGNORE)
- if not buffers or not isinstance(buffers, BufferMapping):
- self.buffers = BufferMapping(buffers, initial=initial_focussed_buffer)
- else:
- self.buffers = buffers
-
- if buffer:
- self.buffers[DEFAULT_BUFFER] = buffer
-
- self.initial_focussed_buffer = initial_focussed_buffer
-
- self.style = style or DEFAULT_STYLE
-
- if key_bindings_registry is None:
+ if not buffers or not isinstance(buffers, BufferMapping):
+ self.buffers = BufferMapping(buffers, initial=initial_focussed_buffer)
+ else:
+ self.buffers = buffers
+
+ if buffer:
+ self.buffers[DEFAULT_BUFFER] = buffer
+
+ self.initial_focussed_buffer = initial_focussed_buffer
+
+ self.style = style or DEFAULT_STYLE
+
+ if key_bindings_registry is None:
key_bindings_registry = load_key_bindings()
-
- if get_title is None:
- get_title = lambda: None
-
- self.key_bindings_registry = key_bindings_registry
- self.clipboard = clipboard or InMemoryClipboard()
- self.on_abort = on_abort
- self.on_exit = on_exit
- self.use_alternate_screen = use_alternate_screen
- self.mouse_support = mouse_support
- self.get_title = get_title
-
- self.paste_mode = paste_mode
- self.ignore_case = ignore_case
+
+ if get_title is None:
+ get_title = lambda: None
+
+ self.key_bindings_registry = key_bindings_registry
+ self.clipboard = clipboard or InMemoryClipboard()
+ self.on_abort = on_abort
+ self.on_exit = on_exit
+ self.use_alternate_screen = use_alternate_screen
+ self.mouse_support = mouse_support
+ self.get_title = get_title
+
+ self.paste_mode = paste_mode
+ self.ignore_case = ignore_case
self.editing_mode = editing_mode
self.erase_when_done = erase_when_done
self.reverse_vi_search_direction = reverse_vi_search_direction
-
+
def dummy_handler(cli):
" Dummy event handler. "
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py
index 5e5eb80ef1a..1d5130521f9 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/auto_suggest.py
@@ -1,88 +1,88 @@
-"""
-`Fish-style <http://fishshell.com/>`_ like auto-suggestion.
-
-While a user types input in a certain buffer, suggestions are generated
-(asynchronously.) Usually, they are displayed after the input. When the cursor
-presses the right arrow and the cursor is at the end of the input, the
-suggestion will be inserted.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-from .filters import to_cli_filter
-
-__all__ = (
- 'Suggestion',
- 'AutoSuggest',
- 'AutoSuggestFromHistory',
- 'ConditionalAutoSuggest',
-)
-
-
-class Suggestion(object):
- """
- Suggestion returned by an auto-suggest algorithm.
-
- :param text: The suggestion text.
- """
- def __init__(self, text):
- self.text = text
-
- def __repr__(self):
- return 'Suggestion(%s)' % self.text
-
-
-class AutoSuggest(with_metaclass(ABCMeta, object)):
- """
- Base class for auto suggestion implementations.
- """
- @abstractmethod
- def get_suggestion(self, cli, buffer, document):
- """
- Return `None` or a :class:`.Suggestion` instance.
-
- We receive both ``buffer`` and ``document``. The reason is that auto
- suggestions are retrieved asynchronously. (Like completions.) The
- buffer text could be changed in the meantime, but ``document`` contains
- the buffer document like it was at the start of the auto suggestion
- call. So, from here, don't access ``buffer.text``, but use
- ``document.text`` instead.
-
- :param buffer: The :class:`~prompt_toolkit.buffer.Buffer` instance.
- :param document: The :class:`~prompt_toolkit.document.Document` instance.
- """
-
-
-class AutoSuggestFromHistory(AutoSuggest):
- """
- Give suggestions based on the lines in the history.
- """
- def get_suggestion(self, cli, buffer, document):
- history = buffer.history
-
- # Consider only the last line for the suggestion.
- text = document.text.rsplit('\n', 1)[-1]
-
- # Only create a suggestion when this is not an empty line.
- if text.strip():
- # Find first matching line in history.
- for string in reversed(list(history)):
- for line in reversed(string.splitlines()):
- if line.startswith(text):
- return Suggestion(line[len(text):])
-
-
-class ConditionalAutoSuggest(AutoSuggest):
- """
- Auto suggest that can be turned on and of according to a certain condition.
- """
- def __init__(self, auto_suggest, filter):
- assert isinstance(auto_suggest, AutoSuggest)
-
- self.auto_suggest = auto_suggest
- self.filter = to_cli_filter(filter)
-
- def get_suggestion(self, cli, buffer, document):
- if self.filter(cli):
- return self.auto_suggest.get_suggestion(cli, buffer, document)
+"""
+`Fish-style <http://fishshell.com/>`_ like auto-suggestion.
+
+While a user types input in a certain buffer, suggestions are generated
+(asynchronously.) Usually, they are displayed after the input. When the cursor
+presses the right arrow and the cursor is at the end of the input, the
+suggestion will be inserted.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+from .filters import to_cli_filter
+
+__all__ = (
+ 'Suggestion',
+ 'AutoSuggest',
+ 'AutoSuggestFromHistory',
+ 'ConditionalAutoSuggest',
+)
+
+
+class Suggestion(object):
+ """
+ Suggestion returned by an auto-suggest algorithm.
+
+ :param text: The suggestion text.
+ """
+ def __init__(self, text):
+ self.text = text
+
+ def __repr__(self):
+ return 'Suggestion(%s)' % self.text
+
+
+class AutoSuggest(with_metaclass(ABCMeta, object)):
+ """
+ Base class for auto suggestion implementations.
+ """
+ @abstractmethod
+ def get_suggestion(self, cli, buffer, document):
+ """
+ Return `None` or a :class:`.Suggestion` instance.
+
+ We receive both ``buffer`` and ``document``. The reason is that auto
+ suggestions are retrieved asynchronously. (Like completions.) The
+ buffer text could be changed in the meantime, but ``document`` contains
+ the buffer document like it was at the start of the auto suggestion
+ call. So, from here, don't access ``buffer.text``, but use
+ ``document.text`` instead.
+
+ :param buffer: The :class:`~prompt_toolkit.buffer.Buffer` instance.
+ :param document: The :class:`~prompt_toolkit.document.Document` instance.
+ """
+
+
+class AutoSuggestFromHistory(AutoSuggest):
+ """
+ Give suggestions based on the lines in the history.
+ """
+ def get_suggestion(self, cli, buffer, document):
+ history = buffer.history
+
+ # Consider only the last line for the suggestion.
+ text = document.text.rsplit('\n', 1)[-1]
+
+ # Only create a suggestion when this is not an empty line.
+ if text.strip():
+ # Find first matching line in history.
+ for string in reversed(list(history)):
+ for line in reversed(string.splitlines()):
+ if line.startswith(text):
+ return Suggestion(line[len(text):])
+
+
+class ConditionalAutoSuggest(AutoSuggest):
+ """
+ Auto suggest that can be turned on and of according to a certain condition.
+ """
+ def __init__(self, auto_suggest, filter):
+ assert isinstance(auto_suggest, AutoSuggest)
+
+ self.auto_suggest = auto_suggest
+ self.filter = to_cli_filter(filter)
+
+ def get_suggestion(self, cli, buffer, document):
+ if self.filter(cli):
+ return self.auto_suggest.get_suggestion(cli, buffer, document)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py
index 6a8b1dc4f51..f5df2898270 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer.py
@@ -1,106 +1,106 @@
-"""
-Data structures for the Buffer.
-It holds the text, cursor position, history, etc...
-"""
-from __future__ import unicode_literals
-
-from .auto_suggest import AutoSuggest
-from .clipboard import ClipboardData
-from .completion import Completer, Completion, CompleteEvent
-from .document import Document
-from .enums import IncrementalSearchDirection
-from .filters import to_simple_filter
-from .history import History, InMemoryHistory
-from .search_state import SearchState
+"""
+Data structures for the Buffer.
+It holds the text, cursor position, history, etc...
+"""
+from __future__ import unicode_literals
+
+from .auto_suggest import AutoSuggest
+from .clipboard import ClipboardData
+from .completion import Completer, Completion, CompleteEvent
+from .document import Document
+from .enums import IncrementalSearchDirection
+from .filters import to_simple_filter
+from .history import History, InMemoryHistory
+from .search_state import SearchState
from .selection import SelectionType, SelectionState, PasteMode
from .utils import Event
from .cache import FastDictCache
-from .validation import ValidationError
-
+from .validation import ValidationError
+
from six.moves import range
-import os
+import os
import re
import shlex
-import six
-import subprocess
-import tempfile
-
-__all__ = (
- 'EditReadOnlyBuffer',
- 'AcceptAction',
- 'Buffer',
- 'indent',
- 'unindent',
+import six
+import subprocess
+import tempfile
+
+__all__ = (
+ 'EditReadOnlyBuffer',
+ 'AcceptAction',
+ 'Buffer',
+ 'indent',
+ 'unindent',
'reshape_text',
-)
-
-
-class EditReadOnlyBuffer(Exception):
- " Attempt editing of read-only :class:`.Buffer`. "
-
-
-class AcceptAction(object):
- """
- What to do when the input is accepted by the user.
- (When Enter was pressed in the command line.)
-
- :param handler: (optional) A callable which takes a
- :class:`~prompt_toolkit.interface.CommandLineInterface` and
- :class:`~prompt_toolkit.document.Document`. It is called when the user
- accepts input.
- """
- def __init__(self, handler=None):
- assert handler is None or callable(handler)
- self.handler = handler
-
- @classmethod
- def run_in_terminal(cls, handler, render_cli_done=False):
- """
- Create an :class:`.AcceptAction` that runs the given handler in the
- terminal.
-
- :param render_cli_done: When True, render the interface in the 'Done'
- state first, then execute the function. If False, erase the
- interface instead.
- """
- def _handler(cli, buffer):
- cli.run_in_terminal(lambda: handler(cli, buffer), render_cli_done=render_cli_done)
- return AcceptAction(handler=_handler)
-
- @property
- def is_returnable(self):
- """
- True when there is something handling accept.
- """
- return bool(self.handler)
-
- def validate_and_handle(self, cli, buffer):
- """
- Validate buffer and handle the accept action.
- """
- if buffer.validate():
- if self.handler:
- self.handler(cli, buffer)
-
- buffer.append_to_history()
-
-
-def _return_document_handler(cli, buffer):
+)
+
+
+class EditReadOnlyBuffer(Exception):
+ " Attempt editing of read-only :class:`.Buffer`. "
+
+
+class AcceptAction(object):
+ """
+ What to do when the input is accepted by the user.
+ (When Enter was pressed in the command line.)
+
+ :param handler: (optional) A callable which takes a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` and
+ :class:`~prompt_toolkit.document.Document`. It is called when the user
+ accepts input.
+ """
+ def __init__(self, handler=None):
+ assert handler is None or callable(handler)
+ self.handler = handler
+
+ @classmethod
+ def run_in_terminal(cls, handler, render_cli_done=False):
+ """
+ Create an :class:`.AcceptAction` that runs the given handler in the
+ terminal.
+
+ :param render_cli_done: When True, render the interface in the 'Done'
+ state first, then execute the function. If False, erase the
+ interface instead.
+ """
+ def _handler(cli, buffer):
+ cli.run_in_terminal(lambda: handler(cli, buffer), render_cli_done=render_cli_done)
+ return AcceptAction(handler=_handler)
+
+ @property
+ def is_returnable(self):
+ """
+ True when there is something handling accept.
+ """
+ return bool(self.handler)
+
+ def validate_and_handle(self, cli, buffer):
+ """
+ Validate buffer and handle the accept action.
+ """
+ if buffer.validate():
+ if self.handler:
+ self.handler(cli, buffer)
+
+ buffer.append_to_history()
+
+
+def _return_document_handler(cli, buffer):
# Set return value.
- cli.set_return_value(buffer.document)
-
+ cli.set_return_value(buffer.document)
+
# Make sure that if we run this UI again, that we reset this buffer, next
# time.
def reset_this_buffer():
buffer.reset()
cli.pre_run_callables.append(reset_this_buffer)
-
-AcceptAction.RETURN_DOCUMENT = AcceptAction(_return_document_handler)
-AcceptAction.IGNORE = AcceptAction(handler=None)
-
-
+
+AcceptAction.RETURN_DOCUMENT = AcceptAction(_return_document_handler)
+AcceptAction.IGNORE = AcceptAction(handler=None)
+
+
class ValidationState(object):
" The validation state of a buffer. This is set after the validation. "
VALID = 'VALID'
@@ -108,63 +108,63 @@ class ValidationState(object):
UNKNOWN = 'UNKNOWN'
-class CompletionState(object):
- """
- Immutable class that contains a completion state.
- """
- def __init__(self, original_document, current_completions=None, complete_index=None):
- #: Document as it was when the completion started.
- self.original_document = original_document
-
- #: List of all the current Completion instances which are possible at
- #: this point.
- self.current_completions = current_completions or []
-
- #: Position in the `current_completions` array.
- #: This can be `None` to indicate "no completion", the original text.
- self.complete_index = complete_index # Position in the `_completions` array.
-
- def __repr__(self):
- return '%s(%r, <%r> completions, index=%r)' % (
- self.__class__.__name__,
- self.original_document, len(self.current_completions), self.complete_index)
-
- def go_to_index(self, index):
- """
- Create a new :class:`.CompletionState` object with the new index.
- """
- return CompletionState(self.original_document, self.current_completions, complete_index=index)
-
- def new_text_and_position(self):
- """
- Return (new_text, new_cursor_position) for this completion.
- """
- if self.complete_index is None:
- return self.original_document.text, self.original_document.cursor_position
- else:
- original_text_before_cursor = self.original_document.text_before_cursor
- original_text_after_cursor = self.original_document.text_after_cursor
-
- c = self.current_completions[self.complete_index]
- if c.start_position == 0:
- before = original_text_before_cursor
- else:
- before = original_text_before_cursor[:c.start_position]
-
- new_text = before + c.text + original_text_after_cursor
- new_cursor_position = len(before) + len(c.text)
- return new_text, new_cursor_position
-
- @property
- def current_completion(self):
- """
- Return the current completion, or return `None` when no completion is
- selected.
- """
- if self.complete_index is not None:
- return self.current_completions[self.complete_index]
-
-
+class CompletionState(object):
+ """
+ Immutable class that contains a completion state.
+ """
+ def __init__(self, original_document, current_completions=None, complete_index=None):
+ #: Document as it was when the completion started.
+ self.original_document = original_document
+
+ #: List of all the current Completion instances which are possible at
+ #: this point.
+ self.current_completions = current_completions or []
+
+ #: Position in the `current_completions` array.
+ #: This can be `None` to indicate "no completion", the original text.
+ self.complete_index = complete_index # Position in the `_completions` array.
+
+ def __repr__(self):
+ return '%s(%r, <%r> completions, index=%r)' % (
+ self.__class__.__name__,
+ self.original_document, len(self.current_completions), self.complete_index)
+
+ def go_to_index(self, index):
+ """
+ Create a new :class:`.CompletionState` object with the new index.
+ """
+ return CompletionState(self.original_document, self.current_completions, complete_index=index)
+
+ def new_text_and_position(self):
+ """
+ Return (new_text, new_cursor_position) for this completion.
+ """
+ if self.complete_index is None:
+ return self.original_document.text, self.original_document.cursor_position
+ else:
+ original_text_before_cursor = self.original_document.text_before_cursor
+ original_text_after_cursor = self.original_document.text_after_cursor
+
+ c = self.current_completions[self.complete_index]
+ if c.start_position == 0:
+ before = original_text_before_cursor
+ else:
+ before = original_text_before_cursor[:c.start_position]
+
+ new_text = before + c.text + original_text_after_cursor
+ new_cursor_position = len(before) + len(c.text)
+ return new_text, new_cursor_position
+
+ @property
+ def current_completion(self):
+ """
+ Return the current completion, or return `None` when no completion is
+ selected.
+ """
+ if self.complete_index is not None:
+ return self.current_completions[self.complete_index]
+
+
_QUOTED_WORDS_RE = re.compile(r"""(\s+|".*?"|'.*?')""")
@@ -183,113 +183,113 @@ class YankNthArgState(object):
self.previous_inserted_word)
-class Buffer(object):
- """
- The core data structure that holds the text and cursor position of the
- current input line and implements all text manupulations on top of it. It
- also implements the history, undo stack and the completion state.
-
- :param completer: :class:`~prompt_toolkit.completion.Completer` instance.
- :param history: :class:`~prompt_toolkit.history.History` instance.
- :param tempfile_suffix: Suffix to be appended to the tempfile for the 'open
- in editor' function.
-
- Events:
-
+class Buffer(object):
+ """
+ The core data structure that holds the text and cursor position of the
+ current input line and implements all text manupulations on top of it. It
+ also implements the history, undo stack and the completion state.
+
+ :param completer: :class:`~prompt_toolkit.completion.Completer` instance.
+ :param history: :class:`~prompt_toolkit.history.History` instance.
+ :param tempfile_suffix: Suffix to be appended to the tempfile for the 'open
+ in editor' function.
+
+ Events:
+
:param on_text_changed: When the buffer text changes. (Callable on None.)
:param on_text_insert: When new text is inserted. (Callable on None.)
:param on_cursor_position_changed: When the cursor moves. (Callable on None.)
-
- Filters:
-
- :param is_multiline: :class:`~prompt_toolkit.filters.SimpleFilter` to
- indicate whether we should consider this buffer a multiline input. If
- so, key bindings can decide to insert newlines when pressing [Enter].
- (Instead of accepting the input.)
- :param complete_while_typing: :class:`~prompt_toolkit.filters.SimpleFilter`
- instance. Decide whether or not to do asynchronous autocompleting while
- typing.
- :param enable_history_search: :class:`~prompt_toolkit.filters.SimpleFilter`
- to indicate when up-arrow partial string matching is enabled. It is
- adviced to not enable this at the same time as `complete_while_typing`,
- because when there is an autocompletion found, the up arrows usually
- browse through the completions, rather than through the history.
- :param read_only: :class:`~prompt_toolkit.filters.SimpleFilter`. When True,
- changes will not be allowed.
- """
- def __init__(self, completer=None, auto_suggest=None, history=None,
- validator=None, tempfile_suffix='',
- is_multiline=False, complete_while_typing=False,
- enable_history_search=False, initial_document=None,
- accept_action=AcceptAction.IGNORE, read_only=False,
- on_text_changed=None, on_text_insert=None, on_cursor_position_changed=None):
-
- # Accept both filters and booleans as input.
- enable_history_search = to_simple_filter(enable_history_search)
- is_multiline = to_simple_filter(is_multiline)
- complete_while_typing = to_simple_filter(complete_while_typing)
- read_only = to_simple_filter(read_only)
-
- # Validate input.
- assert completer is None or isinstance(completer, Completer)
- assert auto_suggest is None or isinstance(auto_suggest, AutoSuggest)
- assert history is None or isinstance(history, History)
+
+ Filters:
+
+ :param is_multiline: :class:`~prompt_toolkit.filters.SimpleFilter` to
+ indicate whether we should consider this buffer a multiline input. If
+ so, key bindings can decide to insert newlines when pressing [Enter].
+ (Instead of accepting the input.)
+ :param complete_while_typing: :class:`~prompt_toolkit.filters.SimpleFilter`
+ instance. Decide whether or not to do asynchronous autocompleting while
+ typing.
+ :param enable_history_search: :class:`~prompt_toolkit.filters.SimpleFilter`
+ to indicate when up-arrow partial string matching is enabled. It is
+ adviced to not enable this at the same time as `complete_while_typing`,
+ because when there is an autocompletion found, the up arrows usually
+ browse through the completions, rather than through the history.
+ :param read_only: :class:`~prompt_toolkit.filters.SimpleFilter`. When True,
+ changes will not be allowed.
+ """
+ def __init__(self, completer=None, auto_suggest=None, history=None,
+ validator=None, tempfile_suffix='',
+ is_multiline=False, complete_while_typing=False,
+ enable_history_search=False, initial_document=None,
+ accept_action=AcceptAction.IGNORE, read_only=False,
+ on_text_changed=None, on_text_insert=None, on_cursor_position_changed=None):
+
+ # Accept both filters and booleans as input.
+ enable_history_search = to_simple_filter(enable_history_search)
+ is_multiline = to_simple_filter(is_multiline)
+ complete_while_typing = to_simple_filter(complete_while_typing)
+ read_only = to_simple_filter(read_only)
+
+ # Validate input.
+ assert completer is None or isinstance(completer, Completer)
+ assert auto_suggest is None or isinstance(auto_suggest, AutoSuggest)
+ assert history is None or isinstance(history, History)
assert on_text_changed is None or callable(on_text_changed)
assert on_text_insert is None or callable(on_text_insert)
assert on_cursor_position_changed is None or callable(on_cursor_position_changed)
-
- self.completer = completer
- self.auto_suggest = auto_suggest
- self.validator = validator
- self.tempfile_suffix = tempfile_suffix
- self.accept_action = accept_action
-
- # Filters. (Usually, used by the key bindings to drive the buffer.)
- self.is_multiline = is_multiline
- self.complete_while_typing = complete_while_typing
- self.enable_history_search = enable_history_search
- self.read_only = read_only
-
+
+ self.completer = completer
+ self.auto_suggest = auto_suggest
+ self.validator = validator
+ self.tempfile_suffix = tempfile_suffix
+ self.accept_action = accept_action
+
+ # Filters. (Usually, used by the key bindings to drive the buffer.)
+ self.is_multiline = is_multiline
+ self.complete_while_typing = complete_while_typing
+ self.enable_history_search = enable_history_search
+ self.read_only = read_only
+
# Text width. (For wrapping, used by the Vi 'gq' operator.)
self.text_width = 0
- #: The command buffer history.
- # Note that we shouldn't use a lazy 'or' here. bool(history) could be
- # False when empty.
- self.history = InMemoryHistory() if history is None else history
-
- self.__cursor_position = 0
-
- # Events
+ #: The command buffer history.
+ # Note that we shouldn't use a lazy 'or' here. bool(history) could be
+ # False when empty.
+ self.history = InMemoryHistory() if history is None else history
+
+ self.__cursor_position = 0
+
+ # Events
self.on_text_changed = Event(self, on_text_changed)
self.on_text_insert = Event(self, on_text_insert)
self.on_cursor_position_changed = Event(self, on_cursor_position_changed)
-
+
# Document cache. (Avoid creating new Document instances.)
self._document_cache = FastDictCache(Document, size=10)
- self.reset(initial_document=initial_document)
-
- def reset(self, initial_document=None, append_to_history=False):
- """
- :param append_to_history: Append current input to history first.
- """
- assert initial_document is None or isinstance(initial_document, Document)
-
- if append_to_history:
- self.append_to_history()
-
- initial_document = initial_document or Document()
-
- self.__cursor_position = initial_document.cursor_position
-
- # `ValidationError` instance. (Will be set when the input is wrong.)
- self.validation_error = None
+ self.reset(initial_document=initial_document)
+
+ def reset(self, initial_document=None, append_to_history=False):
+ """
+ :param append_to_history: Append current input to history first.
+ """
+ assert initial_document is None or isinstance(initial_document, Document)
+
+ if append_to_history:
+ self.append_to_history()
+
+ initial_document = initial_document or Document()
+
+ self.__cursor_position = initial_document.cursor_position
+
+ # `ValidationError` instance. (Will be set when the input is wrong.)
+ self.validation_error = None
self.validation_state = ValidationState.UNKNOWN
-
- # State of the selection.
- self.selection_state = None
-
+
+ # State of the selection.
+ self.selection_state = None
+
# Multiple cursor mode. (When we press 'I' or 'A' in visual-block mode,
# we can insert text on multiple lines at once. This is implemented by
# using multiple cursors.)
@@ -298,9 +298,9 @@ class Buffer(object):
# When doing consecutive up/down movements, prefer to stay at this column.
self.preferred_column = None
- # State of complete browser
- self.complete_state = None # For interactive completion through Ctrl-N/Ctrl-P.
-
+ # State of complete browser
+ self.complete_state = None # For interactive completion through Ctrl-N/Ctrl-P.
+
# State of Emacs yank-nth-arg completion.
self.yank_nth_arg_state = None # for yank-nth-arg.
@@ -308,36 +308,36 @@ class Buffer(object):
# operation. This is used for rotating through the kill ring.
self.document_before_paste = None
- # Current suggestion.
- self.suggestion = None
-
- # The history search text. (Used for filtering the history when we
- # browse through it.)
- self.history_search_text = None
-
- # Undo/redo stacks
- self._undo_stack = [] # Stack of (text, cursor_position)
- self._redo_stack = []
-
- #: The working lines. Similar to history, except that this can be
- #: modified. The user can press arrow_up and edit previous entries.
- #: Ctrl-C should reset this, and copy the whole history back in here.
- #: Enter should process the current command and append to the real
- #: history.
- self._working_lines = self.history.strings[:]
- self._working_lines.append(initial_document.text)
- self.__working_index = len(self._working_lines) - 1
-
- # <getters/setters>
-
- def _set_text(self, value):
- """ set text at current working_index. Return whether it changed. """
+ # Current suggestion.
+ self.suggestion = None
+
+ # The history search text. (Used for filtering the history when we
+ # browse through it.)
+ self.history_search_text = None
+
+ # Undo/redo stacks
+ self._undo_stack = [] # Stack of (text, cursor_position)
+ self._redo_stack = []
+
+ #: The working lines. Similar to history, except that this can be
+ #: modified. The user can press arrow_up and edit previous entries.
+ #: Ctrl-C should reset this, and copy the whole history back in here.
+ #: Enter should process the current command and append to the real
+ #: history.
+ self._working_lines = self.history.strings[:]
+ self._working_lines.append(initial_document.text)
+ self.__working_index = len(self._working_lines) - 1
+
+ # <getters/setters>
+
+ def _set_text(self, value):
+ """ set text at current working_index. Return whether it changed. """
working_index = self.working_index
working_lines = self._working_lines
-
+
original_value = working_lines[working_index]
working_lines[working_index] = value
-
+
# Return True when this text has been changed.
if len(value) != len(original_value):
# For Python 2, it seems that when two strings have a different
@@ -350,190 +350,190 @@ class Buffer(object):
return True
return False
- def _set_cursor_position(self, value):
- """ Set cursor position. Return whether it changed. """
- original_position = self.__cursor_position
- self.__cursor_position = max(0, value)
-
- return value != original_position
-
- @property
- def text(self):
- return self._working_lines[self.working_index]
-
- @text.setter
- def text(self, value):
- """
- Setting text. (When doing this, make sure that the cursor_position is
- valid for this text. text/cursor_position should be consistent at any time,
- otherwise set a Document instead.)
- """
- assert isinstance(value, six.text_type), 'Got %r' % value
- assert self.cursor_position <= len(value)
-
- # Don't allow editing of read-only buffers.
- if self.read_only():
- raise EditReadOnlyBuffer()
-
- changed = self._set_text(value)
-
- if changed:
- self._text_changed()
-
- # Reset history search text.
- self.history_search_text = None
-
- @property
- def cursor_position(self):
- return self.__cursor_position
-
- @cursor_position.setter
- def cursor_position(self, value):
- """
- Setting cursor position.
- """
- assert isinstance(value, int)
- assert value <= len(self.text)
-
- changed = self._set_cursor_position(value)
-
- if changed:
- self._cursor_position_changed()
-
- @property
- def working_index(self):
- return self.__working_index
-
- @working_index.setter
- def working_index(self, value):
- if self.__working_index != value:
- self.__working_index = value
- self._text_changed()
-
- def _text_changed(self):
- # Remove any validation errors and complete state.
- self.validation_error = None
+ def _set_cursor_position(self, value):
+ """ Set cursor position. Return whether it changed. """
+ original_position = self.__cursor_position
+ self.__cursor_position = max(0, value)
+
+ return value != original_position
+
+ @property
+ def text(self):
+ return self._working_lines[self.working_index]
+
+ @text.setter
+ def text(self, value):
+ """
+ Setting text. (When doing this, make sure that the cursor_position is
+ valid for this text. text/cursor_position should be consistent at any time,
+ otherwise set a Document instead.)
+ """
+ assert isinstance(value, six.text_type), 'Got %r' % value
+ assert self.cursor_position <= len(value)
+
+ # Don't allow editing of read-only buffers.
+ if self.read_only():
+ raise EditReadOnlyBuffer()
+
+ changed = self._set_text(value)
+
+ if changed:
+ self._text_changed()
+
+ # Reset history search text.
+ self.history_search_text = None
+
+ @property
+ def cursor_position(self):
+ return self.__cursor_position
+
+ @cursor_position.setter
+ def cursor_position(self, value):
+ """
+ Setting cursor position.
+ """
+ assert isinstance(value, int)
+ assert value <= len(self.text)
+
+ changed = self._set_cursor_position(value)
+
+ if changed:
+ self._cursor_position_changed()
+
+ @property
+ def working_index(self):
+ return self.__working_index
+
+ @working_index.setter
+ def working_index(self, value):
+ if self.__working_index != value:
+ self.__working_index = value
+ self._text_changed()
+
+ def _text_changed(self):
+ # Remove any validation errors and complete state.
+ self.validation_error = None
self.validation_state = ValidationState.UNKNOWN
- self.complete_state = None
+ self.complete_state = None
self.yank_nth_arg_state = None
self.document_before_paste = None
- self.selection_state = None
- self.suggestion = None
+ self.selection_state = None
+ self.suggestion = None
self.preferred_column = None
-
- # fire 'on_text_changed' event.
- self.on_text_changed.fire()
-
- def _cursor_position_changed(self):
- # Remove any validation errors and complete state.
- self.validation_error = None
+
+ # fire 'on_text_changed' event.
+ self.on_text_changed.fire()
+
+ def _cursor_position_changed(self):
+ # Remove any validation errors and complete state.
+ self.validation_error = None
self.validation_state = ValidationState.UNKNOWN
- self.complete_state = None
+ self.complete_state = None
self.yank_nth_arg_state = None
self.document_before_paste = None
-
+
# Unset preferred_column. (Will be set after the cursor movement, if
# required.)
self.preferred_column = None
- # Note that the cursor position can change if we have a selection the
- # new position of the cursor determines the end of the selection.
-
- # fire 'on_cursor_position_changed' event.
- self.on_cursor_position_changed.fire()
-
- @property
- def document(self):
- """
- Return :class:`~prompt_toolkit.document.Document` instance from the
+ # Note that the cursor position can change if we have a selection the
+ # new position of the cursor determines the end of the selection.
+
+ # fire 'on_cursor_position_changed' event.
+ self.on_cursor_position_changed.fire()
+
+ @property
+ def document(self):
+ """
+ Return :class:`~prompt_toolkit.document.Document` instance from the
current text, cursor position and selection state.
- """
+ """
return self._document_cache[
self.text, self.cursor_position, self.selection_state]
-
- @document.setter
- def document(self, value):
- """
- Set :class:`~prompt_toolkit.document.Document` instance.
-
- This will set both the text and cursor position at the same time, but
- atomically. (Change events will be triggered only after both have been set.)
- """
- self.set_document(value)
-
- def set_document(self, value, bypass_readonly=False):
- """
- Set :class:`~prompt_toolkit.document.Document` instance. Like the
- ``document`` property, but accept an ``bypass_readonly`` argument.
-
- :param bypass_readonly: When True, don't raise an
- :class:`.EditReadOnlyBuffer` exception, even
- when the buffer is read-only.
- """
- assert isinstance(value, Document)
-
- # Don't allow editing of read-only buffers.
- if not bypass_readonly and self.read_only():
- raise EditReadOnlyBuffer()
-
- # Set text and cursor position first.
- text_changed = self._set_text(value.text)
- cursor_position_changed = self._set_cursor_position(value.cursor_position)
-
- # Now handle change events. (We do this when text/cursor position is
- # both set and consistent.)
- if text_changed:
- self._text_changed()
-
- if cursor_position_changed:
- self._cursor_position_changed()
-
- # End of <getters/setters>
-
- def save_to_undo_stack(self, clear_redo_stack=True):
- """
- Safe current state (input text and cursor position), so that we can
- restore it by calling undo.
- """
- # Safe if the text is different from the text at the top of the stack
- # is different. If the text is the same, just update the cursor position.
- if self._undo_stack and self._undo_stack[-1][0] == self.text:
- self._undo_stack[-1] = (self._undo_stack[-1][0], self.cursor_position)
- else:
- self._undo_stack.append((self.text, self.cursor_position))
-
- # Saving anything to the undo stack, clears the redo stack.
- if clear_redo_stack:
- self._redo_stack = []
-
- def transform_lines(self, line_index_iterator, transform_callback):
- """
- Transforms the text on a range of lines.
- When the iterator yield an index not in the range of lines that the
- document contains, it skips them silently.
-
- To uppercase some lines::
-
- new_text = transform_lines(range(5,10), lambda text: text.upper())
-
- :param line_index_iterator: Iterator of line numbers (int)
- :param transform_callback: callable that takes the original text of a
- line, and return the new text for this line.
-
- :returns: The new text.
- """
- # Split lines
- lines = self.text.split('\n')
-
- # Apply transformation
- for index in line_index_iterator:
- try:
- lines[index] = transform_callback(lines[index])
- except IndexError:
- pass
-
- return '\n'.join(lines)
-
+
+ @document.setter
+ def document(self, value):
+ """
+ Set :class:`~prompt_toolkit.document.Document` instance.
+
+ This will set both the text and cursor position at the same time, but
+ atomically. (Change events will be triggered only after both have been set.)
+ """
+ self.set_document(value)
+
+ def set_document(self, value, bypass_readonly=False):
+ """
+ Set :class:`~prompt_toolkit.document.Document` instance. Like the
+ ``document`` property, but accept an ``bypass_readonly`` argument.
+
+ :param bypass_readonly: When True, don't raise an
+ :class:`.EditReadOnlyBuffer` exception, even
+ when the buffer is read-only.
+ """
+ assert isinstance(value, Document)
+
+ # Don't allow editing of read-only buffers.
+ if not bypass_readonly and self.read_only():
+ raise EditReadOnlyBuffer()
+
+ # Set text and cursor position first.
+ text_changed = self._set_text(value.text)
+ cursor_position_changed = self._set_cursor_position(value.cursor_position)
+
+ # Now handle change events. (We do this when text/cursor position is
+ # both set and consistent.)
+ if text_changed:
+ self._text_changed()
+
+ if cursor_position_changed:
+ self._cursor_position_changed()
+
+ # End of <getters/setters>
+
+ def save_to_undo_stack(self, clear_redo_stack=True):
+ """
+ Safe current state (input text and cursor position), so that we can
+ restore it by calling undo.
+ """
+ # Safe if the text is different from the text at the top of the stack
+ # is different. If the text is the same, just update the cursor position.
+ if self._undo_stack and self._undo_stack[-1][0] == self.text:
+ self._undo_stack[-1] = (self._undo_stack[-1][0], self.cursor_position)
+ else:
+ self._undo_stack.append((self.text, self.cursor_position))
+
+ # Saving anything to the undo stack, clears the redo stack.
+ if clear_redo_stack:
+ self._redo_stack = []
+
+ def transform_lines(self, line_index_iterator, transform_callback):
+ """
+ Transforms the text on a range of lines.
+ When the iterator yield an index not in the range of lines that the
+ document contains, it skips them silently.
+
+ To uppercase some lines::
+
+ new_text = transform_lines(range(5,10), lambda text: text.upper())
+
+ :param line_index_iterator: Iterator of line numbers (int)
+ :param transform_callback: callable that takes the original text of a
+ line, and return the new text for this line.
+
+ :returns: The new text.
+ """
+ # Split lines
+ lines = self.text.split('\n')
+
+ # Apply transformation
+ for index in line_index_iterator:
+ try:
+ lines[index] = transform_callback(lines[index])
+ except IndexError:
+ pass
+
+ return '\n'.join(lines)
+
def transform_current_line(self, transform_callback):
"""
Apply the given transformation function to the current line.
@@ -548,364 +548,364 @@ class Buffer(object):
transform_callback(document.text[a:b]) +
document.text[b:])
- def transform_region(self, from_, to, transform_callback):
- """
- Transform a part of the input string.
-
- :param from_: (int) start position.
- :param to: (int) end position.
- :param transform_callback: Callable which accepts a string and returns
- the transformed string.
- """
- assert from_ < to
-
- self.text = ''.join([
- self.text[:from_] +
- transform_callback(self.text[from_:to]) +
- self.text[to:]
- ])
-
- def cursor_left(self, count=1):
- self.cursor_position += self.document.get_cursor_left_position(count=count)
-
- def cursor_right(self, count=1):
- self.cursor_position += self.document.get_cursor_right_position(count=count)
-
- def cursor_up(self, count=1):
- """ (for multiline edit). Move cursor to the previous line. """
+ def transform_region(self, from_, to, transform_callback):
+ """
+ Transform a part of the input string.
+
+ :param from_: (int) start position.
+ :param to: (int) end position.
+ :param transform_callback: Callable which accepts a string and returns
+ the transformed string.
+ """
+ assert from_ < to
+
+ self.text = ''.join([
+ self.text[:from_] +
+ transform_callback(self.text[from_:to]) +
+ self.text[to:]
+ ])
+
+ def cursor_left(self, count=1):
+ self.cursor_position += self.document.get_cursor_left_position(count=count)
+
+ def cursor_right(self, count=1):
+ self.cursor_position += self.document.get_cursor_right_position(count=count)
+
+ def cursor_up(self, count=1):
+ """ (for multiline edit). Move cursor to the previous line. """
original_column = self.preferred_column or self.document.cursor_position_col
self.cursor_position += self.document.get_cursor_up_position(
count=count, preferred_column=original_column)
-
+
# Remember the original column for the next up/down movement.
self.preferred_column = original_column
- def cursor_down(self, count=1):
- """ (for multiline edit). Move cursor to the next line. """
+ def cursor_down(self, count=1):
+ """ (for multiline edit). Move cursor to the next line. """
original_column = self.preferred_column or self.document.cursor_position_col
self.cursor_position += self.document.get_cursor_down_position(
count=count, preferred_column=original_column)
-
+
# Remember the original column for the next up/down movement.
self.preferred_column = original_column
def auto_up(self, count=1, go_to_start_of_line_if_history_changes=False):
- """
- If we're not on the first line (of a multiline input) go a line up,
- otherwise go back in history. (If nothing is selected.)
- """
- if self.complete_state:
- self.complete_previous(count=count)
- elif self.document.cursor_position_row > 0:
+ """
+ If we're not on the first line (of a multiline input) go a line up,
+ otherwise go back in history. (If nothing is selected.)
+ """
+ if self.complete_state:
+ self.complete_previous(count=count)
+ elif self.document.cursor_position_row > 0:
self.cursor_up(count=count)
- elif not self.selection_state:
- self.history_backward(count=count)
-
+ elif not self.selection_state:
+ self.history_backward(count=count)
+
# Go to the start of the line?
if go_to_start_of_line_if_history_changes:
self.cursor_position += self.document.get_start_of_line_position()
def auto_down(self, count=1, go_to_start_of_line_if_history_changes=False):
- """
- If we're not on the last line (of a multiline input) go a line down,
- otherwise go forward in history. (If nothing is selected.)
- """
- if self.complete_state:
- self.complete_next(count=count)
- elif self.document.cursor_position_row < self.document.line_count - 1:
+ """
+ If we're not on the last line (of a multiline input) go a line down,
+ otherwise go forward in history. (If nothing is selected.)
+ """
+ if self.complete_state:
+ self.complete_next(count=count)
+ elif self.document.cursor_position_row < self.document.line_count - 1:
self.cursor_down(count=count)
- elif not self.selection_state:
- self.history_forward(count=count)
-
+ elif not self.selection_state:
+ self.history_forward(count=count)
+
# Go to the start of the line?
if go_to_start_of_line_if_history_changes:
self.cursor_position += self.document.get_start_of_line_position()
- def delete_before_cursor(self, count=1):
- """
+ def delete_before_cursor(self, count=1):
+ """
Delete specified number of characters before cursor and return the
deleted text.
- """
- assert count >= 0
- deleted = ''
-
- if self.cursor_position > 0:
- deleted = self.text[self.cursor_position - count:self.cursor_position]
-
- new_text = self.text[:self.cursor_position - count] + self.text[self.cursor_position:]
- new_cursor_position = self.cursor_position - len(deleted)
-
- # Set new Document atomically.
- self.document = Document(new_text, new_cursor_position)
-
- return deleted
-
- def delete(self, count=1):
- """
+ """
+ assert count >= 0
+ deleted = ''
+
+ if self.cursor_position > 0:
+ deleted = self.text[self.cursor_position - count:self.cursor_position]
+
+ new_text = self.text[:self.cursor_position - count] + self.text[self.cursor_position:]
+ new_cursor_position = self.cursor_position - len(deleted)
+
+ # Set new Document atomically.
+ self.document = Document(new_text, new_cursor_position)
+
+ return deleted
+
+ def delete(self, count=1):
+ """
Delete specified number of characters and Return the deleted text.
- """
- if self.cursor_position < len(self.text):
- deleted = self.document.text_after_cursor[:count]
- self.text = self.text[:self.cursor_position] + \
- self.text[self.cursor_position + len(deleted):]
- return deleted
- else:
- return ''
-
+ """
+ if self.cursor_position < len(self.text):
+ deleted = self.document.text_after_cursor[:count]
+ self.text = self.text[:self.cursor_position] + \
+ self.text[self.cursor_position + len(deleted):]
+ return deleted
+ else:
+ return ''
+
def join_next_line(self, separator=' '):
- """
- Join the next line to the current one by deleting the line ending after
- the current line.
- """
- if not self.document.on_last_line:
- self.cursor_position += self.document.get_end_of_line_position()
- self.delete()
-
- # Remove spaces.
+ """
+ Join the next line to the current one by deleting the line ending after
+ the current line.
+ """
+ if not self.document.on_last_line:
+ self.cursor_position += self.document.get_end_of_line_position()
+ self.delete()
+
+ # Remove spaces.
self.text = (self.document.text_before_cursor + separator +
- self.document.text_after_cursor.lstrip(' '))
-
+ self.document.text_after_cursor.lstrip(' '))
+
def join_selected_lines(self, separator=' '):
- """
- Join the selected lines.
- """
- assert self.selection_state
-
- # Get lines.
- from_, to = sorted([self.cursor_position, self.selection_state.original_cursor_position])
-
- before = self.text[:from_]
- lines = self.text[from_:to].splitlines()
- after = self.text[to:]
-
- # Replace leading spaces with just one space.
+ """
+ Join the selected lines.
+ """
+ assert self.selection_state
+
+ # Get lines.
+ from_, to = sorted([self.cursor_position, self.selection_state.original_cursor_position])
+
+ before = self.text[:from_]
+ lines = self.text[from_:to].splitlines()
+ after = self.text[to:]
+
+ # Replace leading spaces with just one space.
lines = [l.lstrip(' ') + separator for l in lines]
-
- # Set new document.
- self.document = Document(text=before + ''.join(lines) + after,
- cursor_position=len(before + ''.join(lines[:-1])) - 1)
-
- def swap_characters_before_cursor(self):
- """
- Swap the last two characters before the cursor.
- """
- pos = self.cursor_position
-
- if pos >= 2:
- a = self.text[pos - 2]
- b = self.text[pos - 1]
-
- self.text = self.text[:pos-2] + b + a + self.text[pos:]
-
- def go_to_history(self, index):
- """
- Go to this item in the history.
- """
- if index < len(self._working_lines):
- self.working_index = index
- self.cursor_position = len(self.text)
-
- def complete_next(self, count=1, disable_wrap_around=False):
- """
- Browse to the next completions.
- (Does nothing if there are no completion.)
- """
- if self.complete_state:
- completions_count = len(self.complete_state.current_completions)
-
- if self.complete_state.complete_index is None:
- index = 0
- elif self.complete_state.complete_index == completions_count - 1:
- index = None
-
- if disable_wrap_around:
- return
- else:
- index = min(completions_count-1, self.complete_state.complete_index + count)
- self.go_to_completion(index)
-
- def complete_previous(self, count=1, disable_wrap_around=False):
- """
- Browse to the previous completions.
- (Does nothing if there are no completion.)
- """
- if self.complete_state:
- if self.complete_state.complete_index == 0:
- index = None
-
- if disable_wrap_around:
- return
- elif self.complete_state.complete_index is None:
- index = len(self.complete_state.current_completions) - 1
- else:
- index = max(0, self.complete_state.complete_index - count)
-
- self.go_to_completion(index)
-
- def cancel_completion(self):
- """
- Cancel completion, go back to the original text.
- """
- if self.complete_state:
- self.go_to_completion(None)
- self.complete_state = None
-
- def set_completions(self, completions, go_to_first=True, go_to_last=False):
- """
- Start completions. (Generate list of completions and initialize.)
- """
- assert not (go_to_first and go_to_last)
-
- # Generate list of all completions.
- if completions is None:
- if self.completer:
- completions = list(self.completer.get_completions(
- self.document,
- CompleteEvent(completion_requested=True)
- ))
- else:
- completions = []
-
- # Set `complete_state`.
- if completions:
- self.complete_state = CompletionState(
- original_document=self.document,
- current_completions=completions)
- if go_to_first:
- self.go_to_completion(0)
- elif go_to_last:
- self.go_to_completion(len(completions) - 1)
- else:
- self.go_to_completion(None)
-
- else:
- self.complete_state = None
-
- def start_history_lines_completion(self):
- """
- Start a completion based on all the other lines in the document and the
- history.
- """
- found_completions = set()
- completions = []
-
- # For every line of the whole history, find matches with the current line.
- current_line = self.document.current_line_before_cursor.lstrip()
-
- for i, string in enumerate(self._working_lines):
- for j, l in enumerate(string.split('\n')):
- l = l.strip()
- if l and l.startswith(current_line):
- # When a new line has been found.
- if l not in found_completions:
- found_completions.add(l)
-
- # Create completion.
- if i == self.working_index:
- display_meta = "Current, line %s" % (j+1)
- else:
- display_meta = "History %s, line %s" % (i+1, j+1)
-
- completions.append(Completion(
- l,
- start_position=-len(current_line),
- display_meta=display_meta))
-
- self.set_completions(completions=completions[::-1])
-
- def go_to_completion(self, index):
- """
- Select a completion from the list of current completions.
- """
- assert index is None or isinstance(index, int)
- assert self.complete_state
-
- # Set new completion
- state = self.complete_state.go_to_index(index)
-
- # Set text/cursor position
- new_text, new_cursor_position = state.new_text_and_position()
- self.document = Document(new_text, new_cursor_position)
-
- # (changing text/cursor position will unset complete_state.)
- self.complete_state = state
-
- def apply_completion(self, completion):
- """
- Insert a given completion.
- """
- assert isinstance(completion, Completion)
-
- # If there was already a completion active, cancel that one.
- if self.complete_state:
- self.go_to_completion(None)
- self.complete_state = None
-
- # Insert text from the given completion.
- self.delete_before_cursor(-completion.start_position)
- self.insert_text(completion.text)
-
- def _set_history_search(self):
- """ Set `history_search_text`. """
- if self.enable_history_search():
- if self.history_search_text is None:
+
+ # Set new document.
+ self.document = Document(text=before + ''.join(lines) + after,
+ cursor_position=len(before + ''.join(lines[:-1])) - 1)
+
+ def swap_characters_before_cursor(self):
+ """
+ Swap the last two characters before the cursor.
+ """
+ pos = self.cursor_position
+
+ if pos >= 2:
+ a = self.text[pos - 2]
+ b = self.text[pos - 1]
+
+ self.text = self.text[:pos-2] + b + a + self.text[pos:]
+
+ def go_to_history(self, index):
+ """
+ Go to this item in the history.
+ """
+ if index < len(self._working_lines):
+ self.working_index = index
+ self.cursor_position = len(self.text)
+
+ def complete_next(self, count=1, disable_wrap_around=False):
+ """
+ Browse to the next completions.
+ (Does nothing if there are no completion.)
+ """
+ if self.complete_state:
+ completions_count = len(self.complete_state.current_completions)
+
+ if self.complete_state.complete_index is None:
+ index = 0
+ elif self.complete_state.complete_index == completions_count - 1:
+ index = None
+
+ if disable_wrap_around:
+ return
+ else:
+ index = min(completions_count-1, self.complete_state.complete_index + count)
+ self.go_to_completion(index)
+
+ def complete_previous(self, count=1, disable_wrap_around=False):
+ """
+ Browse to the previous completions.
+ (Does nothing if there are no completion.)
+ """
+ if self.complete_state:
+ if self.complete_state.complete_index == 0:
+ index = None
+
+ if disable_wrap_around:
+ return
+ elif self.complete_state.complete_index is None:
+ index = len(self.complete_state.current_completions) - 1
+ else:
+ index = max(0, self.complete_state.complete_index - count)
+
+ self.go_to_completion(index)
+
+ def cancel_completion(self):
+ """
+ Cancel completion, go back to the original text.
+ """
+ if self.complete_state:
+ self.go_to_completion(None)
+ self.complete_state = None
+
+ def set_completions(self, completions, go_to_first=True, go_to_last=False):
+ """
+ Start completions. (Generate list of completions and initialize.)
+ """
+ assert not (go_to_first and go_to_last)
+
+ # Generate list of all completions.
+ if completions is None:
+ if self.completer:
+ completions = list(self.completer.get_completions(
+ self.document,
+ CompleteEvent(completion_requested=True)
+ ))
+ else:
+ completions = []
+
+ # Set `complete_state`.
+ if completions:
+ self.complete_state = CompletionState(
+ original_document=self.document,
+ current_completions=completions)
+ if go_to_first:
+ self.go_to_completion(0)
+ elif go_to_last:
+ self.go_to_completion(len(completions) - 1)
+ else:
+ self.go_to_completion(None)
+
+ else:
+ self.complete_state = None
+
+ def start_history_lines_completion(self):
+ """
+ Start a completion based on all the other lines in the document and the
+ history.
+ """
+ found_completions = set()
+ completions = []
+
+ # For every line of the whole history, find matches with the current line.
+ current_line = self.document.current_line_before_cursor.lstrip()
+
+ for i, string in enumerate(self._working_lines):
+ for j, l in enumerate(string.split('\n')):
+ l = l.strip()
+ if l and l.startswith(current_line):
+ # When a new line has been found.
+ if l not in found_completions:
+ found_completions.add(l)
+
+ # Create completion.
+ if i == self.working_index:
+ display_meta = "Current, line %s" % (j+1)
+ else:
+ display_meta = "History %s, line %s" % (i+1, j+1)
+
+ completions.append(Completion(
+ l,
+ start_position=-len(current_line),
+ display_meta=display_meta))
+
+ self.set_completions(completions=completions[::-1])
+
+ def go_to_completion(self, index):
+ """
+ Select a completion from the list of current completions.
+ """
+ assert index is None or isinstance(index, int)
+ assert self.complete_state
+
+ # Set new completion
+ state = self.complete_state.go_to_index(index)
+
+ # Set text/cursor position
+ new_text, new_cursor_position = state.new_text_and_position()
+ self.document = Document(new_text, new_cursor_position)
+
+ # (changing text/cursor position will unset complete_state.)
+ self.complete_state = state
+
+ def apply_completion(self, completion):
+ """
+ Insert a given completion.
+ """
+ assert isinstance(completion, Completion)
+
+ # If there was already a completion active, cancel that one.
+ if self.complete_state:
+ self.go_to_completion(None)
+ self.complete_state = None
+
+ # Insert text from the given completion.
+ self.delete_before_cursor(-completion.start_position)
+ self.insert_text(completion.text)
+
+ def _set_history_search(self):
+ """ Set `history_search_text`. """
+ if self.enable_history_search():
+ if self.history_search_text is None:
self.history_search_text = self.document.text_before_cursor
- else:
- self.history_search_text = None
-
- def _history_matches(self, i):
- """
- True when the current entry matches the history search.
- (when we don't have history search, it's also True.)
- """
- return (self.history_search_text is None or
- self._working_lines[i].startswith(self.history_search_text))
-
- def history_forward(self, count=1):
- """
- Move forwards through the history.
-
- :param count: Amount of items to move forward.
- """
- self._set_history_search()
-
- # Go forward in history.
- found_something = False
-
- for i in range(self.working_index + 1, len(self._working_lines)):
- if self._history_matches(i):
- self.working_index = i
- count -= 1
- found_something = True
- if count == 0:
- break
-
- # If we found an entry, move cursor to the end of the first line.
- if found_something:
- self.cursor_position = 0
- self.cursor_position += self.document.get_end_of_line_position()
-
- def history_backward(self, count=1):
- """
- Move backwards through history.
- """
- self._set_history_search()
-
- # Go back in history.
- found_something = False
-
- for i in range(self.working_index - 1, -1, -1):
- if self._history_matches(i):
- self.working_index = i
- count -= 1
- found_something = True
- if count == 0:
- break
-
- # If we move to another entry, move cursor to the end of the line.
- if found_something:
- self.cursor_position = len(self.text)
-
+ else:
+ self.history_search_text = None
+
+ def _history_matches(self, i):
+ """
+ True when the current entry matches the history search.
+ (when we don't have history search, it's also True.)
+ """
+ return (self.history_search_text is None or
+ self._working_lines[i].startswith(self.history_search_text))
+
+ def history_forward(self, count=1):
+ """
+ Move forwards through the history.
+
+ :param count: Amount of items to move forward.
+ """
+ self._set_history_search()
+
+ # Go forward in history.
+ found_something = False
+
+ for i in range(self.working_index + 1, len(self._working_lines)):
+ if self._history_matches(i):
+ self.working_index = i
+ count -= 1
+ found_something = True
+ if count == 0:
+ break
+
+ # If we found an entry, move cursor to the end of the first line.
+ if found_something:
+ self.cursor_position = 0
+ self.cursor_position += self.document.get_end_of_line_position()
+
+ def history_backward(self, count=1):
+ """
+ Move backwards through history.
+ """
+ self._set_history_search()
+
+ # Go back in history.
+ found_something = False
+
+ for i in range(self.working_index - 1, -1, -1):
+ if self._history_matches(i):
+ self.working_index = i
+ count -= 1
+ found_something = True
+ if count == 0:
+ break
+
+ # If we move to another entry, move cursor to the end of the line.
+ if found_something:
+ self.cursor_position = len(self.text)
+
def yank_nth_arg(self, n=None, _yank_last_arg=False):
"""
Pick nth word from previous history entry (depending on current
@@ -963,36 +963,36 @@ class Buffer(object):
"""
self.yank_nth_arg(n=n, _yank_last_arg=True)
- def start_selection(self, selection_type=SelectionType.CHARACTERS):
- """
- Take the current cursor position as the start of this selection.
- """
- self.selection_state = SelectionState(self.cursor_position, selection_type)
-
- def copy_selection(self, _cut=False):
- """
- Copy selected text and return :class:`.ClipboardData` instance.
- """
- new_document, clipboard_data = self.document.cut_selection()
- if _cut:
- self.document = new_document
-
- self.selection_state = None
- return clipboard_data
-
- def cut_selection(self):
- """
- Delete selected text and return :class:`.ClipboardData` instance.
- """
- return self.copy_selection(_cut=True)
-
+ def start_selection(self, selection_type=SelectionType.CHARACTERS):
+ """
+ Take the current cursor position as the start of this selection.
+ """
+ self.selection_state = SelectionState(self.cursor_position, selection_type)
+
+ def copy_selection(self, _cut=False):
+ """
+ Copy selected text and return :class:`.ClipboardData` instance.
+ """
+ new_document, clipboard_data = self.document.cut_selection()
+ if _cut:
+ self.document = new_document
+
+ self.selection_state = None
+ return clipboard_data
+
+ def cut_selection(self):
+ """
+ Delete selected text and return :class:`.ClipboardData` instance.
+ """
+ return self.copy_selection(_cut=True)
+
def paste_clipboard_data(self, data, paste_mode=PasteMode.EMACS, count=1):
- """
- Insert the data from the clipboard.
- """
- assert isinstance(data, ClipboardData)
+ """
+ Insert the data from the clipboard.
+ """
+ assert isinstance(data, ClipboardData)
assert paste_mode in (PasteMode.VI_BEFORE, PasteMode.VI_AFTER, PasteMode.EMACS)
-
+
original_document = self.document
self.document = self.document.paste_clipboard_data(data, paste_mode=paste_mode, count=count)
@@ -1000,219 +1000,219 @@ class Buffer(object):
# because assigning to 'document' will erase it.
self.document_before_paste = original_document
- def newline(self, copy_margin=True):
- """
- Insert a line ending at the current position.
- """
- if copy_margin:
- self.insert_text('\n' + self.document.leading_whitespace_in_current_line)
- else:
- self.insert_text('\n')
-
- def insert_line_above(self, copy_margin=True):
- """
- Insert a new line above the current one.
- """
- if copy_margin:
- insert = self.document.leading_whitespace_in_current_line + '\n'
- else:
- insert = '\n'
-
- self.cursor_position += self.document.get_start_of_line_position()
- self.insert_text(insert)
- self.cursor_position -= 1
-
- def insert_line_below(self, copy_margin=True):
- """
- Insert a new line below the current one.
- """
- if copy_margin:
- insert = '\n' + self.document.leading_whitespace_in_current_line
- else:
- insert = '\n'
-
- self.cursor_position += self.document.get_end_of_line_position()
- self.insert_text(insert)
-
- def insert_text(self, data, overwrite=False, move_cursor=True, fire_event=True):
- """
- Insert characters at cursor position.
-
- :param fire_event: Fire `on_text_insert` event. This is mainly used to
- trigger autocompletion while typing.
- """
+ def newline(self, copy_margin=True):
+ """
+ Insert a line ending at the current position.
+ """
+ if copy_margin:
+ self.insert_text('\n' + self.document.leading_whitespace_in_current_line)
+ else:
+ self.insert_text('\n')
+
+ def insert_line_above(self, copy_margin=True):
+ """
+ Insert a new line above the current one.
+ """
+ if copy_margin:
+ insert = self.document.leading_whitespace_in_current_line + '\n'
+ else:
+ insert = '\n'
+
+ self.cursor_position += self.document.get_start_of_line_position()
+ self.insert_text(insert)
+ self.cursor_position -= 1
+
+ def insert_line_below(self, copy_margin=True):
+ """
+ Insert a new line below the current one.
+ """
+ if copy_margin:
+ insert = '\n' + self.document.leading_whitespace_in_current_line
+ else:
+ insert = '\n'
+
+ self.cursor_position += self.document.get_end_of_line_position()
+ self.insert_text(insert)
+
+ def insert_text(self, data, overwrite=False, move_cursor=True, fire_event=True):
+ """
+ Insert characters at cursor position.
+
+ :param fire_event: Fire `on_text_insert` event. This is mainly used to
+ trigger autocompletion while typing.
+ """
# Original text & cursor position.
otext = self.text
ocpos = self.cursor_position
- # In insert/text mode.
- if overwrite:
+ # In insert/text mode.
+ if overwrite:
# Don't overwrite the newline itself. Just before the line ending,
# it should act like insert mode.
overwritten_text = otext[ocpos:ocpos + len(data)]
- if '\n' in overwritten_text:
- overwritten_text = overwritten_text[:overwritten_text.find('\n')]
-
+ if '\n' in overwritten_text:
+ overwritten_text = overwritten_text[:overwritten_text.find('\n')]
+
self.text = otext[:ocpos] + data + otext[ocpos + len(overwritten_text):]
- else:
+ else:
self.text = otext[:ocpos] + data + otext[ocpos:]
-
- if move_cursor:
- self.cursor_position += len(data)
-
- # Fire 'on_text_insert' event.
- if fire_event:
- self.on_text_insert.fire()
-
- def undo(self):
- # Pop from the undo-stack until we find a text that if different from
- # the current text. (The current logic of `save_to_undo_stack` will
- # cause that the top of the undo stack is usually the same as the
- # current text, so in that case we have to pop twice.)
- while self._undo_stack:
- text, pos = self._undo_stack.pop()
-
- if text != self.text:
- # Push current text to redo stack.
- self._redo_stack.append((self.text, self.cursor_position))
-
- # Set new text/cursor_position.
- self.document = Document(text, cursor_position=pos)
- break
-
- def redo(self):
- if self._redo_stack:
- # Copy current state on undo stack.
- self.save_to_undo_stack(clear_redo_stack=False)
-
- # Pop state from redo stack.
- text, pos = self._redo_stack.pop()
- self.document = Document(text, cursor_position=pos)
-
- def validate(self):
- """
- Returns `True` if valid.
- """
+
+ if move_cursor:
+ self.cursor_position += len(data)
+
+ # Fire 'on_text_insert' event.
+ if fire_event:
+ self.on_text_insert.fire()
+
+ def undo(self):
+ # Pop from the undo-stack until we find a text that if different from
+ # the current text. (The current logic of `save_to_undo_stack` will
+ # cause that the top of the undo stack is usually the same as the
+ # current text, so in that case we have to pop twice.)
+ while self._undo_stack:
+ text, pos = self._undo_stack.pop()
+
+ if text != self.text:
+ # Push current text to redo stack.
+ self._redo_stack.append((self.text, self.cursor_position))
+
+ # Set new text/cursor_position.
+ self.document = Document(text, cursor_position=pos)
+ break
+
+ def redo(self):
+ if self._redo_stack:
+ # Copy current state on undo stack.
+ self.save_to_undo_stack(clear_redo_stack=False)
+
+ # Pop state from redo stack.
+ text, pos = self._redo_stack.pop()
+ self.document = Document(text, cursor_position=pos)
+
+ def validate(self):
+ """
+ Returns `True` if valid.
+ """
# Don't call the validator again, if it was already called for the
# current input.
if self.validation_state != ValidationState.UNKNOWN:
return self.validation_state == ValidationState.VALID
-
- # Validate first. If not valid, set validation exception.
- if self.validator:
- try:
- self.validator.validate(self.document)
- except ValidationError as e:
- # Set cursor position (don't allow invalid values.)
- cursor_position = e.cursor_position
- self.cursor_position = min(max(0, cursor_position), len(self.text))
-
+
+ # Validate first. If not valid, set validation exception.
+ if self.validator:
+ try:
+ self.validator.validate(self.document)
+ except ValidationError as e:
+ # Set cursor position (don't allow invalid values.)
+ cursor_position = e.cursor_position
+ self.cursor_position = min(max(0, cursor_position), len(self.text))
+
self.validation_state = ValidationState.INVALID
- self.validation_error = e
- return False
-
+ self.validation_error = e
+ return False
+
self.validation_state = ValidationState.VALID
self.validation_error = None
- return True
-
- def append_to_history(self):
- """
- Append the current input to the history.
- (Only if valid input.)
- """
- # Validate first. If not valid, set validation exception.
- if not self.validate():
- return
-
- # Save at the tail of the history. (But don't if the last entry the
- # history is already the same.)
- if self.text and (not len(self.history) or self.history[-1] != self.text):
- self.history.append(self.text)
-
- def _search(self, search_state, include_current_position=False, count=1):
- """
- Execute search. Return (working_index, cursor_position) tuple when this
- search is applied. Returns `None` when this text cannot be found.
- """
- assert isinstance(search_state, SearchState)
- assert isinstance(count, int) and count > 0
-
- text = search_state.text
- direction = search_state.direction
- ignore_case = search_state.ignore_case()
-
- def search_once(working_index, document):
- """
- Do search one time.
- Return (working_index, document) or `None`
- """
- if direction == IncrementalSearchDirection.FORWARD:
- # Try find at the current input.
- new_index = document.find(
- text, include_current_position=include_current_position,
- ignore_case=ignore_case)
-
- if new_index is not None:
- return (working_index,
- Document(document.text, document.cursor_position + new_index))
- else:
- # No match, go forward in the history. (Include len+1 to wrap around.)
- # (Here we should always include all cursor positions, because
- # it's a different line.)
- for i in range(working_index + 1, len(self._working_lines) + 1):
- i %= len(self._working_lines)
-
- document = Document(self._working_lines[i], 0)
- new_index = document.find(text, include_current_position=True,
- ignore_case=ignore_case)
- if new_index is not None:
- return (i, Document(document.text, new_index))
- else:
- # Try find at the current input.
- new_index = document.find_backwards(
- text, ignore_case=ignore_case)
-
- if new_index is not None:
- return (working_index,
- Document(document.text, document.cursor_position + new_index))
- else:
- # No match, go back in the history. (Include -1 to wrap around.)
- for i in range(working_index - 1, -2, -1):
- i %= len(self._working_lines)
-
- document = Document(self._working_lines[i], len(self._working_lines[i]))
- new_index = document.find_backwards(
- text, ignore_case=ignore_case)
- if new_index is not None:
- return (i, Document(document.text, len(document.text) + new_index))
-
- # Do 'count' search iterations.
- working_index = self.working_index
- document = self.document
- for _ in range(count):
- result = search_once(working_index, document)
- if result is None:
+ return True
+
+ def append_to_history(self):
+ """
+ Append the current input to the history.
+ (Only if valid input.)
+ """
+ # Validate first. If not valid, set validation exception.
+ if not self.validate():
+ return
+
+ # Save at the tail of the history. (But don't if the last entry the
+ # history is already the same.)
+ if self.text and (not len(self.history) or self.history[-1] != self.text):
+ self.history.append(self.text)
+
+ def _search(self, search_state, include_current_position=False, count=1):
+ """
+ Execute search. Return (working_index, cursor_position) tuple when this
+ search is applied. Returns `None` when this text cannot be found.
+ """
+ assert isinstance(search_state, SearchState)
+ assert isinstance(count, int) and count > 0
+
+ text = search_state.text
+ direction = search_state.direction
+ ignore_case = search_state.ignore_case()
+
+ def search_once(working_index, document):
+ """
+ Do search one time.
+ Return (working_index, document) or `None`
+ """
+ if direction == IncrementalSearchDirection.FORWARD:
+ # Try find at the current input.
+ new_index = document.find(
+ text, include_current_position=include_current_position,
+ ignore_case=ignore_case)
+
+ if new_index is not None:
+ return (working_index,
+ Document(document.text, document.cursor_position + new_index))
+ else:
+ # No match, go forward in the history. (Include len+1 to wrap around.)
+ # (Here we should always include all cursor positions, because
+ # it's a different line.)
+ for i in range(working_index + 1, len(self._working_lines) + 1):
+ i %= len(self._working_lines)
+
+ document = Document(self._working_lines[i], 0)
+ new_index = document.find(text, include_current_position=True,
+ ignore_case=ignore_case)
+ if new_index is not None:
+ return (i, Document(document.text, new_index))
+ else:
+ # Try find at the current input.
+ new_index = document.find_backwards(
+ text, ignore_case=ignore_case)
+
+ if new_index is not None:
+ return (working_index,
+ Document(document.text, document.cursor_position + new_index))
+ else:
+ # No match, go back in the history. (Include -1 to wrap around.)
+ for i in range(working_index - 1, -2, -1):
+ i %= len(self._working_lines)
+
+ document = Document(self._working_lines[i], len(self._working_lines[i]))
+ new_index = document.find_backwards(
+ text, ignore_case=ignore_case)
+ if new_index is not None:
+ return (i, Document(document.text, len(document.text) + new_index))
+
+ # Do 'count' search iterations.
+ working_index = self.working_index
+ document = self.document
+ for _ in range(count):
+ result = search_once(working_index, document)
+ if result is None:
return # Nothing found.
- else:
- working_index, document = result
-
- return (working_index, document.cursor_position)
-
- def document_for_search(self, search_state):
- """
- Return a :class:`~prompt_toolkit.document.Document` instance that has
+ else:
+ working_index, document = result
+
+ return (working_index, document.cursor_position)
+
+ def document_for_search(self, search_state):
+ """
+ Return a :class:`~prompt_toolkit.document.Document` instance that has
the text/cursor position for this search, if we would apply it. This
will be used in the
:class:`~prompt_toolkit.layout.controls.BufferControl` to display
feedback while searching.
- """
- search_result = self._search(search_state, include_current_position=True)
-
- if search_result is None:
- return self.document
- else:
- working_index, cursor_position = search_result
-
+ """
+ search_result = self._search(search_state, include_current_position=True)
+
+ if search_result is None:
+ return self.document
+ else:
+ working_index, cursor_position = search_result
+
# Keep selection, when `working_index` was not changed.
if working_index == self.working_index:
selection = self.selection_state
@@ -1237,137 +1237,137 @@ class Buffer(object):
working_index, cursor_position = search_result
return cursor_position
- def apply_search(self, search_state, include_current_position=True, count=1):
- """
- Apply search. If something is found, set `working_index` and
- `cursor_position`.
- """
+ def apply_search(self, search_state, include_current_position=True, count=1):
+ """
+ Apply search. If something is found, set `working_index` and
+ `cursor_position`.
+ """
search_result = self._search(
search_state, include_current_position=include_current_position, count=count)
-
- if search_result is not None:
- working_index, cursor_position = search_result
- self.working_index = working_index
- self.cursor_position = cursor_position
-
- def exit_selection(self):
- self.selection_state = None
-
- def open_in_editor(self, cli):
- """
- Open code in editor.
-
- :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`
- instance.
- """
- if self.read_only():
- raise EditReadOnlyBuffer()
-
- # Write to temporary file
- descriptor, filename = tempfile.mkstemp(self.tempfile_suffix)
- os.write(descriptor, self.text.encode('utf-8'))
- os.close(descriptor)
-
- # Open in editor
- # (We need to use `cli.run_in_terminal`, because not all editors go to
- # the alternate screen buffer, and some could influence the cursor
- # position.)
- succes = cli.run_in_terminal(lambda: self._open_file_in_editor(filename))
-
- # Read content again.
- if succes:
- with open(filename, 'rb') as f:
- text = f.read().decode('utf-8')
-
- # Drop trailing newline. (Editors are supposed to add it at the
- # end, but we don't need it.)
- if text.endswith('\n'):
- text = text[:-1]
-
- self.document = Document(
- text=text,
- cursor_position=len(text))
-
- # Clean up temp file.
- os.remove(filename)
-
- def _open_file_in_editor(self, filename):
- """
- Call editor executable.
-
- Return True when we received a zero return code.
- """
+
+ if search_result is not None:
+ working_index, cursor_position = search_result
+ self.working_index = working_index
+ self.cursor_position = cursor_position
+
+ def exit_selection(self):
+ self.selection_state = None
+
+ def open_in_editor(self, cli):
+ """
+ Open code in editor.
+
+ :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`
+ instance.
+ """
+ if self.read_only():
+ raise EditReadOnlyBuffer()
+
+ # Write to temporary file
+ descriptor, filename = tempfile.mkstemp(self.tempfile_suffix)
+ os.write(descriptor, self.text.encode('utf-8'))
+ os.close(descriptor)
+
+ # Open in editor
+ # (We need to use `cli.run_in_terminal`, because not all editors go to
+ # the alternate screen buffer, and some could influence the cursor
+ # position.)
+ succes = cli.run_in_terminal(lambda: self._open_file_in_editor(filename))
+
+ # Read content again.
+ if succes:
+ with open(filename, 'rb') as f:
+ text = f.read().decode('utf-8')
+
+ # Drop trailing newline. (Editors are supposed to add it at the
+ # end, but we don't need it.)
+ if text.endswith('\n'):
+ text = text[:-1]
+
+ self.document = Document(
+ text=text,
+ cursor_position=len(text))
+
+ # Clean up temp file.
+ os.remove(filename)
+
+ def _open_file_in_editor(self, filename):
+ """
+ Call editor executable.
+
+ Return True when we received a zero return code.
+ """
# If the 'VISUAL' or 'EDITOR' environment variable has been set, use that.
- # Otherwise, fall back to the first available editor that we can find.
+ # Otherwise, fall back to the first available editor that we can find.
visual = os.environ.get('VISUAL')
- editor = os.environ.get('EDITOR')
-
- editors = [
+ editor = os.environ.get('EDITOR')
+
+ editors = [
visual,
- editor,
-
- # Order of preference.
- '/usr/bin/editor',
- '/usr/bin/nano',
- '/usr/bin/pico',
- '/usr/bin/vi',
- '/usr/bin/emacs',
- ]
-
- for e in editors:
- if e:
- try:
+ editor,
+
+ # Order of preference.
+ '/usr/bin/editor',
+ '/usr/bin/nano',
+ '/usr/bin/pico',
+ '/usr/bin/vi',
+ '/usr/bin/emacs',
+ ]
+
+ for e in editors:
+ if e:
+ try:
# Use 'shlex.split()', because $VISUAL can contain spaces
# and quotes.
returncode = subprocess.call(shlex.split(e) + [filename])
- return returncode == 0
-
- except OSError:
- # Executable does not exist, try the next one.
- pass
-
- return False
-
-
-def indent(buffer, from_row, to_row, count=1):
- """
- Indent text of a :class:`.Buffer` object.
- """
- current_row = buffer.document.cursor_position_row
- line_range = range(from_row, to_row)
-
- # Apply transformation.
- new_text = buffer.transform_lines(line_range, lambda l: ' ' * count + l)
- buffer.document = Document(
- new_text,
- Document(new_text).translate_row_col_to_index(current_row, 0))
-
- # Go to the start of the line.
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
-
-
-def unindent(buffer, from_row, to_row, count=1):
- """
- Unindent text of a :class:`.Buffer` object.
- """
- current_row = buffer.document.cursor_position_row
- line_range = range(from_row, to_row)
-
- def transform(text):
- remove = ' ' * count
- if text.startswith(remove):
- return text[len(remove):]
- else:
- return text.lstrip()
-
- # Apply transformation.
- new_text = buffer.transform_lines(line_range, transform)
- buffer.document = Document(
- new_text,
- Document(new_text).translate_row_col_to_index(current_row, 0))
-
- # Go to the start of the line.
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+ return returncode == 0
+
+ except OSError:
+ # Executable does not exist, try the next one.
+ pass
+
+ return False
+
+
+def indent(buffer, from_row, to_row, count=1):
+ """
+ Indent text of a :class:`.Buffer` object.
+ """
+ current_row = buffer.document.cursor_position_row
+ line_range = range(from_row, to_row)
+
+ # Apply transformation.
+ new_text = buffer.transform_lines(line_range, lambda l: ' ' * count + l)
+ buffer.document = Document(
+ new_text,
+ Document(new_text).translate_row_col_to_index(current_row, 0))
+
+ # Go to the start of the line.
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+
+
+def unindent(buffer, from_row, to_row, count=1):
+ """
+ Unindent text of a :class:`.Buffer` object.
+ """
+ current_row = buffer.document.cursor_position_row
+ line_range = range(from_row, to_row)
+
+ def transform(text):
+ remove = ' ' * count
+ if text.startswith(remove):
+ return text[len(remove):]
+ else:
+ return text.lstrip()
+
+ # Apply transformation.
+ new_text = buffer.transform_lines(line_range, transform)
+ buffer.document = Document(
+ new_text,
+ Document(new_text).translate_row_col_to_index(current_row, 0))
+
+ # Go to the start of the line.
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
def reshape_text(buffer, from_row, to_row):
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py
index 99884ddd03d..34f443bd47a 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/buffer_mapping.py
@@ -1,92 +1,92 @@
-"""
-The BufferMapping contains all the buffers for a command line interface, and it
-keeps track of which buffer gets the focus.
-"""
-from __future__ import unicode_literals
-from .enums import DEFAULT_BUFFER, SEARCH_BUFFER, SYSTEM_BUFFER, DUMMY_BUFFER
-from .buffer import Buffer, AcceptAction
-from .history import InMemoryHistory
-
-import six
-
-__all__ = (
- 'BufferMapping',
-)
-
-
-class BufferMapping(dict):
- """
- Dictionary that maps the name of the buffers to the
- :class:`~prompt_toolkit.buffer.Buffer` instances.
-
- This mapping also keeps track of which buffer currently has the focus.
- (Some methods receive a 'cli' parameter. This is useful for applications
- where this `BufferMapping` is shared between several applications.)
- """
- def __init__(self, buffers=None, initial=DEFAULT_BUFFER):
- assert buffers is None or isinstance(buffers, dict)
-
- # Start with an empty dict.
- super(BufferMapping, self).__init__()
-
- # Add default buffers.
- self.update({
- # For the 'search' and 'system' buffers, 'returnable' is False, in
- # order to block normal Enter/ControlC behaviour.
- DEFAULT_BUFFER: Buffer(accept_action=AcceptAction.RETURN_DOCUMENT),
- SEARCH_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE),
- SYSTEM_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE),
- DUMMY_BUFFER: Buffer(read_only=True),
- })
-
- # Add received buffers.
- if buffers is not None:
- self.update(buffers)
-
- # Focus stack.
- self.focus_stack = [initial or DEFAULT_BUFFER]
-
- def current(self, cli):
- """
- The active :class:`.Buffer`.
- """
- return self[self.focus_stack[-1]]
-
- def current_name(self, cli):
- """
- The name of the active :class:`.Buffer`.
- """
- return self.focus_stack[-1]
-
- def previous(self, cli):
- """
- Return the previously focussed :class:`.Buffer` or `None`.
- """
- if len(self.focus_stack) > 1:
- try:
- return self[self.focus_stack[-2]]
- except KeyError:
- pass
-
- def focus(self, cli, buffer_name):
- """
- Focus the buffer with the given name.
- """
- assert isinstance(buffer_name, six.text_type)
- self.focus_stack = [buffer_name]
-
- def push_focus(self, cli, buffer_name):
- """
- Push buffer on the focus stack.
- """
- assert isinstance(buffer_name, six.text_type)
- self.focus_stack.append(buffer_name)
-
- def pop_focus(self, cli):
- """
- Pop buffer from the focus stack.
- """
- if len(self.focus_stack) > 1:
- self.focus_stack.pop()
- else:
- raise IndexError('Cannot pop last item from the focus stack.')
+"""
+The BufferMapping contains all the buffers for a command line interface, and it
+keeps track of which buffer gets the focus.
+"""
+from __future__ import unicode_literals
+from .enums import DEFAULT_BUFFER, SEARCH_BUFFER, SYSTEM_BUFFER, DUMMY_BUFFER
+from .buffer import Buffer, AcceptAction
+from .history import InMemoryHistory
+
+import six
+
+__all__ = (
+ 'BufferMapping',
+)
+
+
+class BufferMapping(dict):
+ """
+ Dictionary that maps the name of the buffers to the
+ :class:`~prompt_toolkit.buffer.Buffer` instances.
+
+ This mapping also keeps track of which buffer currently has the focus.
+ (Some methods receive a 'cli' parameter. This is useful for applications
+ where this `BufferMapping` is shared between several applications.)
+ """
+ def __init__(self, buffers=None, initial=DEFAULT_BUFFER):
+ assert buffers is None or isinstance(buffers, dict)
+
+ # Start with an empty dict.
+ super(BufferMapping, self).__init__()
+
+ # Add default buffers.
+ self.update({
+ # For the 'search' and 'system' buffers, 'returnable' is False, in
+ # order to block normal Enter/ControlC behaviour.
+ DEFAULT_BUFFER: Buffer(accept_action=AcceptAction.RETURN_DOCUMENT),
+ SEARCH_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE),
+ SYSTEM_BUFFER: Buffer(history=InMemoryHistory(), accept_action=AcceptAction.IGNORE),
+ DUMMY_BUFFER: Buffer(read_only=True),
+ })
+
+ # Add received buffers.
+ if buffers is not None:
+ self.update(buffers)
+
+ # Focus stack.
+ self.focus_stack = [initial or DEFAULT_BUFFER]
+
+ def current(self, cli):
+ """
+ The active :class:`.Buffer`.
+ """
+ return self[self.focus_stack[-1]]
+
+ def current_name(self, cli):
+ """
+ The name of the active :class:`.Buffer`.
+ """
+ return self.focus_stack[-1]
+
+ def previous(self, cli):
+ """
+ Return the previously focussed :class:`.Buffer` or `None`.
+ """
+ if len(self.focus_stack) > 1:
+ try:
+ return self[self.focus_stack[-2]]
+ except KeyError:
+ pass
+
+ def focus(self, cli, buffer_name):
+ """
+ Focus the buffer with the given name.
+ """
+ assert isinstance(buffer_name, six.text_type)
+ self.focus_stack = [buffer_name]
+
+ def push_focus(self, cli, buffer_name):
+ """
+ Push buffer on the focus stack.
+ """
+ assert isinstance(buffer_name, six.text_type)
+ self.focus_stack.append(buffer_name)
+
+ def pop_focus(self, cli):
+ """
+ Pop buffer from the focus stack.
+ """
+ if len(self.focus_stack) > 1:
+ self.focus_stack.pop()
+ else:
+ raise IndexError('Cannot pop last item from the focus stack.')
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py
index 5c9cc8df31b..56202ddd3bd 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/__init__.py
@@ -1,8 +1,8 @@
-from .base import Clipboard, ClipboardData
-from .in_memory import InMemoryClipboard
-
-
-# We are not importing `PyperclipClipboard` here, because it would require the
-# `pyperclip` module to be present.
-
-#from .pyperclip import PyperclipClipboard
+from .base import Clipboard, ClipboardData
+from .in_memory import InMemoryClipboard
+
+
+# We are not importing `PyperclipClipboard` here, because it would require the
+# `pyperclip` module to be present.
+
+#from .pyperclip import PyperclipClipboard
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py
index 71be6148eb7..803c0b0e7d8 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/base.py
@@ -1,62 +1,62 @@
-"""
-Clipboard for command line interface.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-import six
-
-from prompt_toolkit.selection import SelectionType
-
-__all__ = (
- 'Clipboard',
- 'ClipboardData',
-)
-
-
-class ClipboardData(object):
- """
- Text on the clipboard.
-
- :param text: string
- :param type: :class:`~prompt_toolkit.selection.SelectionType`
- """
- def __init__(self, text='', type=SelectionType.CHARACTERS):
- assert isinstance(text, six.string_types)
- assert type in (SelectionType.CHARACTERS, SelectionType.LINES, SelectionType.BLOCK)
-
- self.text = text
- self.type = type
-
-
-class Clipboard(with_metaclass(ABCMeta, object)):
- """
- Abstract baseclass for clipboards.
- (An implementation can be in memory, it can share the X11 or Windows
- keyboard, or can be persistent.)
- """
- @abstractmethod
- def set_data(self, data):
- """
- Set data to the clipboard.
-
- :param data: :class:`~.ClipboardData` instance.
- """
-
- def set_text(self, text): # Not abstract.
- """
- Shortcut for setting plain text on clipboard.
- """
- assert isinstance(text, six.string_types)
- self.set_data(ClipboardData(text))
-
+"""
+Clipboard for command line interface.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+import six
+
+from prompt_toolkit.selection import SelectionType
+
+__all__ = (
+ 'Clipboard',
+ 'ClipboardData',
+)
+
+
+class ClipboardData(object):
+ """
+ Text on the clipboard.
+
+ :param text: string
+ :param type: :class:`~prompt_toolkit.selection.SelectionType`
+ """
+ def __init__(self, text='', type=SelectionType.CHARACTERS):
+ assert isinstance(text, six.string_types)
+ assert type in (SelectionType.CHARACTERS, SelectionType.LINES, SelectionType.BLOCK)
+
+ self.text = text
+ self.type = type
+
+
+class Clipboard(with_metaclass(ABCMeta, object)):
+ """
+ Abstract baseclass for clipboards.
+ (An implementation can be in memory, it can share the X11 or Windows
+ keyboard, or can be persistent.)
+ """
+ @abstractmethod
+ def set_data(self, data):
+ """
+ Set data to the clipboard.
+
+ :param data: :class:`~.ClipboardData` instance.
+ """
+
+ def set_text(self, text): # Not abstract.
+ """
+ Shortcut for setting plain text on clipboard.
+ """
+ assert isinstance(text, six.string_types)
+ self.set_data(ClipboardData(text))
+
def rotate(self):
"""
For Emacs mode, rotate the kill ring.
"""
- @abstractmethod
- def get_data(self):
- """
- Return clipboard data.
- """
+ @abstractmethod
+ def get_data(self):
+ """
+ Return clipboard data.
+ """
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py
index a8591b91f93..081666ab808 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/in_memory.py
@@ -1,36 +1,36 @@
-from .base import Clipboard, ClipboardData
-
+from .base import Clipboard, ClipboardData
+
from collections import deque
-__all__ = (
- 'InMemoryClipboard',
-)
-
-
-class InMemoryClipboard(Clipboard):
- """
- Default clipboard implementation.
- Just keep the data in memory.
+__all__ = (
+ 'InMemoryClipboard',
+)
+
+
+class InMemoryClipboard(Clipboard):
+ """
+ Default clipboard implementation.
+ Just keep the data in memory.
This implements a kill-ring, for Emacs mode.
- """
+ """
def __init__(self, data=None, max_size=60):
assert data is None or isinstance(data, ClipboardData)
assert max_size >= 1
-
+
self.max_size = max_size
self._ring = deque()
if data is not None:
self.set_data(data)
- def set_data(self, data):
- assert isinstance(data, ClipboardData)
+ def set_data(self, data):
+ assert isinstance(data, ClipboardData)
self._ring.appendleft(data)
-
+
while len(self._ring) > self.max_size:
self._ring.pop()
- def get_data(self):
+ def get_data(self):
if self._ring:
return self._ring[0]
else:
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py
index 2dc49ae8cba..61ab3aac0ab 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/clipboard/pyperclip.py
@@ -1,39 +1,39 @@
-from __future__ import absolute_import, unicode_literals
-import pyperclip
-
-from prompt_toolkit.selection import SelectionType
-from .base import Clipboard, ClipboardData
-
-__all__ = (
- 'PyperclipClipboard',
-)
-
-
-class PyperclipClipboard(Clipboard):
- """
- Clipboard that synchronizes with the Windows/Mac/Linux system clipboard,
- using the pyperclip module.
- """
- def __init__(self):
- self._data = None
-
- def set_data(self, data):
- assert isinstance(data, ClipboardData)
- self._data = data
- pyperclip.copy(data.text)
-
- def get_data(self):
- text = pyperclip.paste()
-
- # When the clipboard data is equal to what we copied last time, reuse
- # the `ClipboardData` instance. That way we're sure to keep the same
- # `SelectionType`.
- if self._data and self._data.text == text:
- return self._data
-
- # Pyperclip returned something else. Create a new `ClipboardData`
- # instance.
- else:
- return ClipboardData(
- text=text,
- type=SelectionType.LINES if '\n' in text else SelectionType.LINES)
+from __future__ import absolute_import, unicode_literals
+import pyperclip
+
+from prompt_toolkit.selection import SelectionType
+from .base import Clipboard, ClipboardData
+
+__all__ = (
+ 'PyperclipClipboard',
+)
+
+
+class PyperclipClipboard(Clipboard):
+ """
+ Clipboard that synchronizes with the Windows/Mac/Linux system clipboard,
+ using the pyperclip module.
+ """
+ def __init__(self):
+ self._data = None
+
+ def set_data(self, data):
+ assert isinstance(data, ClipboardData)
+ self._data = data
+ pyperclip.copy(data.text)
+
+ def get_data(self):
+ text = pyperclip.paste()
+
+ # When the clipboard data is equal to what we copied last time, reuse
+ # the `ClipboardData` instance. That way we're sure to keep the same
+ # `SelectionType`.
+ if self._data and self._data.text == text:
+ return self._data
+
+ # Pyperclip returned something else. Create a new `ClipboardData`
+ # instance.
+ else:
+ return ClipboardData(
+ text=text,
+ type=SelectionType.LINES if '\n' in text else SelectionType.LINES)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py
index 2d9897a2042..339738ab979 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/completion.py
@@ -1,45 +1,45 @@
-"""
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-__all__ = (
- 'Completion',
- 'Completer',
- 'CompleteEvent',
- 'get_common_complete_suffix',
-)
-
-
-class Completion(object):
- """
- :param text: The new string that will be inserted into the document.
- :param start_position: Position relative to the cursor_position where the
- new text will start. The text will be inserted between the
- start_position and the original cursor position.
- :param display: (optional string) If the completion has to be displayed
- differently in the completion menu.
- :param display_meta: (Optional string) Meta information about the
- completion, e.g. the path or source where it's coming from.
- :param get_display_meta: Lazy `display_meta`. Retrieve meta information
- only when meta is displayed.
- """
- def __init__(self, text, start_position=0, display=None, display_meta=None,
- get_display_meta=None):
- self.text = text
- self.start_position = start_position
- self._display_meta = display_meta
- self._get_display_meta = get_display_meta
-
- if display is None:
- self.display = text
- else:
- self.display = display
-
- assert self.start_position <= 0
-
- def __repr__(self):
+"""
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+__all__ = (
+ 'Completion',
+ 'Completer',
+ 'CompleteEvent',
+ 'get_common_complete_suffix',
+)
+
+
+class Completion(object):
+ """
+ :param text: The new string that will be inserted into the document.
+ :param start_position: Position relative to the cursor_position where the
+ new text will start. The text will be inserted between the
+ start_position and the original cursor position.
+ :param display: (optional string) If the completion has to be displayed
+ differently in the completion menu.
+ :param display_meta: (Optional string) Meta information about the
+ completion, e.g. the path or source where it's coming from.
+ :param get_display_meta: Lazy `display_meta`. Retrieve meta information
+ only when meta is displayed.
+ """
+ def __init__(self, text, start_position=0, display=None, display_meta=None,
+ get_display_meta=None):
+ self.text = text
+ self.start_position = start_position
+ self._display_meta = display_meta
+ self._get_display_meta = get_display_meta
+
+ if display is None:
+ self.display = text
+ else:
+ self.display = display
+
+ assert self.start_position <= 0
+
+ def __repr__(self):
if self.display == self.text:
return '%s(text=%r, start_position=%r)' % (
self.__class__.__name__, self.text, self.start_position)
@@ -47,30 +47,30 @@ class Completion(object):
return '%s(text=%r, start_position=%r, display=%r)' % (
self.__class__.__name__, self.text, self.start_position,
self.display)
-
- def __eq__(self, other):
- return (
- self.text == other.text and
- self.start_position == other.start_position and
- self.display == other.display and
- self.display_meta == other.display_meta)
-
- def __hash__(self):
- return hash((self.text, self.start_position, self.display, self.display_meta))
-
- @property
- def display_meta(self):
- # Return meta-text. (This is lazy when using "get_display_meta".)
- if self._display_meta is not None:
- return self._display_meta
-
- elif self._get_display_meta:
- self._display_meta = self._get_display_meta()
- return self._display_meta
-
- else:
- return ''
-
+
+ def __eq__(self, other):
+ return (
+ self.text == other.text and
+ self.start_position == other.start_position and
+ self.display == other.display and
+ self.display_meta == other.display_meta)
+
+ def __hash__(self):
+ return hash((self.text, self.start_position, self.display, self.display_meta))
+
+ @property
+ def display_meta(self):
+ # Return meta-text. (This is lazy when using "get_display_meta".)
+ if self._display_meta is not None:
+ return self._display_meta
+
+ elif self._get_display_meta:
+ self._display_meta = self._get_display_meta()
+ return self._display_meta
+
+ else:
+ return ''
+
def new_completion_from_position(self, position):
"""
(Only for internal use!)
@@ -79,7 +79,7 @@ class Completion(object):
after inserting the common prefix.
"""
assert isinstance(position, int) and position - self.start_position >= 0
-
+
return Completion(
text=self.text[position - self.start_position:],
display=self.display,
@@ -87,84 +87,84 @@ class Completion(object):
get_display_meta=self._get_display_meta)
-class CompleteEvent(object):
- """
- Event that called the completer.
-
- :param text_inserted: When True, it means that completions are requested
- because of a text insert. (`Buffer.complete_while_typing`.)
- :param completion_requested: When True, it means that the user explicitely
- pressed the `Tab` key in order to view the completions.
-
- These two flags can be used for instance to implemented a completer that
- shows some completions when ``Tab`` has been pressed, but not
- automatically when the user presses a space. (Because of
- `complete_while_typing`.)
- """
- def __init__(self, text_inserted=False, completion_requested=False):
- assert not (text_inserted and completion_requested)
-
- #: Automatic completion while typing.
- self.text_inserted = text_inserted
-
- #: Used explicitely requested completion by pressing 'tab'.
- self.completion_requested = completion_requested
-
- def __repr__(self):
- return '%s(text_inserted=%r, completion_requested=%r)' % (
- self.__class__.__name__, self.text_inserted, self.completion_requested)
-
-
-class Completer(with_metaclass(ABCMeta, object)):
- """
- Base class for completer implementations.
- """
- @abstractmethod
- def get_completions(self, document, complete_event):
- """
- Yield :class:`.Completion` instances.
-
- :param document: :class:`~prompt_toolkit.document.Document` instance.
- :param complete_event: :class:`.CompleteEvent` instance.
- """
- while False:
- yield
-
-
-def get_common_complete_suffix(document, completions):
- """
- Return the common prefix for all completions.
- """
- # Take only completions that don't change the text before the cursor.
- def doesnt_change_before_cursor(completion):
- end = completion.text[:-completion.start_position]
- return document.text_before_cursor.endswith(end)
-
+class CompleteEvent(object):
+ """
+ Event that called the completer.
+
+ :param text_inserted: When True, it means that completions are requested
+ because of a text insert. (`Buffer.complete_while_typing`.)
+ :param completion_requested: When True, it means that the user explicitely
+ pressed the `Tab` key in order to view the completions.
+
+ These two flags can be used for instance to implemented a completer that
+ shows some completions when ``Tab`` has been pressed, but not
+ automatically when the user presses a space. (Because of
+ `complete_while_typing`.)
+ """
+ def __init__(self, text_inserted=False, completion_requested=False):
+ assert not (text_inserted and completion_requested)
+
+ #: Automatic completion while typing.
+ self.text_inserted = text_inserted
+
+ #: Used explicitely requested completion by pressing 'tab'.
+ self.completion_requested = completion_requested
+
+ def __repr__(self):
+ return '%s(text_inserted=%r, completion_requested=%r)' % (
+ self.__class__.__name__, self.text_inserted, self.completion_requested)
+
+
+class Completer(with_metaclass(ABCMeta, object)):
+ """
+ Base class for completer implementations.
+ """
+ @abstractmethod
+ def get_completions(self, document, complete_event):
+ """
+ Yield :class:`.Completion` instances.
+
+ :param document: :class:`~prompt_toolkit.document.Document` instance.
+ :param complete_event: :class:`.CompleteEvent` instance.
+ """
+ while False:
+ yield
+
+
+def get_common_complete_suffix(document, completions):
+ """
+ Return the common prefix for all completions.
+ """
+ # Take only completions that don't change the text before the cursor.
+ def doesnt_change_before_cursor(completion):
+ end = completion.text[:-completion.start_position]
+ return document.text_before_cursor.endswith(end)
+
completions2 = [c for c in completions if doesnt_change_before_cursor(c)]
-
+
# When there is at least one completion that changes the text before the
# cursor, don't return any common part.
if len(completions2) != len(completions):
return ''
- # Return the common prefix.
- def get_suffix(completion):
- return completion.text[-completion.start_position:]
-
+ # Return the common prefix.
+ def get_suffix(completion):
+ return completion.text[-completion.start_position:]
+
return _commonprefix([get_suffix(c) for c in completions2])
-
-
-def _commonprefix(strings):
- # Similar to os.path.commonprefix
- if not strings:
- return ''
-
- else:
- s1 = min(strings)
- s2 = max(strings)
-
- for i, c in enumerate(s1):
- if c != s2[i]:
- return s1[:i]
-
- return s1
+
+
+def _commonprefix(strings):
+ # Similar to os.path.commonprefix
+ if not strings:
+ return ''
+
+ else:
+ s1 = min(strings)
+ s2 = max(strings)
+
+ for i, c in enumerate(s1):
+ if c != s2[i]:
+ return s1[:i]
+
+ return s1
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py
index a788d61004c..43893b8c8cf 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/__init__.py
@@ -1,5 +1,5 @@
-from __future__ import unicode_literals
-
-from .filesystem import PathCompleter
-from .base import WordCompleter
-from .system import SystemCompleter
+from __future__ import unicode_literals
+
+from .filesystem import PathCompleter
+from .base import WordCompleter
+from .system import SystemCompleter
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py
index 0a4a3abc709..65a69fede10 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/base.py
@@ -1,61 +1,61 @@
-from __future__ import unicode_literals
-
-from six import string_types
-from prompt_toolkit.completion import Completer, Completion
-
-__all__ = (
- 'WordCompleter',
-)
-
-
-class WordCompleter(Completer):
- """
- Simple autocompletion on a list of words.
-
- :param words: List of words.
- :param ignore_case: If True, case-insensitive completion.
- :param meta_dict: Optional dict mapping words to their meta-information.
- :param WORD: When True, use WORD characters.
- :param sentence: When True, don't complete by comparing the word before the
- cursor, but by comparing all the text before the cursor. In this case,
- the list of words is just a list of strings, where each string can
- contain spaces. (Can not be used together with the WORD option.)
- :param match_middle: When True, match not only the start, but also in the
- middle of the word.
- """
- def __init__(self, words, ignore_case=False, meta_dict=None, WORD=False,
- sentence=False, match_middle=False):
- assert not (WORD and sentence)
-
- self.words = list(words)
- self.ignore_case = ignore_case
- self.meta_dict = meta_dict or {}
- self.WORD = WORD
- self.sentence = sentence
- self.match_middle = match_middle
- assert all(isinstance(w, string_types) for w in self.words)
-
- def get_completions(self, document, complete_event):
- # Get word/text before cursor.
- if self.sentence:
- word_before_cursor = document.text_before_cursor
- else:
- word_before_cursor = document.get_word_before_cursor(WORD=self.WORD)
-
- if self.ignore_case:
- word_before_cursor = word_before_cursor.lower()
-
- def word_matches(word):
- """ True when the word before the cursor matches. """
- if self.ignore_case:
- word = word.lower()
-
- if self.match_middle:
- return word_before_cursor in word
- else:
- return word.startswith(word_before_cursor)
-
- for a in self.words:
- if word_matches(a):
- display_meta = self.meta_dict.get(a, '')
- yield Completion(a, -len(word_before_cursor), display_meta=display_meta)
+from __future__ import unicode_literals
+
+from six import string_types
+from prompt_toolkit.completion import Completer, Completion
+
+__all__ = (
+ 'WordCompleter',
+)
+
+
+class WordCompleter(Completer):
+ """
+ Simple autocompletion on a list of words.
+
+ :param words: List of words.
+ :param ignore_case: If True, case-insensitive completion.
+ :param meta_dict: Optional dict mapping words to their meta-information.
+ :param WORD: When True, use WORD characters.
+ :param sentence: When True, don't complete by comparing the word before the
+ cursor, but by comparing all the text before the cursor. In this case,
+ the list of words is just a list of strings, where each string can
+ contain spaces. (Can not be used together with the WORD option.)
+ :param match_middle: When True, match not only the start, but also in the
+ middle of the word.
+ """
+ def __init__(self, words, ignore_case=False, meta_dict=None, WORD=False,
+ sentence=False, match_middle=False):
+ assert not (WORD and sentence)
+
+ self.words = list(words)
+ self.ignore_case = ignore_case
+ self.meta_dict = meta_dict or {}
+ self.WORD = WORD
+ self.sentence = sentence
+ self.match_middle = match_middle
+ assert all(isinstance(w, string_types) for w in self.words)
+
+ def get_completions(self, document, complete_event):
+ # Get word/text before cursor.
+ if self.sentence:
+ word_before_cursor = document.text_before_cursor
+ else:
+ word_before_cursor = document.get_word_before_cursor(WORD=self.WORD)
+
+ if self.ignore_case:
+ word_before_cursor = word_before_cursor.lower()
+
+ def word_matches(word):
+ """ True when the word before the cursor matches. """
+ if self.ignore_case:
+ word = word.lower()
+
+ if self.match_middle:
+ return word_before_cursor in word
+ else:
+ return word.startswith(word_before_cursor)
+
+ for a in self.words:
+ if word_matches(a):
+ display_meta = self.meta_dict.get(a, '')
+ yield Completion(a, -len(word_before_cursor), display_meta=display_meta)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py
index 287ec6e85d5..cbd74d8fea2 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/filesystem.py
@@ -1,105 +1,105 @@
-from __future__ import unicode_literals
-
-from prompt_toolkit.completion import Completer, Completion
-import os
-
-__all__ = (
- 'PathCompleter',
- 'ExecutableCompleter',
-)
-
-
-class PathCompleter(Completer):
- """
- Complete for Path variables.
-
- :param get_paths: Callable which returns a list of directories to look into
- when the user enters a relative path.
- :param file_filter: Callable which takes a filename and returns whether
- this file should show up in the completion. ``None``
- when no filtering has to be done.
- :param min_input_len: Don't do autocompletion when the input string is shorter.
- """
- def __init__(self, only_directories=False, get_paths=None, file_filter=None,
- min_input_len=0, expanduser=False):
- assert get_paths is None or callable(get_paths)
- assert file_filter is None or callable(file_filter)
- assert isinstance(min_input_len, int)
- assert isinstance(expanduser, bool)
-
- self.only_directories = only_directories
- self.get_paths = get_paths or (lambda: ['.'])
- self.file_filter = file_filter or (lambda _: True)
- self.min_input_len = min_input_len
- self.expanduser = expanduser
-
- def get_completions(self, document, complete_event):
- text = document.text_before_cursor
-
- # Complete only when we have at least the minimal input length,
- # otherwise, we can too many results and autocompletion will become too
- # heavy.
- if len(text) < self.min_input_len:
- return
-
- try:
- # Do tilde expansion.
- if self.expanduser:
- text = os.path.expanduser(text)
-
- # Directories where to look.
- dirname = os.path.dirname(text)
- if dirname:
- directories = [os.path.dirname(os.path.join(p, text))
- for p in self.get_paths()]
- else:
- directories = self.get_paths()
-
- # Start of current file.
- prefix = os.path.basename(text)
-
- # Get all filenames.
- filenames = []
- for directory in directories:
- # Look for matches in this directory.
- if os.path.isdir(directory):
- for filename in os.listdir(directory):
- if filename.startswith(prefix):
- filenames.append((directory, filename))
-
- # Sort
- filenames = sorted(filenames, key=lambda k: k[1])
-
- # Yield them.
- for directory, filename in filenames:
- completion = filename[len(prefix):]
- full_name = os.path.join(directory, filename)
-
- if os.path.isdir(full_name):
- # For directories, add a slash to the filename.
- # (We don't add them to the `completion`. Users can type it
- # to trigger the autocompletion themself.)
- filename += '/'
+from __future__ import unicode_literals
+
+from prompt_toolkit.completion import Completer, Completion
+import os
+
+__all__ = (
+ 'PathCompleter',
+ 'ExecutableCompleter',
+)
+
+
+class PathCompleter(Completer):
+ """
+ Complete for Path variables.
+
+ :param get_paths: Callable which returns a list of directories to look into
+ when the user enters a relative path.
+ :param file_filter: Callable which takes a filename and returns whether
+ this file should show up in the completion. ``None``
+ when no filtering has to be done.
+ :param min_input_len: Don't do autocompletion when the input string is shorter.
+ """
+ def __init__(self, only_directories=False, get_paths=None, file_filter=None,
+ min_input_len=0, expanduser=False):
+ assert get_paths is None or callable(get_paths)
+ assert file_filter is None or callable(file_filter)
+ assert isinstance(min_input_len, int)
+ assert isinstance(expanduser, bool)
+
+ self.only_directories = only_directories
+ self.get_paths = get_paths or (lambda: ['.'])
+ self.file_filter = file_filter or (lambda _: True)
+ self.min_input_len = min_input_len
+ self.expanduser = expanduser
+
+ def get_completions(self, document, complete_event):
+ text = document.text_before_cursor
+
+ # Complete only when we have at least the minimal input length,
+ # otherwise, we can too many results and autocompletion will become too
+ # heavy.
+ if len(text) < self.min_input_len:
+ return
+
+ try:
+ # Do tilde expansion.
+ if self.expanduser:
+ text = os.path.expanduser(text)
+
+ # Directories where to look.
+ dirname = os.path.dirname(text)
+ if dirname:
+ directories = [os.path.dirname(os.path.join(p, text))
+ for p in self.get_paths()]
+ else:
+ directories = self.get_paths()
+
+ # Start of current file.
+ prefix = os.path.basename(text)
+
+ # Get all filenames.
+ filenames = []
+ for directory in directories:
+ # Look for matches in this directory.
+ if os.path.isdir(directory):
+ for filename in os.listdir(directory):
+ if filename.startswith(prefix):
+ filenames.append((directory, filename))
+
+ # Sort
+ filenames = sorted(filenames, key=lambda k: k[1])
+
+ # Yield them.
+ for directory, filename in filenames:
+ completion = filename[len(prefix):]
+ full_name = os.path.join(directory, filename)
+
+ if os.path.isdir(full_name):
+ # For directories, add a slash to the filename.
+ # (We don't add them to the `completion`. Users can type it
+ # to trigger the autocompletion themself.)
+ filename += '/'
elif self.only_directories:
continue
-
+
if not self.file_filter(full_name):
continue
- yield Completion(completion, 0, display=filename)
- except OSError:
- pass
-
-
-class ExecutableCompleter(PathCompleter):
- """
- Complete only excutable files in the current path.
- """
- def __init__(self):
- PathCompleter.__init__(
- self,
- only_directories=False,
- min_input_len=1,
- get_paths=lambda: os.environ.get('PATH', '').split(os.pathsep),
- file_filter=lambda name: os.access(name, os.X_OK),
- expanduser=True),
+ yield Completion(completion, 0, display=filename)
+ except OSError:
+ pass
+
+
+class ExecutableCompleter(PathCompleter):
+ """
+ Complete only excutable files in the current path.
+ """
+ def __init__(self):
+ PathCompleter.__init__(
+ self,
+ only_directories=False,
+ min_input_len=1,
+ get_paths=lambda: os.environ.get('PATH', '').split(os.pathsep),
+ file_filter=lambda name: os.access(name, os.X_OK),
+ expanduser=True),
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py
index 35b2eeaef29..76d6c1f9b41 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/completers/system.py
@@ -1,56 +1,56 @@
-from __future__ import unicode_literals
-
-from prompt_toolkit.contrib.regular_languages.completion import GrammarCompleter
-from prompt_toolkit.contrib.regular_languages.compiler import compile
-
-from .filesystem import PathCompleter, ExecutableCompleter
-
-__all__ = (
- 'SystemCompleter',
-)
-
-
-class SystemCompleter(GrammarCompleter):
- """
- Completer for system commands.
- """
- def __init__(self):
- # Compile grammar.
- g = compile(
- r"""
- # First we have an executable.
- (?P<executable>[^\s]+)
-
- # Ignore literals in between.
- (
- \s+
- ("[^"]*" | '[^']*' | [^'"]+ )
- )*
-
- \s+
-
- # Filename as parameters.
- (
- (?P<filename>[^\s]+) |
- "(?P<double_quoted_filename>[^\s]+)" |
- '(?P<single_quoted_filename>[^\s]+)'
- )
- """,
- escape_funcs={
- 'double_quoted_filename': (lambda string: string.replace('"', '\\"')),
- 'single_quoted_filename': (lambda string: string.replace("'", "\\'")),
- },
- unescape_funcs={
- 'double_quoted_filename': (lambda string: string.replace('\\"', '"')), # XXX: not enterily correct.
- 'single_quoted_filename': (lambda string: string.replace("\\'", "'")),
- })
-
- # Create GrammarCompleter
- super(SystemCompleter, self).__init__(
- g,
- {
- 'executable': ExecutableCompleter(),
- 'filename': PathCompleter(only_directories=False, expanduser=True),
- 'double_quoted_filename': PathCompleter(only_directories=False, expanduser=True),
- 'single_quoted_filename': PathCompleter(only_directories=False, expanduser=True),
- })
+from __future__ import unicode_literals
+
+from prompt_toolkit.contrib.regular_languages.completion import GrammarCompleter
+from prompt_toolkit.contrib.regular_languages.compiler import compile
+
+from .filesystem import PathCompleter, ExecutableCompleter
+
+__all__ = (
+ 'SystemCompleter',
+)
+
+
+class SystemCompleter(GrammarCompleter):
+ """
+ Completer for system commands.
+ """
+ def __init__(self):
+ # Compile grammar.
+ g = compile(
+ r"""
+ # First we have an executable.
+ (?P<executable>[^\s]+)
+
+ # Ignore literals in between.
+ (
+ \s+
+ ("[^"]*" | '[^']*' | [^'"]+ )
+ )*
+
+ \s+
+
+ # Filename as parameters.
+ (
+ (?P<filename>[^\s]+) |
+ "(?P<double_quoted_filename>[^\s]+)" |
+ '(?P<single_quoted_filename>[^\s]+)'
+ )
+ """,
+ escape_funcs={
+ 'double_quoted_filename': (lambda string: string.replace('"', '\\"')),
+ 'single_quoted_filename': (lambda string: string.replace("'", "\\'")),
+ },
+ unescape_funcs={
+ 'double_quoted_filename': (lambda string: string.replace('\\"', '"')), # XXX: not enterily correct.
+ 'single_quoted_filename': (lambda string: string.replace("\\'", "'")),
+ })
+
+ # Create GrammarCompleter
+ super(SystemCompleter, self).__init__(
+ g,
+ {
+ 'executable': ExecutableCompleter(),
+ 'filename': PathCompleter(only_directories=False, expanduser=True),
+ 'double_quoted_filename': PathCompleter(only_directories=False, expanduser=True),
+ 'single_quoted_filename': PathCompleter(only_directories=False, expanduser=True),
+ })
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py
index 21f2c55e750..314cb1f81db 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/__init__.py
@@ -1,76 +1,76 @@
-r"""
-Tool for expressing the grammar of an input as a regular language.
-==================================================================
-
-The grammar for the input of many simple command line interfaces can be
-expressed by a regular language. Examples are PDB (the Python debugger); a
-simple (bash-like) shell with "pwd", "cd", "cat" and "ls" commands; arguments
-that you can pass to an executable; etc. It is possible to use regular
-expressions for validation and parsing of such a grammar. (More about regular
-languages: http://en.wikipedia.org/wiki/Regular_language)
-
-Example
--------
-
-Let's take the pwd/cd/cat/ls example. We want to have a shell that accepts
-these three commands. "cd" is followed by a quoted directory name and "cat" is
-followed by a quoted file name. (We allow quotes inside the filename when
-they're escaped with a backslash.) We could define the grammar using the
-following regular expression::
-
- grammar = \s* (
- pwd |
- ls |
- (cd \s+ " ([^"]|\.)+ ") |
- (cat \s+ " ([^"]|\.)+ ")
- ) \s*
-
-
-What can we do with this grammar?
----------------------------------
-
-- Syntax highlighting: We could use this for instance to give file names
- different colour.
-- Parse the result: .. We can extract the file names and commands by using a
- regular expression with named groups.
-- Input validation: .. Don't accept anything that does not match this grammar.
- When combined with a parser, we can also recursively do
- filename validation (and accept only existing files.)
-- Autocompletion: .... Each part of the grammar can have its own autocompleter.
- "cat" has to be completed using file names, while "cd"
- has to be completed using directory names.
-
-How does it work?
------------------
-
-As a user of this library, you have to define the grammar of the input as a
-regular expression. The parts of this grammar where autocompletion, validation
-or any other processing is required need to be marked using a regex named
-group. Like ``(?P<varname>...)`` for instance.
-
-When the input is processed for validation (for instance), the regex will
-execute, the named group is captured, and the validator associated with this
-named group will test the captured string.
-
-There is one tricky bit:
-
- Ofter we operate on incomplete input (this is by definition the case for
- autocompletion) and we have to decide for the cursor position in which
- possible state the grammar it could be and in which way variables could be
- matched up to that point.
-
-To solve this problem, the compiler takes the original regular expression and
-translates it into a set of other regular expressions which each match prefixes
-of strings that would match the first expression. (We translate it into
-multiple expression, because we want to have each possible state the regex
-could be in -- in case there are several or-clauses with each different
-completers.)
-
-
-TODO: some examples of:
- - How to create a highlighter from this grammar.
- - How to create a validator from this grammar.
- - How to create an autocompleter from this grammar.
- - How to create a parser from this grammar.
-"""
-from .compiler import compile
+r"""
+Tool for expressing the grammar of an input as a regular language.
+==================================================================
+
+The grammar for the input of many simple command line interfaces can be
+expressed by a regular language. Examples are PDB (the Python debugger); a
+simple (bash-like) shell with "pwd", "cd", "cat" and "ls" commands; arguments
+that you can pass to an executable; etc. It is possible to use regular
+expressions for validation and parsing of such a grammar. (More about regular
+languages: http://en.wikipedia.org/wiki/Regular_language)
+
+Example
+-------
+
+Let's take the pwd/cd/cat/ls example. We want to have a shell that accepts
+these three commands. "cd" is followed by a quoted directory name and "cat" is
+followed by a quoted file name. (We allow quotes inside the filename when
+they're escaped with a backslash.) We could define the grammar using the
+following regular expression::
+
+ grammar = \s* (
+ pwd |
+ ls |
+ (cd \s+ " ([^"]|\.)+ ") |
+ (cat \s+ " ([^"]|\.)+ ")
+ ) \s*
+
+
+What can we do with this grammar?
+---------------------------------
+
+- Syntax highlighting: We could use this for instance to give file names
+ different colour.
+- Parse the result: .. We can extract the file names and commands by using a
+ regular expression with named groups.
+- Input validation: .. Don't accept anything that does not match this grammar.
+ When combined with a parser, we can also recursively do
+ filename validation (and accept only existing files.)
+- Autocompletion: .... Each part of the grammar can have its own autocompleter.
+ "cat" has to be completed using file names, while "cd"
+ has to be completed using directory names.
+
+How does it work?
+-----------------
+
+As a user of this library, you have to define the grammar of the input as a
+regular expression. The parts of this grammar where autocompletion, validation
+or any other processing is required need to be marked using a regex named
+group. Like ``(?P<varname>...)`` for instance.
+
+When the input is processed for validation (for instance), the regex will
+execute, the named group is captured, and the validator associated with this
+named group will test the captured string.
+
+There is one tricky bit:
+
+ Ofter we operate on incomplete input (this is by definition the case for
+ autocompletion) and we have to decide for the cursor position in which
+ possible state the grammar it could be and in which way variables could be
+ matched up to that point.
+
+To solve this problem, the compiler takes the original regular expression and
+translates it into a set of other regular expressions which each match prefixes
+of strings that would match the first expression. (We translate it into
+multiple expression, because we want to have each possible state the regex
+could be in -- in case there are several or-clauses with each different
+completers.)
+
+
+TODO: some examples of:
+ - How to create a highlighter from this grammar.
+ - How to create a validator from this grammar.
+ - How to create an autocompleter from this grammar.
+ - How to create a parser from this grammar.
+"""
+from .compiler import compile
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py
index 4b0939fbf8c..01476bf6261 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/compiler.py
@@ -1,408 +1,408 @@
-r"""
-Compiler for a regular grammar.
-
-Example usage::
-
- # Create and compile grammar.
- p = compile('add \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)')
-
- # Match input string.
- m = p.match('add 23 432')
-
- # Get variables.
- m.variables().get('var1') # Returns "23"
- m.variables().get('var2') # Returns "432"
-
-
-Partial matches are possible::
-
- # Create and compile grammar.
- p = compile('''
- # Operators with two arguments.
- ((?P<operator1>[^\s]+) \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)) |
-
- # Operators with only one arguments.
- ((?P<operator2>[^\s]+) \s+ (?P<var1>[^\s]+))
- ''')
-
- # Match partial input string.
- m = p.match_prefix('add 23')
-
- # Get variables. (Notice that both operator1 and operator2 contain the
- # value "add".) This is because our input is incomplete, and we don't know
- # yet in which rule of the regex we we'll end up. It could also be that
- # `operator1` and `operator2` have a different autocompleter and we want to
- # call all possible autocompleters that would result in valid input.)
- m.variables().get('var1') # Returns "23"
- m.variables().get('operator1') # Returns "add"
- m.variables().get('operator2') # Returns "add"
-
-"""
-from __future__ import unicode_literals
-import re
-
+r"""
+Compiler for a regular grammar.
+
+Example usage::
+
+ # Create and compile grammar.
+ p = compile('add \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)')
+
+ # Match input string.
+ m = p.match('add 23 432')
+
+ # Get variables.
+ m.variables().get('var1') # Returns "23"
+ m.variables().get('var2') # Returns "432"
+
+
+Partial matches are possible::
+
+ # Create and compile grammar.
+ p = compile('''
+ # Operators with two arguments.
+ ((?P<operator1>[^\s]+) \s+ (?P<var1>[^\s]+) \s+ (?P<var2>[^\s]+)) |
+
+ # Operators with only one arguments.
+ ((?P<operator2>[^\s]+) \s+ (?P<var1>[^\s]+))
+ ''')
+
+ # Match partial input string.
+ m = p.match_prefix('add 23')
+
+ # Get variables. (Notice that both operator1 and operator2 contain the
+ # value "add".) This is because our input is incomplete, and we don't know
+ # yet in which rule of the regex we we'll end up. It could also be that
+ # `operator1` and `operator2` have a different autocompleter and we want to
+ # call all possible autocompleters that would result in valid input.)
+ m.variables().get('var1') # Returns "23"
+ m.variables().get('operator1') # Returns "add"
+ m.variables().get('operator2') # Returns "add"
+
+"""
+from __future__ import unicode_literals
+import re
+
from six.moves import range
-from .regex_parser import Any, Sequence, Regex, Variable, Repeat, Lookahead
-from .regex_parser import parse_regex, tokenize_regex
-
-__all__ = (
- 'compile',
-)
-
-
-# Name of the named group in the regex, matching trailing input.
-# (Trailing input is when the input contains characters after the end of the
-# expression has been matched.)
-_INVALID_TRAILING_INPUT = 'invalid_trailing'
-
-
-class _CompiledGrammar(object):
- """
- Compiles a grammar. This will take the parse tree of a regular expression
- and compile the grammar.
-
- :param root_node: :class~`.regex_parser.Node` instance.
- :param escape_funcs: `dict` mapping variable names to escape callables.
- :param unescape_funcs: `dict` mapping variable names to unescape callables.
- """
- def __init__(self, root_node, escape_funcs=None, unescape_funcs=None):
- self.root_node = root_node
- self.escape_funcs = escape_funcs or {}
- self.unescape_funcs = unescape_funcs or {}
-
- #: Dictionary that will map the redex names to Node instances.
- self._group_names_to_nodes = {} # Maps regex group names to varnames.
- counter = [0]
-
- def create_group_func(node):
- name = 'n%s' % counter[0]
- self._group_names_to_nodes[name] = node.varname
- counter[0] += 1
- return name
-
- # Compile regex strings.
- self._re_pattern = '^%s$' % self._transform(root_node, create_group_func)
- self._re_prefix_patterns = list(self._transform_prefix(root_node, create_group_func))
-
- # Compile the regex itself.
- flags = re.DOTALL # Note that we don't need re.MULTILINE! (^ and $
- # still represent the start and end of input text.)
- self._re = re.compile(self._re_pattern, flags)
- self._re_prefix = [re.compile(t, flags) for t in self._re_prefix_patterns]
-
- # We compile one more set of regexes, similar to `_re_prefix`, but accept any trailing
- # input. This will ensure that we can still highlight the input correctly, even when the
- # input contains some additional characters at the end that don't match the grammar.)
- self._re_prefix_with_trailing_input = [
- re.compile(r'(?:%s)(?P<%s>.*?)$' % (t.rstrip('$'), _INVALID_TRAILING_INPUT), flags)
- for t in self._re_prefix_patterns]
-
- def escape(self, varname, value):
- """
- Escape `value` to fit in the place of this variable into the grammar.
- """
- f = self.escape_funcs.get(varname)
- return f(value) if f else value
-
- def unescape(self, varname, value):
- """
- Unescape `value`.
- """
- f = self.unescape_funcs.get(varname)
- return f(value) if f else value
-
- @classmethod
- def _transform(cls, root_node, create_group_func):
- """
- Turn a :class:`Node` object into a regular expression.
-
- :param root_node: The :class:`Node` instance for which we generate the grammar.
- :param create_group_func: A callable which takes a `Node` and returns the next
- free name for this node.
- """
- def transform(node):
- # Turn `Any` into an OR.
- if isinstance(node, Any):
- return '(?:%s)' % '|'.join(transform(c) for c in node.children)
-
- # Concatenate a `Sequence`
- elif isinstance(node, Sequence):
- return ''.join(transform(c) for c in node.children)
-
- # For Regex and Lookahead nodes, just insert them literally.
- elif isinstance(node, Regex):
- return node.regex
-
- elif isinstance(node, Lookahead):
- before = ('(?!' if node.negative else '(=')
- return before + transform(node.childnode) + ')'
-
- # A `Variable` wraps the children into a named group.
- elif isinstance(node, Variable):
- return '(?P<%s>%s)' % (create_group_func(node), transform(node.childnode))
-
- # `Repeat`.
- elif isinstance(node, Repeat):
- return '(?:%s){%i,%s}%s' % (
- transform(node.childnode), node.min_repeat,
- ('' if node.max_repeat is None else str(node.max_repeat)),
- ('' if node.greedy else '?')
- )
- else:
- raise TypeError('Got %r' % (node, ))
-
- return transform(root_node)
-
- @classmethod
- def _transform_prefix(cls, root_node, create_group_func):
- """
- Yield all the regular expressions matching a prefix of the grammar
- defined by the `Node` instance.
-
- This can yield multiple expressions, because in the case of on OR
- operation in the grammar, we can have another outcome depending on
- which clause would appear first. E.g. "(A|B)C" is not the same as
- "(B|A)C" because the regex engine is lazy and takes the first match.
- However, because we the current input is actually a prefix of the
- grammar which meight not yet contain the data for "C", we need to know
- both intermediate states, in order to call the appropriate
- autocompletion for both cases.
-
- :param root_node: The :class:`Node` instance for which we generate the grammar.
- :param create_group_func: A callable which takes a `Node` and returns the next
- free name for this node.
- """
- def transform(node):
- # Generate regexes for all permutations of this OR. Each node
- # should be in front once.
- if isinstance(node, Any):
- for c in node.children:
- for r in transform(c):
- yield '(?:%s)?' % r
-
- # For a sequence. We can either have a match for the sequence
- # of all the children, or for an exact match of the first X
- # children, followed by a partial match of the next children.
- elif isinstance(node, Sequence):
- for i in range(len(node.children)):
- a = [cls._transform(c, create_group_func) for c in node.children[:i]]
- for c in transform(node.children[i]):
- yield '(?:%s)' % (''.join(a) + c)
-
- elif isinstance(node, Regex):
- yield '(?:%s)?' % node.regex
-
- elif isinstance(node, Lookahead):
- if node.negative:
- yield '(?!%s)' % cls._transform(node.childnode, create_group_func)
- else:
- # Not sure what the correct semantics are in this case.
- # (Probably it's not worth implementing this.)
- raise Exception('Positive lookahead not yet supported.')
-
- elif isinstance(node, Variable):
- # (Note that we should not append a '?' here. the 'transform'
- # method will already recursively do that.)
- for c in transform(node.childnode):
- yield '(?P<%s>%s)' % (create_group_func(node), c)
-
- elif isinstance(node, Repeat):
- # If we have a repetition of 8 times. That would mean that the
- # current input could have for instance 7 times a complete
- # match, followed by a partial match.
- prefix = cls._transform(node.childnode, create_group_func)
-
- for c in transform(node.childnode):
- if node.max_repeat:
- repeat_sign = '{,%i}' % (node.max_repeat - 1)
- else:
- repeat_sign = '*'
- yield '(?:%s)%s%s(?:%s)?' % (
- prefix,
- repeat_sign,
- ('' if node.greedy else '?'),
- c)
-
- else:
- raise TypeError('Got %r' % node)
-
- for r in transform(root_node):
- yield '^%s$' % r
-
- def match(self, string):
- """
- Match the string with the grammar.
- Returns a :class:`Match` instance or `None` when the input doesn't match the grammar.
-
- :param string: The input string.
- """
- m = self._re.match(string)
-
- if m:
- return Match(string, [(self._re, m)], self._group_names_to_nodes, self.unescape_funcs)
-
- def match_prefix(self, string):
- """
- Do a partial match of the string with the grammar. The returned
- :class:`Match` instance can contain multiple representations of the
- match. This will never return `None`. If it doesn't match at all, the "trailing input"
- part will capture all of the input.
-
- :param string: The input string.
- """
- # First try to match using `_re_prefix`. If nothing is found, use the patterns that
- # also accept trailing characters.
- for patterns in [self._re_prefix, self._re_prefix_with_trailing_input]:
- matches = [(r, r.match(string)) for r in patterns]
- matches = [(r, m) for r, m in matches if m]
-
- if matches != []:
- return Match(string, matches, self._group_names_to_nodes, self.unescape_funcs)
-
-
-class Match(object):
- """
- :param string: The input string.
- :param re_matches: List of (compiled_re_pattern, re_match) tuples.
- :param group_names_to_nodes: Dictionary mapping all the re group names to the matching Node instances.
- """
- def __init__(self, string, re_matches, group_names_to_nodes, unescape_funcs):
- self.string = string
- self._re_matches = re_matches
- self._group_names_to_nodes = group_names_to_nodes
- self._unescape_funcs = unescape_funcs
-
- def _nodes_to_regs(self):
- """
- Return a list of (varname, reg) tuples.
- """
- def get_tuples():
- for r, re_match in self._re_matches:
- for group_name, group_index in r.groupindex.items():
- if group_name != _INVALID_TRAILING_INPUT:
- reg = re_match.regs[group_index]
- node = self._group_names_to_nodes[group_name]
- yield (node, reg)
-
- return list(get_tuples())
-
- def _nodes_to_values(self):
- """
- Returns list of list of (Node, string_value) tuples.
- """
- def is_none(slice):
- return slice[0] == -1 and slice[1] == -1
-
- def get(slice):
- return self.string[slice[0]:slice[1]]
-
- return [(varname, get(slice), slice) for varname, slice in self._nodes_to_regs() if not is_none(slice)]
-
- def _unescape(self, varname, value):
- unwrapper = self._unescape_funcs.get(varname)
- return unwrapper(value) if unwrapper else value
-
- def variables(self):
- """
- Returns :class:`Variables` instance.
- """
- return Variables([(k, self._unescape(k, v), sl) for k, v, sl in self._nodes_to_values()])
-
- def trailing_input(self):
- """
- Get the `MatchVariable` instance, representing trailing input, if there is any.
- "Trailing input" is input at the end that does not match the grammar anymore, but
- when this is removed from the end of the input, the input would be a valid string.
- """
- slices = []
-
- # Find all regex group for the name _INVALID_TRAILING_INPUT.
- for r, re_match in self._re_matches:
- for group_name, group_index in r.groupindex.items():
- if group_name == _INVALID_TRAILING_INPUT:
- slices.append(re_match.regs[group_index])
-
- # Take the smallest part. (Smaller trailing text means that a larger input has
- # been matched, so that is better.)
- if slices:
- slice = [max(i[0] for i in slices), max(i[1] for i in slices)]
- value = self.string[slice[0]:slice[1]]
- return MatchVariable('<trailing_input>', value, slice)
-
- def end_nodes(self):
- """
- Yields `MatchVariable` instances for all the nodes having their end
- position at the end of the input string.
- """
- for varname, reg in self._nodes_to_regs():
- # If this part goes until the end of the input string.
- if reg[1] == len(self.string):
- value = self._unescape(varname, self.string[reg[0]: reg[1]])
- yield MatchVariable(varname, value, (reg[0], reg[1]))
-
-
-class Variables(object):
- def __init__(self, tuples):
- #: List of (varname, value, slice) tuples.
- self._tuples = tuples
-
- def __repr__(self):
- return '%s(%s)' % (
- self.__class__.__name__, ', '.join('%s=%r' % (k, v) for k, v, _ in self._tuples))
-
- def get(self, key, default=None):
- items = self.getall(key)
- return items[0] if items else default
-
- def getall(self, key):
- return [v for k, v, _ in self._tuples if k == key]
-
- def __getitem__(self, key):
- return self.get(key)
-
- def __iter__(self):
- """
- Yield `MatchVariable` instances.
- """
- for varname, value, slice in self._tuples:
- yield MatchVariable(varname, value, slice)
-
-
-class MatchVariable(object):
- """
- Represents a match of a variable in the grammar.
-
- :param varname: (string) Name of the variable.
- :param value: (string) Value of this variable.
- :param slice: (start, stop) tuple, indicating the position of this variable
- in the input string.
- """
- def __init__(self, varname, value, slice):
- self.varname = varname
- self.value = value
- self.slice = slice
-
- self.start = self.slice[0]
- self.stop = self.slice[1]
-
- def __repr__(self):
- return '%s(%r, %r)' % (self.__class__.__name__, self.varname, self.value)
-
-
-def compile(expression, escape_funcs=None, unescape_funcs=None):
- """
- Compile grammar (given as regex string), returning a `CompiledGrammar`
- instance.
- """
- return _compile_from_parse_tree(
- parse_regex(tokenize_regex(expression)),
- escape_funcs=escape_funcs,
- unescape_funcs=unescape_funcs)
-
-
-def _compile_from_parse_tree(root_node, *a, **kw):
- """
- Compile grammar (given as parse tree), returning a `CompiledGrammar`
- instance.
- """
- return _CompiledGrammar(root_node, *a, **kw)
+from .regex_parser import Any, Sequence, Regex, Variable, Repeat, Lookahead
+from .regex_parser import parse_regex, tokenize_regex
+
+__all__ = (
+ 'compile',
+)
+
+
+# Name of the named group in the regex, matching trailing input.
+# (Trailing input is when the input contains characters after the end of the
+# expression has been matched.)
+_INVALID_TRAILING_INPUT = 'invalid_trailing'
+
+
+class _CompiledGrammar(object):
+ """
+ Compiles a grammar. This will take the parse tree of a regular expression
+ and compile the grammar.
+
+ :param root_node: :class~`.regex_parser.Node` instance.
+ :param escape_funcs: `dict` mapping variable names to escape callables.
+ :param unescape_funcs: `dict` mapping variable names to unescape callables.
+ """
+ def __init__(self, root_node, escape_funcs=None, unescape_funcs=None):
+ self.root_node = root_node
+ self.escape_funcs = escape_funcs or {}
+ self.unescape_funcs = unescape_funcs or {}
+
+ #: Dictionary that will map the redex names to Node instances.
+ self._group_names_to_nodes = {} # Maps regex group names to varnames.
+ counter = [0]
+
+ def create_group_func(node):
+ name = 'n%s' % counter[0]
+ self._group_names_to_nodes[name] = node.varname
+ counter[0] += 1
+ return name
+
+ # Compile regex strings.
+ self._re_pattern = '^%s$' % self._transform(root_node, create_group_func)
+ self._re_prefix_patterns = list(self._transform_prefix(root_node, create_group_func))
+
+ # Compile the regex itself.
+ flags = re.DOTALL # Note that we don't need re.MULTILINE! (^ and $
+ # still represent the start and end of input text.)
+ self._re = re.compile(self._re_pattern, flags)
+ self._re_prefix = [re.compile(t, flags) for t in self._re_prefix_patterns]
+
+ # We compile one more set of regexes, similar to `_re_prefix`, but accept any trailing
+ # input. This will ensure that we can still highlight the input correctly, even when the
+ # input contains some additional characters at the end that don't match the grammar.)
+ self._re_prefix_with_trailing_input = [
+ re.compile(r'(?:%s)(?P<%s>.*?)$' % (t.rstrip('$'), _INVALID_TRAILING_INPUT), flags)
+ for t in self._re_prefix_patterns]
+
+ def escape(self, varname, value):
+ """
+ Escape `value` to fit in the place of this variable into the grammar.
+ """
+ f = self.escape_funcs.get(varname)
+ return f(value) if f else value
+
+ def unescape(self, varname, value):
+ """
+ Unescape `value`.
+ """
+ f = self.unescape_funcs.get(varname)
+ return f(value) if f else value
+
+ @classmethod
+ def _transform(cls, root_node, create_group_func):
+ """
+ Turn a :class:`Node` object into a regular expression.
+
+ :param root_node: The :class:`Node` instance for which we generate the grammar.
+ :param create_group_func: A callable which takes a `Node` and returns the next
+ free name for this node.
+ """
+ def transform(node):
+ # Turn `Any` into an OR.
+ if isinstance(node, Any):
+ return '(?:%s)' % '|'.join(transform(c) for c in node.children)
+
+ # Concatenate a `Sequence`
+ elif isinstance(node, Sequence):
+ return ''.join(transform(c) for c in node.children)
+
+ # For Regex and Lookahead nodes, just insert them literally.
+ elif isinstance(node, Regex):
+ return node.regex
+
+ elif isinstance(node, Lookahead):
+ before = ('(?!' if node.negative else '(=')
+ return before + transform(node.childnode) + ')'
+
+ # A `Variable` wraps the children into a named group.
+ elif isinstance(node, Variable):
+ return '(?P<%s>%s)' % (create_group_func(node), transform(node.childnode))
+
+ # `Repeat`.
+ elif isinstance(node, Repeat):
+ return '(?:%s){%i,%s}%s' % (
+ transform(node.childnode), node.min_repeat,
+ ('' if node.max_repeat is None else str(node.max_repeat)),
+ ('' if node.greedy else '?')
+ )
+ else:
+ raise TypeError('Got %r' % (node, ))
+
+ return transform(root_node)
+
+ @classmethod
+ def _transform_prefix(cls, root_node, create_group_func):
+ """
+ Yield all the regular expressions matching a prefix of the grammar
+ defined by the `Node` instance.
+
+ This can yield multiple expressions, because in the case of on OR
+ operation in the grammar, we can have another outcome depending on
+ which clause would appear first. E.g. "(A|B)C" is not the same as
+ "(B|A)C" because the regex engine is lazy and takes the first match.
+ However, because we the current input is actually a prefix of the
+ grammar which meight not yet contain the data for "C", we need to know
+ both intermediate states, in order to call the appropriate
+ autocompletion for both cases.
+
+ :param root_node: The :class:`Node` instance for which we generate the grammar.
+ :param create_group_func: A callable which takes a `Node` and returns the next
+ free name for this node.
+ """
+ def transform(node):
+ # Generate regexes for all permutations of this OR. Each node
+ # should be in front once.
+ if isinstance(node, Any):
+ for c in node.children:
+ for r in transform(c):
+ yield '(?:%s)?' % r
+
+ # For a sequence. We can either have a match for the sequence
+ # of all the children, or for an exact match of the first X
+ # children, followed by a partial match of the next children.
+ elif isinstance(node, Sequence):
+ for i in range(len(node.children)):
+ a = [cls._transform(c, create_group_func) for c in node.children[:i]]
+ for c in transform(node.children[i]):
+ yield '(?:%s)' % (''.join(a) + c)
+
+ elif isinstance(node, Regex):
+ yield '(?:%s)?' % node.regex
+
+ elif isinstance(node, Lookahead):
+ if node.negative:
+ yield '(?!%s)' % cls._transform(node.childnode, create_group_func)
+ else:
+ # Not sure what the correct semantics are in this case.
+ # (Probably it's not worth implementing this.)
+ raise Exception('Positive lookahead not yet supported.')
+
+ elif isinstance(node, Variable):
+ # (Note that we should not append a '?' here. the 'transform'
+ # method will already recursively do that.)
+ for c in transform(node.childnode):
+ yield '(?P<%s>%s)' % (create_group_func(node), c)
+
+ elif isinstance(node, Repeat):
+ # If we have a repetition of 8 times. That would mean that the
+ # current input could have for instance 7 times a complete
+ # match, followed by a partial match.
+ prefix = cls._transform(node.childnode, create_group_func)
+
+ for c in transform(node.childnode):
+ if node.max_repeat:
+ repeat_sign = '{,%i}' % (node.max_repeat - 1)
+ else:
+ repeat_sign = '*'
+ yield '(?:%s)%s%s(?:%s)?' % (
+ prefix,
+ repeat_sign,
+ ('' if node.greedy else '?'),
+ c)
+
+ else:
+ raise TypeError('Got %r' % node)
+
+ for r in transform(root_node):
+ yield '^%s$' % r
+
+ def match(self, string):
+ """
+ Match the string with the grammar.
+ Returns a :class:`Match` instance or `None` when the input doesn't match the grammar.
+
+ :param string: The input string.
+ """
+ m = self._re.match(string)
+
+ if m:
+ return Match(string, [(self._re, m)], self._group_names_to_nodes, self.unescape_funcs)
+
+ def match_prefix(self, string):
+ """
+ Do a partial match of the string with the grammar. The returned
+ :class:`Match` instance can contain multiple representations of the
+ match. This will never return `None`. If it doesn't match at all, the "trailing input"
+ part will capture all of the input.
+
+ :param string: The input string.
+ """
+ # First try to match using `_re_prefix`. If nothing is found, use the patterns that
+ # also accept trailing characters.
+ for patterns in [self._re_prefix, self._re_prefix_with_trailing_input]:
+ matches = [(r, r.match(string)) for r in patterns]
+ matches = [(r, m) for r, m in matches if m]
+
+ if matches != []:
+ return Match(string, matches, self._group_names_to_nodes, self.unescape_funcs)
+
+
+class Match(object):
+ """
+ :param string: The input string.
+ :param re_matches: List of (compiled_re_pattern, re_match) tuples.
+ :param group_names_to_nodes: Dictionary mapping all the re group names to the matching Node instances.
+ """
+ def __init__(self, string, re_matches, group_names_to_nodes, unescape_funcs):
+ self.string = string
+ self._re_matches = re_matches
+ self._group_names_to_nodes = group_names_to_nodes
+ self._unescape_funcs = unescape_funcs
+
+ def _nodes_to_regs(self):
+ """
+ Return a list of (varname, reg) tuples.
+ """
+ def get_tuples():
+ for r, re_match in self._re_matches:
+ for group_name, group_index in r.groupindex.items():
+ if group_name != _INVALID_TRAILING_INPUT:
+ reg = re_match.regs[group_index]
+ node = self._group_names_to_nodes[group_name]
+ yield (node, reg)
+
+ return list(get_tuples())
+
+ def _nodes_to_values(self):
+ """
+ Returns list of list of (Node, string_value) tuples.
+ """
+ def is_none(slice):
+ return slice[0] == -1 and slice[1] == -1
+
+ def get(slice):
+ return self.string[slice[0]:slice[1]]
+
+ return [(varname, get(slice), slice) for varname, slice in self._nodes_to_regs() if not is_none(slice)]
+
+ def _unescape(self, varname, value):
+ unwrapper = self._unescape_funcs.get(varname)
+ return unwrapper(value) if unwrapper else value
+
+ def variables(self):
+ """
+ Returns :class:`Variables` instance.
+ """
+ return Variables([(k, self._unescape(k, v), sl) for k, v, sl in self._nodes_to_values()])
+
+ def trailing_input(self):
+ """
+ Get the `MatchVariable` instance, representing trailing input, if there is any.
+ "Trailing input" is input at the end that does not match the grammar anymore, but
+ when this is removed from the end of the input, the input would be a valid string.
+ """
+ slices = []
+
+ # Find all regex group for the name _INVALID_TRAILING_INPUT.
+ for r, re_match in self._re_matches:
+ for group_name, group_index in r.groupindex.items():
+ if group_name == _INVALID_TRAILING_INPUT:
+ slices.append(re_match.regs[group_index])
+
+ # Take the smallest part. (Smaller trailing text means that a larger input has
+ # been matched, so that is better.)
+ if slices:
+ slice = [max(i[0] for i in slices), max(i[1] for i in slices)]
+ value = self.string[slice[0]:slice[1]]
+ return MatchVariable('<trailing_input>', value, slice)
+
+ def end_nodes(self):
+ """
+ Yields `MatchVariable` instances for all the nodes having their end
+ position at the end of the input string.
+ """
+ for varname, reg in self._nodes_to_regs():
+ # If this part goes until the end of the input string.
+ if reg[1] == len(self.string):
+ value = self._unescape(varname, self.string[reg[0]: reg[1]])
+ yield MatchVariable(varname, value, (reg[0], reg[1]))
+
+
+class Variables(object):
+ def __init__(self, tuples):
+ #: List of (varname, value, slice) tuples.
+ self._tuples = tuples
+
+ def __repr__(self):
+ return '%s(%s)' % (
+ self.__class__.__name__, ', '.join('%s=%r' % (k, v) for k, v, _ in self._tuples))
+
+ def get(self, key, default=None):
+ items = self.getall(key)
+ return items[0] if items else default
+
+ def getall(self, key):
+ return [v for k, v, _ in self._tuples if k == key]
+
+ def __getitem__(self, key):
+ return self.get(key)
+
+ def __iter__(self):
+ """
+ Yield `MatchVariable` instances.
+ """
+ for varname, value, slice in self._tuples:
+ yield MatchVariable(varname, value, slice)
+
+
+class MatchVariable(object):
+ """
+ Represents a match of a variable in the grammar.
+
+ :param varname: (string) Name of the variable.
+ :param value: (string) Value of this variable.
+ :param slice: (start, stop) tuple, indicating the position of this variable
+ in the input string.
+ """
+ def __init__(self, varname, value, slice):
+ self.varname = varname
+ self.value = value
+ self.slice = slice
+
+ self.start = self.slice[0]
+ self.stop = self.slice[1]
+
+ def __repr__(self):
+ return '%s(%r, %r)' % (self.__class__.__name__, self.varname, self.value)
+
+
+def compile(expression, escape_funcs=None, unescape_funcs=None):
+ """
+ Compile grammar (given as regex string), returning a `CompiledGrammar`
+ instance.
+ """
+ return _compile_from_parse_tree(
+ parse_regex(tokenize_regex(expression)),
+ escape_funcs=escape_funcs,
+ unescape_funcs=unescape_funcs)
+
+
+def _compile_from_parse_tree(root_node, *a, **kw):
+ """
+ Compile grammar (given as parse tree), returning a `CompiledGrammar`
+ instance.
+ """
+ return _CompiledGrammar(root_node, *a, **kw)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py
index ff4aadca2c0..bb49986a039 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/completion.py
@@ -1,84 +1,84 @@
-"""
-Completer for a regular grammar.
-"""
-from __future__ import unicode_literals
-
-from prompt_toolkit.completion import Completer, Completion
-from prompt_toolkit.document import Document
-
-from .compiler import _CompiledGrammar
-
-__all__ = (
- 'GrammarCompleter',
-)
-
-
-class GrammarCompleter(Completer):
- """
- Completer which can be used for autocompletion according to variables in
- the grammar. Each variable can have a different autocompleter.
-
- :param compiled_grammar: `GrammarCompleter` instance.
- :param completers: `dict` mapping variable names of the grammar to the
- `Completer` instances to be used for each variable.
- """
- def __init__(self, compiled_grammar, completers):
- assert isinstance(compiled_grammar, _CompiledGrammar)
- assert isinstance(completers, dict)
-
- self.compiled_grammar = compiled_grammar
- self.completers = completers
-
- def get_completions(self, document, complete_event):
- m = self.compiled_grammar.match_prefix(document.text_before_cursor)
-
- if m:
- completions = self._remove_duplicates(
- self._get_completions_for_match(m, complete_event))
-
- for c in completions:
- yield c
-
- def _get_completions_for_match(self, match, complete_event):
- """
- Yield all the possible completions for this input string.
- (The completer assumes that the cursor position was at the end of the
- input string.)
- """
- for match_variable in match.end_nodes():
- varname = match_variable.varname
- start = match_variable.start
-
- completer = self.completers.get(varname)
-
- if completer:
- text = match_variable.value
-
- # Unwrap text.
- unwrapped_text = self.compiled_grammar.unescape(varname, text)
-
- # Create a document, for the completions API (text/cursor_position)
- document = Document(unwrapped_text, len(unwrapped_text))
-
- # Call completer
- for completion in completer.get_completions(document, complete_event):
- new_text = unwrapped_text[:len(text) + completion.start_position] + completion.text
-
- # Wrap again.
- yield Completion(
- text=self.compiled_grammar.escape(varname, new_text),
- start_position=start - len(match.string),
- display=completion.display,
- display_meta=completion.display_meta)
-
- def _remove_duplicates(self, items):
- """
- Remove duplicates, while keeping the order.
- (Sometimes we have duplicates, because the there several matches of the
- same grammar, each yielding similar completions.)
- """
- result = []
- for i in items:
- if i not in result:
- result.append(i)
- return result
+"""
+Completer for a regular grammar.
+"""
+from __future__ import unicode_literals
+
+from prompt_toolkit.completion import Completer, Completion
+from prompt_toolkit.document import Document
+
+from .compiler import _CompiledGrammar
+
+__all__ = (
+ 'GrammarCompleter',
+)
+
+
+class GrammarCompleter(Completer):
+ """
+ Completer which can be used for autocompletion according to variables in
+ the grammar. Each variable can have a different autocompleter.
+
+ :param compiled_grammar: `GrammarCompleter` instance.
+ :param completers: `dict` mapping variable names of the grammar to the
+ `Completer` instances to be used for each variable.
+ """
+ def __init__(self, compiled_grammar, completers):
+ assert isinstance(compiled_grammar, _CompiledGrammar)
+ assert isinstance(completers, dict)
+
+ self.compiled_grammar = compiled_grammar
+ self.completers = completers
+
+ def get_completions(self, document, complete_event):
+ m = self.compiled_grammar.match_prefix(document.text_before_cursor)
+
+ if m:
+ completions = self._remove_duplicates(
+ self._get_completions_for_match(m, complete_event))
+
+ for c in completions:
+ yield c
+
+ def _get_completions_for_match(self, match, complete_event):
+ """
+ Yield all the possible completions for this input string.
+ (The completer assumes that the cursor position was at the end of the
+ input string.)
+ """
+ for match_variable in match.end_nodes():
+ varname = match_variable.varname
+ start = match_variable.start
+
+ completer = self.completers.get(varname)
+
+ if completer:
+ text = match_variable.value
+
+ # Unwrap text.
+ unwrapped_text = self.compiled_grammar.unescape(varname, text)
+
+ # Create a document, for the completions API (text/cursor_position)
+ document = Document(unwrapped_text, len(unwrapped_text))
+
+ # Call completer
+ for completion in completer.get_completions(document, complete_event):
+ new_text = unwrapped_text[:len(text) + completion.start_position] + completion.text
+
+ # Wrap again.
+ yield Completion(
+ text=self.compiled_grammar.escape(varname, new_text),
+ start_position=start - len(match.string),
+ display=completion.display,
+ display_meta=completion.display_meta)
+
+ def _remove_duplicates(self, items):
+ """
+ Remove duplicates, while keeping the order.
+ (Sometimes we have duplicates, because the there several matches of the
+ same grammar, each yielding similar completions.)
+ """
+ result = []
+ for i in items:
+ if i not in result:
+ result.append(i)
+ return result
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py
index 353c91c0870..c166d84fd10 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/lexer.py
@@ -1,57 +1,57 @@
-"""
-`GrammarLexer` is compatible with Pygments lexers and can be used to highlight
-the input using a regular grammar with token annotations.
-"""
-from __future__ import unicode_literals
+"""
+`GrammarLexer` is compatible with Pygments lexers and can be used to highlight
+the input using a regular grammar with token annotations.
+"""
+from __future__ import unicode_literals
from prompt_toolkit.document import Document
-from prompt_toolkit.layout.lexers import Lexer
+from prompt_toolkit.layout.lexers import Lexer
from prompt_toolkit.layout.utils import split_lines
from prompt_toolkit.token import Token
-
-from .compiler import _CompiledGrammar
+
+from .compiler import _CompiledGrammar
from six.moves import range
-
-__all__ = (
- 'GrammarLexer',
-)
-
-
-class GrammarLexer(Lexer):
- """
- Lexer which can be used for highlighting of tokens according to variables in the grammar.
-
- (It does not actual lexing of the string, but it exposes an API, compatible
- with the Pygments lexer class.)
-
- :param compiled_grammar: Grammar as returned by the `compile()` function.
- :param lexers: Dictionary mapping variable names of the regular grammar to
- the lexers that should be used for this part. (This can
- call other lexers recursively.) If you wish a part of the
- grammar to just get one token, use a
- `prompt_toolkit.layout.lexers.SimpleLexer`.
- """
- def __init__(self, compiled_grammar, default_token=None, lexers=None):
- assert isinstance(compiled_grammar, _CompiledGrammar)
- assert default_token is None or isinstance(default_token, tuple)
- assert lexers is None or all(isinstance(v, Lexer) for k, v in lexers.items())
- assert lexers is None or isinstance(lexers, dict)
-
- self.compiled_grammar = compiled_grammar
- self.default_token = default_token or Token
- self.lexers = lexers or {}
-
+
+__all__ = (
+ 'GrammarLexer',
+)
+
+
+class GrammarLexer(Lexer):
+ """
+ Lexer which can be used for highlighting of tokens according to variables in the grammar.
+
+ (It does not actual lexing of the string, but it exposes an API, compatible
+ with the Pygments lexer class.)
+
+ :param compiled_grammar: Grammar as returned by the `compile()` function.
+ :param lexers: Dictionary mapping variable names of the regular grammar to
+ the lexers that should be used for this part. (This can
+ call other lexers recursively.) If you wish a part of the
+ grammar to just get one token, use a
+ `prompt_toolkit.layout.lexers.SimpleLexer`.
+ """
+ def __init__(self, compiled_grammar, default_token=None, lexers=None):
+ assert isinstance(compiled_grammar, _CompiledGrammar)
+ assert default_token is None or isinstance(default_token, tuple)
+ assert lexers is None or all(isinstance(v, Lexer) for k, v in lexers.items())
+ assert lexers is None or isinstance(lexers, dict)
+
+ self.compiled_grammar = compiled_grammar
+ self.default_token = default_token or Token
+ self.lexers = lexers or {}
+
def _get_tokens(self, cli, text):
- m = self.compiled_grammar.match_prefix(text)
-
- if m:
- characters = [[self.default_token, c] for c in text]
-
- for v in m.variables():
- # If we have a `Lexer` instance for this part of the input.
- # Tokenize recursively and apply tokens.
- lexer = self.lexers.get(v.varname)
-
- if lexer:
+ m = self.compiled_grammar.match_prefix(text)
+
+ if m:
+ characters = [[self.default_token, c] for c in text]
+
+ for v in m.variables():
+ # If we have a `Lexer` instance for this part of the input.
+ # Tokenize recursively and apply tokens.
+ lexer = self.lexers.get(v.varname)
+
+ if lexer:
document = Document(text[v.start:v.stop])
lexer_tokens_for_line = lexer.lex_document(cli, document)
lexer_tokens = []
@@ -61,22 +61,22 @@ class GrammarLexer(Lexer):
if lexer_tokens:
lexer_tokens.pop()
- i = v.start
- for t, s in lexer_tokens:
- for c in s:
- if characters[i][0] == self.default_token:
- characters[i][0] = t
- i += 1
-
- # Highlight trailing input.
- trailing_input = m.trailing_input()
- if trailing_input:
- for i in range(trailing_input.start, trailing_input.stop):
- characters[i][0] = Token.TrailingInput
-
- return characters
- else:
- return [(Token, text)]
+ i = v.start
+ for t, s in lexer_tokens:
+ for c in s:
+ if characters[i][0] == self.default_token:
+ characters[i][0] = t
+ i += 1
+
+ # Highlight trailing input.
+ trailing_input = m.trailing_input()
+ if trailing_input:
+ for i in range(trailing_input.start, trailing_input.stop):
+ characters[i][0] = Token.TrailingInput
+
+ return characters
+ else:
+ return [(Token, text)]
def lex_document(self, cli, document):
lines = list(split_lines(self._get_tokens(cli, document.text)))
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py
index 5f903d30dba..e5909b241e3 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/regex_parser.py
@@ -1,262 +1,262 @@
-"""
-Parser for parsing a regular expression.
-Take a string representing a regular expression and return the root node of its
-parse tree.
-
-usage::
-
- root_node = parse_regex('(hello|world)')
-
-Remarks:
-- The regex parser processes multiline, it ignores all whitespace and supports
- multiple named groups with the same name and #-style comments.
-
-Limitations:
-- Lookahead is not supported.
-"""
-from __future__ import unicode_literals
-import re
-
-__all__ = (
- 'Repeat',
- 'Variable',
- 'Regex',
- 'Lookahead',
-
- 'tokenize_regex',
- 'parse_regex',
-)
-
-
-class Node(object):
- """
- Base class for all the grammar nodes.
- (You don't initialize this one.)
- """
- def __add__(self, other_node):
- return Sequence([self, other_node])
-
- def __or__(self, other_node):
- return Any([self, other_node])
-
-
-class Any(Node):
- """
- Union operation (OR operation) between several grammars. You don't
- initialize this yourself, but it's a result of a "Grammar1 | Grammar2"
- operation.
- """
- def __init__(self, children):
- self.children = children
-
- def __or__(self, other_node):
- return Any(self.children + [other_node])
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.children)
-
-
-class Sequence(Node):
- """
- Concatenation operation of several grammars. You don't initialize this
- yourself, but it's a result of a "Grammar1 + Grammar2" operation.
- """
- def __init__(self, children):
- self.children = children
-
- def __add__(self, other_node):
- return Sequence(self.children + [other_node])
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.children)
-
-
-class Regex(Node):
- """
- Regular expression.
- """
- def __init__(self, regex):
- re.compile(regex) # Validate
-
- self.regex = regex
-
- def __repr__(self):
- return '%s(/%s/)' % (self.__class__.__name__, self.regex)
-
-
-class Lookahead(Node):
- """
- Lookahead expression.
- """
- def __init__(self, childnode, negative=False):
- self.childnode = childnode
- self.negative = negative
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.childnode)
-
-
-class Variable(Node):
- """
- Mark a variable in the regular grammar. This will be translated into a
- named group. Each variable can have his own completer, validator, etc..
-
- :param childnode: The grammar which is wrapped inside this variable.
- :param varname: String.
- """
- def __init__(self, childnode, varname=None):
- self.childnode = childnode
- self.varname = varname
-
- def __repr__(self):
- return '%s(childnode=%r, varname=%r)' % (
- self.__class__.__name__, self.childnode, self.varname)
-
-
-class Repeat(Node):
- def __init__(self, childnode, min_repeat=0, max_repeat=None, greedy=True):
- self.childnode = childnode
- self.min_repeat = min_repeat
- self.max_repeat = max_repeat
- self.greedy = greedy
-
- def __repr__(self):
- return '%s(childnode=%r)' % (self.__class__.__name__, self.childnode)
-
-
-def tokenize_regex(input):
- """
- Takes a string, representing a regular expression as input, and tokenizes
- it.
-
- :param input: string, representing a regular expression.
- :returns: List of tokens.
- """
- # Regular expression for tokenizing other regular expressions.
- p = re.compile(r'''^(
- \(\?P\<[a-zA-Z0-9_-]+\> | # Start of named group.
- \(\?#[^)]*\) | # Comment
- \(\?= | # Start of lookahead assertion
- \(\?! | # Start of negative lookahead assertion
- \(\?<= | # If preceded by.
- \(\?< | # If not preceded by.
- \(?: | # Start of group. (non capturing.)
- \( | # Start of group.
- \(?[iLmsux] | # Flags.
- \(?P=[a-zA-Z]+\) | # Back reference to named group
- \) | # End of group.
- \{[^{}]*\} | # Repetition
- \*\? | \+\? | \?\?\ | # Non greedy repetition.
- \* | \+ | \? | # Repetition
- \#.*\n | # Comment
- \\. |
-
- # Character group.
- \[
- ( [^\]\\] | \\.)*
- \] |
-
- [^(){}] |
- .
- )''', re.VERBOSE)
-
- tokens = []
-
- while input:
- m = p.match(input)
- if m:
- token, input = input[:m.end()], input[m.end():]
- if not token.isspace():
- tokens.append(token)
- else:
- raise Exception('Could not tokenize input regex.')
-
- return tokens
-
-
-def parse_regex(regex_tokens):
- """
- Takes a list of tokens from the tokenizer, and returns a parse tree.
- """
- # We add a closing brace because that represents the final pop of the stack.
- tokens = [')'] + regex_tokens[::-1]
-
- def wrap(lst):
- """ Turn list into sequence when it contains several items. """
- if len(lst) == 1:
- return lst[0]
- else:
- return Sequence(lst)
-
- def _parse():
- or_list = []
- result = []
-
- def wrapped_result():
- if or_list == []:
- return wrap(result)
- else:
- or_list.append(result)
- return Any([wrap(i) for i in or_list])
-
- while tokens:
- t = tokens.pop()
-
- if t.startswith('(?P<'):
- variable = Variable(_parse(), varname=t[4:-1])
- result.append(variable)
-
- elif t in ('*', '*?'):
- greedy = (t == '*')
- result[-1] = Repeat(result[-1], greedy=greedy)
-
- elif t in ('+', '+?'):
- greedy = (t == '+')
- result[-1] = Repeat(result[-1], min_repeat=1, greedy=greedy)
-
- elif t in ('?', '??'):
- if result == []:
- raise Exception('Nothing to repeat.' + repr(tokens))
- else:
- greedy = (t == '?')
- result[-1] = Repeat(result[-1], min_repeat=0, max_repeat=1, greedy=greedy)
-
- elif t == '|':
- or_list.append(result)
- result = []
-
- elif t in ('(', '(?:'):
- result.append(_parse())
-
- elif t == '(?!':
- result.append(Lookahead(_parse(), negative=True))
-
- elif t == '(?=':
- result.append(Lookahead(_parse(), negative=False))
-
- elif t == ')':
- return wrapped_result()
-
- elif t.startswith('#'):
- pass
-
- elif t.startswith('{'):
- # TODO: implement!
- raise Exception('{}-style repitition not yet supported' % t)
-
- elif t.startswith('(?'):
- raise Exception('%r not supported' % t)
-
- elif t.isspace():
- pass
- else:
- result.append(Regex(t))
-
- raise Exception("Expecting ')' token")
-
- result = _parse()
-
- if len(tokens) != 0:
- raise Exception("Unmatched parantheses.")
- else:
- return result
+"""
+Parser for parsing a regular expression.
+Take a string representing a regular expression and return the root node of its
+parse tree.
+
+usage::
+
+ root_node = parse_regex('(hello|world)')
+
+Remarks:
+- The regex parser processes multiline, it ignores all whitespace and supports
+ multiple named groups with the same name and #-style comments.
+
+Limitations:
+- Lookahead is not supported.
+"""
+from __future__ import unicode_literals
+import re
+
+__all__ = (
+ 'Repeat',
+ 'Variable',
+ 'Regex',
+ 'Lookahead',
+
+ 'tokenize_regex',
+ 'parse_regex',
+)
+
+
+class Node(object):
+ """
+ Base class for all the grammar nodes.
+ (You don't initialize this one.)
+ """
+ def __add__(self, other_node):
+ return Sequence([self, other_node])
+
+ def __or__(self, other_node):
+ return Any([self, other_node])
+
+
+class Any(Node):
+ """
+ Union operation (OR operation) between several grammars. You don't
+ initialize this yourself, but it's a result of a "Grammar1 | Grammar2"
+ operation.
+ """
+ def __init__(self, children):
+ self.children = children
+
+ def __or__(self, other_node):
+ return Any(self.children + [other_node])
+
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.children)
+
+
+class Sequence(Node):
+ """
+ Concatenation operation of several grammars. You don't initialize this
+ yourself, but it's a result of a "Grammar1 + Grammar2" operation.
+ """
+ def __init__(self, children):
+ self.children = children
+
+ def __add__(self, other_node):
+ return Sequence(self.children + [other_node])
+
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.children)
+
+
+class Regex(Node):
+ """
+ Regular expression.
+ """
+ def __init__(self, regex):
+ re.compile(regex) # Validate
+
+ self.regex = regex
+
+ def __repr__(self):
+ return '%s(/%s/)' % (self.__class__.__name__, self.regex)
+
+
+class Lookahead(Node):
+ """
+ Lookahead expression.
+ """
+ def __init__(self, childnode, negative=False):
+ self.childnode = childnode
+ self.negative = negative
+
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.childnode)
+
+
+class Variable(Node):
+ """
+ Mark a variable in the regular grammar. This will be translated into a
+ named group. Each variable can have his own completer, validator, etc..
+
+ :param childnode: The grammar which is wrapped inside this variable.
+ :param varname: String.
+ """
+ def __init__(self, childnode, varname=None):
+ self.childnode = childnode
+ self.varname = varname
+
+ def __repr__(self):
+ return '%s(childnode=%r, varname=%r)' % (
+ self.__class__.__name__, self.childnode, self.varname)
+
+
+class Repeat(Node):
+ def __init__(self, childnode, min_repeat=0, max_repeat=None, greedy=True):
+ self.childnode = childnode
+ self.min_repeat = min_repeat
+ self.max_repeat = max_repeat
+ self.greedy = greedy
+
+ def __repr__(self):
+ return '%s(childnode=%r)' % (self.__class__.__name__, self.childnode)
+
+
+def tokenize_regex(input):
+ """
+ Takes a string, representing a regular expression as input, and tokenizes
+ it.
+
+ :param input: string, representing a regular expression.
+ :returns: List of tokens.
+ """
+ # Regular expression for tokenizing other regular expressions.
+ p = re.compile(r'''^(
+ \(\?P\<[a-zA-Z0-9_-]+\> | # Start of named group.
+ \(\?#[^)]*\) | # Comment
+ \(\?= | # Start of lookahead assertion
+ \(\?! | # Start of negative lookahead assertion
+ \(\?<= | # If preceded by.
+ \(\?< | # If not preceded by.
+ \(?: | # Start of group. (non capturing.)
+ \( | # Start of group.
+ \(?[iLmsux] | # Flags.
+ \(?P=[a-zA-Z]+\) | # Back reference to named group
+ \) | # End of group.
+ \{[^{}]*\} | # Repetition
+ \*\? | \+\? | \?\?\ | # Non greedy repetition.
+ \* | \+ | \? | # Repetition
+ \#.*\n | # Comment
+ \\. |
+
+ # Character group.
+ \[
+ ( [^\]\\] | \\.)*
+ \] |
+
+ [^(){}] |
+ .
+ )''', re.VERBOSE)
+
+ tokens = []
+
+ while input:
+ m = p.match(input)
+ if m:
+ token, input = input[:m.end()], input[m.end():]
+ if not token.isspace():
+ tokens.append(token)
+ else:
+ raise Exception('Could not tokenize input regex.')
+
+ return tokens
+
+
+def parse_regex(regex_tokens):
+ """
+ Takes a list of tokens from the tokenizer, and returns a parse tree.
+ """
+ # We add a closing brace because that represents the final pop of the stack.
+ tokens = [')'] + regex_tokens[::-1]
+
+ def wrap(lst):
+ """ Turn list into sequence when it contains several items. """
+ if len(lst) == 1:
+ return lst[0]
+ else:
+ return Sequence(lst)
+
+ def _parse():
+ or_list = []
+ result = []
+
+ def wrapped_result():
+ if or_list == []:
+ return wrap(result)
+ else:
+ or_list.append(result)
+ return Any([wrap(i) for i in or_list])
+
+ while tokens:
+ t = tokens.pop()
+
+ if t.startswith('(?P<'):
+ variable = Variable(_parse(), varname=t[4:-1])
+ result.append(variable)
+
+ elif t in ('*', '*?'):
+ greedy = (t == '*')
+ result[-1] = Repeat(result[-1], greedy=greedy)
+
+ elif t in ('+', '+?'):
+ greedy = (t == '+')
+ result[-1] = Repeat(result[-1], min_repeat=1, greedy=greedy)
+
+ elif t in ('?', '??'):
+ if result == []:
+ raise Exception('Nothing to repeat.' + repr(tokens))
+ else:
+ greedy = (t == '?')
+ result[-1] = Repeat(result[-1], min_repeat=0, max_repeat=1, greedy=greedy)
+
+ elif t == '|':
+ or_list.append(result)
+ result = []
+
+ elif t in ('(', '(?:'):
+ result.append(_parse())
+
+ elif t == '(?!':
+ result.append(Lookahead(_parse(), negative=True))
+
+ elif t == '(?=':
+ result.append(Lookahead(_parse(), negative=False))
+
+ elif t == ')':
+ return wrapped_result()
+
+ elif t.startswith('#'):
+ pass
+
+ elif t.startswith('{'):
+ # TODO: implement!
+ raise Exception('{}-style repitition not yet supported' % t)
+
+ elif t.startswith('(?'):
+ raise Exception('%r not supported' % t)
+
+ elif t.isspace():
+ pass
+ else:
+ result.append(Regex(t))
+
+ raise Exception("Expecting ')' token")
+
+ result = _parse()
+
+ if len(tokens) != 0:
+ raise Exception("Unmatched parantheses.")
+ else:
+ return result
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py
index 14ee901244f..d5f8cfccc6a 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/regular_languages/validation.py
@@ -1,57 +1,57 @@
-"""
-Validator for a regular langage.
-"""
-from __future__ import unicode_literals
-
-from prompt_toolkit.validation import Validator, ValidationError
-from prompt_toolkit.document import Document
-
-from .compiler import _CompiledGrammar
-
-__all__ = (
- 'GrammarValidator',
-)
-
-
-class GrammarValidator(Validator):
- """
- Validator which can be used for validation according to variables in
- the grammar. Each variable can have its own validator.
-
- :param compiled_grammar: `GrammarCompleter` instance.
- :param validators: `dict` mapping variable names of the grammar to the
- `Validator` instances to be used for each variable.
- """
- def __init__(self, compiled_grammar, validators):
- assert isinstance(compiled_grammar, _CompiledGrammar)
- assert isinstance(validators, dict)
-
- self.compiled_grammar = compiled_grammar
- self.validators = validators
-
- def validate(self, document):
- # Parse input document.
- # We use `match`, not `match_prefix`, because for validation, we want
- # the actual, unambiguous interpretation of the input.
- m = self.compiled_grammar.match(document.text)
-
- if m:
- for v in m.variables():
- validator = self.validators.get(v.varname)
-
- if validator:
- # Unescape text.
- unwrapped_text = self.compiled_grammar.unescape(v.varname, v.value)
-
- # Create a document, for the completions API (text/cursor_position)
- inner_document = Document(unwrapped_text, len(unwrapped_text))
-
- try:
- validator.validate(inner_document)
- except ValidationError as e:
- raise ValidationError(
+"""
+Validator for a regular langage.
+"""
+from __future__ import unicode_literals
+
+from prompt_toolkit.validation import Validator, ValidationError
+from prompt_toolkit.document import Document
+
+from .compiler import _CompiledGrammar
+
+__all__ = (
+ 'GrammarValidator',
+)
+
+
+class GrammarValidator(Validator):
+ """
+ Validator which can be used for validation according to variables in
+ the grammar. Each variable can have its own validator.
+
+ :param compiled_grammar: `GrammarCompleter` instance.
+ :param validators: `dict` mapping variable names of the grammar to the
+ `Validator` instances to be used for each variable.
+ """
+ def __init__(self, compiled_grammar, validators):
+ assert isinstance(compiled_grammar, _CompiledGrammar)
+ assert isinstance(validators, dict)
+
+ self.compiled_grammar = compiled_grammar
+ self.validators = validators
+
+ def validate(self, document):
+ # Parse input document.
+ # We use `match`, not `match_prefix`, because for validation, we want
+ # the actual, unambiguous interpretation of the input.
+ m = self.compiled_grammar.match(document.text)
+
+ if m:
+ for v in m.variables():
+ validator = self.validators.get(v.varname)
+
+ if validator:
+ # Unescape text.
+ unwrapped_text = self.compiled_grammar.unescape(v.varname, v.value)
+
+ # Create a document, for the completions API (text/cursor_position)
+ inner_document = Document(unwrapped_text, len(unwrapped_text))
+
+ try:
+ validator.validate(inner_document)
+ except ValidationError as e:
+ raise ValidationError(
cursor_position=v.start + e.cursor_position,
- message=e.message)
- else:
- raise ValidationError(cursor_position=len(document.text),
- message='Invalid command')
+ message=e.message)
+ else:
+ raise ValidationError(cursor_position=len(document.text),
+ message='Invalid command')
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py
index 815c9adf5e8..7b7aeec8200 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/__init__.py
@@ -1,2 +1,2 @@
-from .server import *
-from .application import *
+from .server import *
+from .application import *
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py
index e499f299971..7fe6cc97b73 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/application.py
@@ -1,32 +1,32 @@
-"""
-Interface for Telnet applications.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-__all__ = (
- 'TelnetApplication',
-)
-
-
-class TelnetApplication(with_metaclass(ABCMeta, object)):
- """
- The interface which has to be implemented for any telnet application.
- An instance of this class has to be passed to `TelnetServer`.
- """
- @abstractmethod
- def client_connected(self, telnet_connection):
- """
- Called when a new client was connected.
-
- Probably you want to call `telnet_connection.set_cli` here to set a
- the CommandLineInterface instance to be used.
- Hint: Use the following shortcut: `prompt_toolkit.shortcuts.create_cli`
- """
-
- @abstractmethod
- def client_leaving(self, telnet_connection):
- """
- Called when a client quits.
- """
+"""
+Interface for Telnet applications.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+__all__ = (
+ 'TelnetApplication',
+)
+
+
+class TelnetApplication(with_metaclass(ABCMeta, object)):
+ """
+ The interface which has to be implemented for any telnet application.
+ An instance of this class has to be passed to `TelnetServer`.
+ """
+ @abstractmethod
+ def client_connected(self, telnet_connection):
+ """
+ Called when a new client was connected.
+
+ Probably you want to call `telnet_connection.set_cli` here to set a
+ the CommandLineInterface instance to be used.
+ Hint: Use the following shortcut: `prompt_toolkit.shortcuts.create_cli`
+ """
+
+ @abstractmethod
+ def client_leaving(self, telnet_connection):
+ """
+ Called when a client quits.
+ """
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py
index 8d97ec9ac7c..10792ceed6c 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/log.py
@@ -1,11 +1,11 @@
-"""
-Python logger for the telnet server.
-"""
-from __future__ import unicode_literals
-import logging
-
-logger = logging.getLogger(__package__)
-
-__all__ = (
- 'logger',
-)
+"""
+Python logger for the telnet server.
+"""
+from __future__ import unicode_literals
+import logging
+
+logger = logging.getLogger(__package__)
+
+__all__ = (
+ 'logger',
+)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py
index 2774160121c..b1bb0ccbe80 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/protocol.py
@@ -1,181 +1,181 @@
-"""
-Parser for the Telnet protocol. (Not a complete implementation of the telnet
-specification, but sufficient for a command line interface.)
-
-Inspired by `Twisted.conch.telnet`.
-"""
-from __future__ import unicode_literals
-
-import struct
-from six import int2byte, binary_type, iterbytes
-
-from .log import logger
-
-__all__ = (
- 'TelnetProtocolParser',
-)
-
-# Telnet constants.
-NOP = int2byte(0)
-SGA = int2byte(3)
-
-IAC = int2byte(255)
-DO = int2byte(253)
-DONT = int2byte(254)
-LINEMODE = int2byte(34)
-SB = int2byte(250)
-WILL = int2byte(251)
-WONT = int2byte(252)
-MODE = int2byte(1)
-SE = int2byte(240)
-ECHO = int2byte(1)
-NAWS = int2byte(31)
-LINEMODE = int2byte(34)
-SUPPRESS_GO_AHEAD = int2byte(3)
-
-DM = int2byte(242)
-BRK = int2byte(243)
-IP = int2byte(244)
-AO = int2byte(245)
-AYT = int2byte(246)
-EC = int2byte(247)
-EL = int2byte(248)
-GA = int2byte(249)
-
-
-class TelnetProtocolParser(object):
- """
- Parser for the Telnet protocol.
- Usage::
-
- def data_received(data):
- print(data)
-
- def size_received(rows, columns):
- print(rows, columns)
-
- p = TelnetProtocolParser(data_received, size_received)
- p.feed(binary_data)
- """
- def __init__(self, data_received_callback, size_received_callback):
- self.data_received_callback = data_received_callback
- self.size_received_callback = size_received_callback
-
- self._parser = self._parse_coroutine()
- self._parser.send(None)
-
- def received_data(self, data):
- self.data_received_callback(data)
-
- def do_received(self, data):
- """ Received telnet DO command. """
- logger.info('DO %r', data)
-
- def dont_received(self, data):
- """ Received telnet DONT command. """
- logger.info('DONT %r', data)
-
- def will_received(self, data):
- """ Received telnet WILL command. """
- logger.info('WILL %r', data)
-
- def wont_received(self, data):
- """ Received telnet WONT command. """
- logger.info('WONT %r', data)
-
- def command_received(self, command, data):
- if command == DO:
- self.do_received(data)
-
- elif command == DONT:
- self.dont_received(data)
-
- elif command == WILL:
- self.will_received(data)
-
- elif command == WONT:
- self.wont_received(data)
-
- else:
- logger.info('command received %r %r', command, data)
-
- def naws(self, data):
- """
- Received NAWS. (Window dimensions.)
- """
- if len(data) == 4:
- # NOTE: the first parameter of struct.unpack should be
- # a 'str' object. Both on Py2/py3. This crashes on OSX
- # otherwise.
- columns, rows = struct.unpack(str('!HH'), data)
- self.size_received_callback(rows, columns)
- else:
- logger.warning('Wrong number of NAWS bytes')
-
- def negotiate(self, data):
- """
- Got negotiate data.
- """
- command, payload = data[0:1], data[1:]
- assert isinstance(command, bytes)
-
- if command == NAWS:
- self.naws(payload)
- else:
- logger.info('Negotiate (%r got bytes)', len(data))
-
- def _parse_coroutine(self):
- """
- Parser state machine.
- Every 'yield' expression returns the next byte.
- """
- while True:
- d = yield
-
- if d == int2byte(0):
- pass # NOP
-
- # Go to state escaped.
- elif d == IAC:
- d2 = yield
-
- if d2 == IAC:
- self.received_data(d2)
-
- # Handle simple commands.
- elif d2 in (NOP, DM, BRK, IP, AO, AYT, EC, EL, GA):
- self.command_received(d2, None)
-
- # Handle IAC-[DO/DONT/WILL/WONT] commands.
- elif d2 in (DO, DONT, WILL, WONT):
- d3 = yield
- self.command_received(d2, d3)
-
- # Subnegotiation
- elif d2 == SB:
- # Consume everything until next IAC-SE
- data = []
-
- while True:
- d3 = yield
-
- if d3 == IAC:
- d4 = yield
- if d4 == SE:
- break
- else:
- data.append(d4)
- else:
- data.append(d3)
-
- self.negotiate(b''.join(data))
- else:
- self.received_data(d)
-
- def feed(self, data):
- """
- Feed data to the parser.
- """
- assert isinstance(data, binary_type)
- for b in iterbytes(data):
- self._parser.send(int2byte(b))
+"""
+Parser for the Telnet protocol. (Not a complete implementation of the telnet
+specification, but sufficient for a command line interface.)
+
+Inspired by `Twisted.conch.telnet`.
+"""
+from __future__ import unicode_literals
+
+import struct
+from six import int2byte, binary_type, iterbytes
+
+from .log import logger
+
+__all__ = (
+ 'TelnetProtocolParser',
+)
+
+# Telnet constants.
+NOP = int2byte(0)
+SGA = int2byte(3)
+
+IAC = int2byte(255)
+DO = int2byte(253)
+DONT = int2byte(254)
+LINEMODE = int2byte(34)
+SB = int2byte(250)
+WILL = int2byte(251)
+WONT = int2byte(252)
+MODE = int2byte(1)
+SE = int2byte(240)
+ECHO = int2byte(1)
+NAWS = int2byte(31)
+LINEMODE = int2byte(34)
+SUPPRESS_GO_AHEAD = int2byte(3)
+
+DM = int2byte(242)
+BRK = int2byte(243)
+IP = int2byte(244)
+AO = int2byte(245)
+AYT = int2byte(246)
+EC = int2byte(247)
+EL = int2byte(248)
+GA = int2byte(249)
+
+
+class TelnetProtocolParser(object):
+ """
+ Parser for the Telnet protocol.
+ Usage::
+
+ def data_received(data):
+ print(data)
+
+ def size_received(rows, columns):
+ print(rows, columns)
+
+ p = TelnetProtocolParser(data_received, size_received)
+ p.feed(binary_data)
+ """
+ def __init__(self, data_received_callback, size_received_callback):
+ self.data_received_callback = data_received_callback
+ self.size_received_callback = size_received_callback
+
+ self._parser = self._parse_coroutine()
+ self._parser.send(None)
+
+ def received_data(self, data):
+ self.data_received_callback(data)
+
+ def do_received(self, data):
+ """ Received telnet DO command. """
+ logger.info('DO %r', data)
+
+ def dont_received(self, data):
+ """ Received telnet DONT command. """
+ logger.info('DONT %r', data)
+
+ def will_received(self, data):
+ """ Received telnet WILL command. """
+ logger.info('WILL %r', data)
+
+ def wont_received(self, data):
+ """ Received telnet WONT command. """
+ logger.info('WONT %r', data)
+
+ def command_received(self, command, data):
+ if command == DO:
+ self.do_received(data)
+
+ elif command == DONT:
+ self.dont_received(data)
+
+ elif command == WILL:
+ self.will_received(data)
+
+ elif command == WONT:
+ self.wont_received(data)
+
+ else:
+ logger.info('command received %r %r', command, data)
+
+ def naws(self, data):
+ """
+ Received NAWS. (Window dimensions.)
+ """
+ if len(data) == 4:
+ # NOTE: the first parameter of struct.unpack should be
+ # a 'str' object. Both on Py2/py3. This crashes on OSX
+ # otherwise.
+ columns, rows = struct.unpack(str('!HH'), data)
+ self.size_received_callback(rows, columns)
+ else:
+ logger.warning('Wrong number of NAWS bytes')
+
+ def negotiate(self, data):
+ """
+ Got negotiate data.
+ """
+ command, payload = data[0:1], data[1:]
+ assert isinstance(command, bytes)
+
+ if command == NAWS:
+ self.naws(payload)
+ else:
+ logger.info('Negotiate (%r got bytes)', len(data))
+
+ def _parse_coroutine(self):
+ """
+ Parser state machine.
+ Every 'yield' expression returns the next byte.
+ """
+ while True:
+ d = yield
+
+ if d == int2byte(0):
+ pass # NOP
+
+ # Go to state escaped.
+ elif d == IAC:
+ d2 = yield
+
+ if d2 == IAC:
+ self.received_data(d2)
+
+ # Handle simple commands.
+ elif d2 in (NOP, DM, BRK, IP, AO, AYT, EC, EL, GA):
+ self.command_received(d2, None)
+
+ # Handle IAC-[DO/DONT/WILL/WONT] commands.
+ elif d2 in (DO, DONT, WILL, WONT):
+ d3 = yield
+ self.command_received(d2, d3)
+
+ # Subnegotiation
+ elif d2 == SB:
+ # Consume everything until next IAC-SE
+ data = []
+
+ while True:
+ d3 = yield
+
+ if d3 == IAC:
+ d4 = yield
+ if d4 == SE:
+ break
+ else:
+ data.append(d4)
+ else:
+ data.append(d3)
+
+ self.negotiate(b''.join(data))
+ else:
+ self.received_data(d)
+
+ def feed(self, data):
+ """
+ Feed data to the parser.
+ """
+ assert isinstance(data, binary_type)
+ for b in iterbytes(data):
+ self._parser.send(int2byte(b))
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py
index d8f8a087eb6..d75a9572eb9 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/telnet/server.py
@@ -1,407 +1,407 @@
-"""
-Telnet server.
-
-Example usage::
-
- class MyTelnetApplication(TelnetApplication):
- def client_connected(self, telnet_connection):
- # Set CLI with simple prompt.
- telnet_connection.set_application(
- telnet_connection.create_prompt_application(...))
-
- def handle_command(self, telnet_connection, document):
- # When the client enters a command, just reply.
- telnet_connection.send('You said: %r\n\n' % document.text)
-
- ...
-
- a = MyTelnetApplication()
- TelnetServer(application=a, host='127.0.0.1', port=23).run()
-"""
-from __future__ import unicode_literals
-
-import socket
-import select
-
-import threading
-import os
-import fcntl
-
-from six import int2byte, text_type, binary_type
-from codecs import getincrementaldecoder
-
-from prompt_toolkit.enums import DEFAULT_BUFFER
-from prompt_toolkit.eventloop.base import EventLoop
-from prompt_toolkit.interface import CommandLineInterface, Application
-from prompt_toolkit.layout.screen import Size
-from prompt_toolkit.shortcuts import create_prompt_application
-from prompt_toolkit.terminal.vt100_input import InputStream
-from prompt_toolkit.terminal.vt100_output import Vt100_Output
-
-from .log import logger
-from .protocol import IAC, DO, LINEMODE, SB, MODE, SE, WILL, ECHO, NAWS, SUPPRESS_GO_AHEAD
-from .protocol import TelnetProtocolParser
-from .application import TelnetApplication
-
-__all__ = (
- 'TelnetServer',
-)
-
-
-def _initialize_telnet(connection):
- logger.info('Initializing telnet connection')
-
- # Iac Do Linemode
- connection.send(IAC + DO + LINEMODE)
-
- # Suppress Go Ahead. (This seems important for Putty to do correct echoing.)
- # This will allow bi-directional operation.
- connection.send(IAC + WILL + SUPPRESS_GO_AHEAD)
-
- # Iac sb
- connection.send(IAC + SB + LINEMODE + MODE + int2byte(0) + IAC + SE)
-
- # IAC Will Echo
- connection.send(IAC + WILL + ECHO)
-
- # Negotiate window size
- connection.send(IAC + DO + NAWS)
-
-
-class _ConnectionStdout(object):
- """
- Wrapper around socket which provides `write` and `flush` methods for the
- Vt100_Output output.
- """
- def __init__(self, connection, encoding):
- self._encoding = encoding
- self._connection = connection
- self._buffer = []
-
- def write(self, data):
- assert isinstance(data, text_type)
- self._buffer.append(data.encode(self._encoding))
- self.flush()
-
- def flush(self):
- try:
- self._connection.send(b''.join(self._buffer))
- except socket.error as e:
- logger.error("Couldn't send data over socket: %s" % e)
-
- self._buffer = []
-
-
-class TelnetConnection(object):
- """
- Class that represents one Telnet connection.
- """
- def __init__(self, conn, addr, application, server, encoding):
- assert isinstance(addr, tuple) # (addr, port) tuple
- assert isinstance(application, TelnetApplication)
- assert isinstance(server, TelnetServer)
- assert isinstance(encoding, text_type) # e.g. 'utf-8'
-
- self.conn = conn
- self.addr = addr
- self.application = application
- self.closed = False
- self.handling_command = True
- self.server = server
- self.encoding = encoding
- self.callback = None # Function that handles the CLI result.
-
- # Create "Output" object.
- self.size = Size(rows=40, columns=79)
-
- # Initialize.
- _initialize_telnet(conn)
-
- # Create output.
- def get_size():
- return self.size
- self.stdout = _ConnectionStdout(conn, encoding=encoding)
+"""
+Telnet server.
+
+Example usage::
+
+ class MyTelnetApplication(TelnetApplication):
+ def client_connected(self, telnet_connection):
+ # Set CLI with simple prompt.
+ telnet_connection.set_application(
+ telnet_connection.create_prompt_application(...))
+
+ def handle_command(self, telnet_connection, document):
+ # When the client enters a command, just reply.
+ telnet_connection.send('You said: %r\n\n' % document.text)
+
+ ...
+
+ a = MyTelnetApplication()
+ TelnetServer(application=a, host='127.0.0.1', port=23).run()
+"""
+from __future__ import unicode_literals
+
+import socket
+import select
+
+import threading
+import os
+import fcntl
+
+from six import int2byte, text_type, binary_type
+from codecs import getincrementaldecoder
+
+from prompt_toolkit.enums import DEFAULT_BUFFER
+from prompt_toolkit.eventloop.base import EventLoop
+from prompt_toolkit.interface import CommandLineInterface, Application
+from prompt_toolkit.layout.screen import Size
+from prompt_toolkit.shortcuts import create_prompt_application
+from prompt_toolkit.terminal.vt100_input import InputStream
+from prompt_toolkit.terminal.vt100_output import Vt100_Output
+
+from .log import logger
+from .protocol import IAC, DO, LINEMODE, SB, MODE, SE, WILL, ECHO, NAWS, SUPPRESS_GO_AHEAD
+from .protocol import TelnetProtocolParser
+from .application import TelnetApplication
+
+__all__ = (
+ 'TelnetServer',
+)
+
+
+def _initialize_telnet(connection):
+ logger.info('Initializing telnet connection')
+
+ # Iac Do Linemode
+ connection.send(IAC + DO + LINEMODE)
+
+ # Suppress Go Ahead. (This seems important for Putty to do correct echoing.)
+ # This will allow bi-directional operation.
+ connection.send(IAC + WILL + SUPPRESS_GO_AHEAD)
+
+ # Iac sb
+ connection.send(IAC + SB + LINEMODE + MODE + int2byte(0) + IAC + SE)
+
+ # IAC Will Echo
+ connection.send(IAC + WILL + ECHO)
+
+ # Negotiate window size
+ connection.send(IAC + DO + NAWS)
+
+
+class _ConnectionStdout(object):
+ """
+ Wrapper around socket which provides `write` and `flush` methods for the
+ Vt100_Output output.
+ """
+ def __init__(self, connection, encoding):
+ self._encoding = encoding
+ self._connection = connection
+ self._buffer = []
+
+ def write(self, data):
+ assert isinstance(data, text_type)
+ self._buffer.append(data.encode(self._encoding))
+ self.flush()
+
+ def flush(self):
+ try:
+ self._connection.send(b''.join(self._buffer))
+ except socket.error as e:
+ logger.error("Couldn't send data over socket: %s" % e)
+
+ self._buffer = []
+
+
+class TelnetConnection(object):
+ """
+ Class that represents one Telnet connection.
+ """
+ def __init__(self, conn, addr, application, server, encoding):
+ assert isinstance(addr, tuple) # (addr, port) tuple
+ assert isinstance(application, TelnetApplication)
+ assert isinstance(server, TelnetServer)
+ assert isinstance(encoding, text_type) # e.g. 'utf-8'
+
+ self.conn = conn
+ self.addr = addr
+ self.application = application
+ self.closed = False
+ self.handling_command = True
+ self.server = server
+ self.encoding = encoding
+ self.callback = None # Function that handles the CLI result.
+
+ # Create "Output" object.
+ self.size = Size(rows=40, columns=79)
+
+ # Initialize.
+ _initialize_telnet(conn)
+
+ # Create output.
+ def get_size():
+ return self.size
+ self.stdout = _ConnectionStdout(conn, encoding=encoding)
self.vt100_output = Vt100_Output(self.stdout, get_size, write_binary=False)
-
- # Create an eventloop (adaptor) for the CommandLineInterface.
- self.eventloop = _TelnetEventLoopInterface(server)
-
- # Set default CommandLineInterface.
- self.set_application(create_prompt_application())
-
- # Call client_connected
- application.client_connected(self)
-
- # Draw for the first time.
- self.handling_command = False
- self.cli._redraw()
-
- def set_application(self, app, callback=None):
- """
- Set ``CommandLineInterface`` instance for this connection.
- (This can be replaced any time.)
-
- :param cli: CommandLineInterface instance.
- :param callback: Callable that takes the result of the CLI.
- """
- assert isinstance(app, Application)
- assert callback is None or callable(callback)
-
- self.cli = CommandLineInterface(
- application=app,
- eventloop=self.eventloop,
- output=self.vt100_output)
- self.callback = callback
-
- # Create a parser, and parser callbacks.
- cb = self.cli.create_eventloop_callbacks()
- inputstream = InputStream(cb.feed_key)
-
- # Input decoder for stdin. (Required when working with multibyte
- # characters, like chinese input.)
- stdin_decoder_cls = getincrementaldecoder(self.encoding)
- stdin_decoder = [stdin_decoder_cls()] # nonlocal
-
- # Tell the CLI that it's running. We don't start it through the run()
- # call, but will still want _redraw() to work.
- self.cli._is_running = True
-
- def data_received(data):
- """ TelnetProtocolParser 'data_received' callback """
- assert isinstance(data, binary_type)
-
- try:
- result = stdin_decoder[0].decode(data)
- inputstream.feed(result)
- except UnicodeDecodeError:
- stdin_decoder[0] = stdin_decoder_cls()
- return ''
-
- def size_received(rows, columns):
- """ TelnetProtocolParser 'size_received' callback """
- self.size = Size(rows=rows, columns=columns)
- cb.terminal_size_changed()
-
- self.parser = TelnetProtocolParser(data_received, size_received)
-
- def feed(self, data):
- """
- Handler for incoming data. (Called by TelnetServer.)
- """
- assert isinstance(data, binary_type)
-
- self.parser.feed(data)
-
- # Render again.
- self.cli._redraw()
-
- # When a return value has been set (enter was pressed), handle command.
- if self.cli.is_returning:
- try:
- return_value = self.cli.return_value()
- except (EOFError, KeyboardInterrupt) as e:
- # Control-D or Control-C was pressed.
- logger.info('%s, closing connection.', type(e).__name__)
- self.close()
- return
-
- # Handle CLI command
- self._handle_command(return_value)
-
- def _handle_command(self, command):
- """
- Handle command. This will run in a separate thread, in order not
- to block the event loop.
- """
- logger.info('Handle command %r', command)
-
- def in_executor():
- self.handling_command = True
- try:
- if self.callback is not None:
- self.callback(self, command)
- finally:
- self.server.call_from_executor(done)
-
- def done():
- self.handling_command = False
-
- # Reset state and draw again. (If the connection is still open --
- # the application could have called TelnetConnection.close()
- if not self.closed:
- self.cli.reset()
- self.cli.buffers[DEFAULT_BUFFER].reset()
- self.cli.renderer.request_absolute_cursor_position()
- self.vt100_output.flush()
- self.cli._redraw()
-
- self.server.run_in_executor(in_executor)
-
- def erase_screen(self):
- """
- Erase output screen.
- """
- self.vt100_output.erase_screen()
- self.vt100_output.cursor_goto(0, 0)
- self.vt100_output.flush()
-
- def send(self, data):
- """
- Send text to the client.
- """
- assert isinstance(data, text_type)
-
- # When data is send back to the client, we should replace the line
- # endings. (We didn't allocate a real pseudo terminal, and the telnet
- # connection is raw, so we are responsible for inserting \r.)
- self.stdout.write(data.replace('\n', '\r\n'))
- self.stdout.flush()
-
- def close(self):
- """
- Close the connection.
- """
- self.application.client_leaving(self)
-
- self.conn.close()
- self.closed = True
-
-
-class _TelnetEventLoopInterface(EventLoop):
- """
- Eventloop object to be assigned to `CommandLineInterface`.
- """
- def __init__(self, server):
- self._server = server
-
- def close(self):
- " Ignore. "
-
- def stop(self):
- " Ignore. "
-
- def run_in_executor(self, callback):
- self._server.run_in_executor(callback)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- self._server.call_from_executor(callback)
-
- def add_reader(self, fd, callback):
- raise NotImplementedError
-
- def remove_reader(self, fd):
- raise NotImplementedError
-
-
-class TelnetServer(object):
- """
- Telnet server implementation.
- """
- def __init__(self, host='127.0.0.1', port=23, application=None, encoding='utf-8'):
- assert isinstance(host, text_type)
- assert isinstance(port, int)
- assert isinstance(application, TelnetApplication)
- assert isinstance(encoding, text_type)
-
- self.host = host
- self.port = port
- self.application = application
- self.encoding = encoding
-
- self.connections = set()
-
- self._calls_from_executor = []
-
- # Create a pipe for inter thread communication.
- self._schedule_pipe = os.pipe()
- fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
-
- @classmethod
- def create_socket(cls, host, port):
- # Create and bind socket
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.bind((host, port))
-
- s.listen(4)
- return s
-
- def run_in_executor(self, callback):
- threading.Thread(target=callback).start()
-
- def call_from_executor(self, callback):
- self._calls_from_executor.append(callback)
-
- if self._schedule_pipe:
- os.write(self._schedule_pipe[1], b'x')
-
- def _process_callbacks(self):
- """
- Process callbacks from `call_from_executor` in eventloop.
- """
- # Flush all the pipe content.
- os.read(self._schedule_pipe[0], 1024)
-
- # Process calls from executor.
- calls_from_executor, self._calls_from_executor = self._calls_from_executor, []
- for c in calls_from_executor:
- c()
-
- def run(self):
- """
- Run the eventloop for the telnet server.
- """
- listen_socket = self.create_socket(self.host, self.port)
- logger.info('Listening for telnet connections on %s port %r', self.host, self.port)
-
- try:
- while True:
- # Removed closed connections.
- self.connections = set([c for c in self.connections if not c.closed])
-
- # Ignore connections handling commands.
- connections = set([c for c in self.connections if not c.handling_command])
-
- # Wait for next event.
- read_list = (
- [listen_socket, self._schedule_pipe[0]] +
- [c.conn for c in connections])
-
- read, _, _ = select.select(read_list, [], [])
-
- for s in read:
- # When the socket itself is ready, accept a new connection.
- if s == listen_socket:
- self._accept(listen_socket)
-
- # If we receive something on our "call_from_executor" pipe, process
- # these callbacks in a thread safe way.
- elif s == self._schedule_pipe[0]:
- self._process_callbacks()
-
- # Handle incoming data on socket.
- else:
- self._handle_incoming_data(s)
- finally:
- listen_socket.close()
-
- def _accept(self, listen_socket):
- """
- Accept new incoming connection.
- """
- conn, addr = listen_socket.accept()
- connection = TelnetConnection(conn, addr, self.application, self, encoding=self.encoding)
- self.connections.add(connection)
-
- logger.info('New connection %r %r', *addr)
-
- def _handle_incoming_data(self, conn):
- """
- Handle incoming data on socket.
- """
- connection = [c for c in self.connections if c.conn == conn][0]
- data = conn.recv(1024)
- if data:
- connection.feed(data)
- else:
- self.connections.remove(connection)
+
+ # Create an eventloop (adaptor) for the CommandLineInterface.
+ self.eventloop = _TelnetEventLoopInterface(server)
+
+ # Set default CommandLineInterface.
+ self.set_application(create_prompt_application())
+
+ # Call client_connected
+ application.client_connected(self)
+
+ # Draw for the first time.
+ self.handling_command = False
+ self.cli._redraw()
+
+ def set_application(self, app, callback=None):
+ """
+ Set ``CommandLineInterface`` instance for this connection.
+ (This can be replaced any time.)
+
+ :param cli: CommandLineInterface instance.
+ :param callback: Callable that takes the result of the CLI.
+ """
+ assert isinstance(app, Application)
+ assert callback is None or callable(callback)
+
+ self.cli = CommandLineInterface(
+ application=app,
+ eventloop=self.eventloop,
+ output=self.vt100_output)
+ self.callback = callback
+
+ # Create a parser, and parser callbacks.
+ cb = self.cli.create_eventloop_callbacks()
+ inputstream = InputStream(cb.feed_key)
+
+ # Input decoder for stdin. (Required when working with multibyte
+ # characters, like chinese input.)
+ stdin_decoder_cls = getincrementaldecoder(self.encoding)
+ stdin_decoder = [stdin_decoder_cls()] # nonlocal
+
+ # Tell the CLI that it's running. We don't start it through the run()
+ # call, but will still want _redraw() to work.
+ self.cli._is_running = True
+
+ def data_received(data):
+ """ TelnetProtocolParser 'data_received' callback """
+ assert isinstance(data, binary_type)
+
+ try:
+ result = stdin_decoder[0].decode(data)
+ inputstream.feed(result)
+ except UnicodeDecodeError:
+ stdin_decoder[0] = stdin_decoder_cls()
+ return ''
+
+ def size_received(rows, columns):
+ """ TelnetProtocolParser 'size_received' callback """
+ self.size = Size(rows=rows, columns=columns)
+ cb.terminal_size_changed()
+
+ self.parser = TelnetProtocolParser(data_received, size_received)
+
+ def feed(self, data):
+ """
+ Handler for incoming data. (Called by TelnetServer.)
+ """
+ assert isinstance(data, binary_type)
+
+ self.parser.feed(data)
+
+ # Render again.
+ self.cli._redraw()
+
+ # When a return value has been set (enter was pressed), handle command.
+ if self.cli.is_returning:
+ try:
+ return_value = self.cli.return_value()
+ except (EOFError, KeyboardInterrupt) as e:
+ # Control-D or Control-C was pressed.
+ logger.info('%s, closing connection.', type(e).__name__)
+ self.close()
+ return
+
+ # Handle CLI command
+ self._handle_command(return_value)
+
+ def _handle_command(self, command):
+ """
+ Handle command. This will run in a separate thread, in order not
+ to block the event loop.
+ """
+ logger.info('Handle command %r', command)
+
+ def in_executor():
+ self.handling_command = True
+ try:
+ if self.callback is not None:
+ self.callback(self, command)
+ finally:
+ self.server.call_from_executor(done)
+
+ def done():
+ self.handling_command = False
+
+ # Reset state and draw again. (If the connection is still open --
+ # the application could have called TelnetConnection.close()
+ if not self.closed:
+ self.cli.reset()
+ self.cli.buffers[DEFAULT_BUFFER].reset()
+ self.cli.renderer.request_absolute_cursor_position()
+ self.vt100_output.flush()
+ self.cli._redraw()
+
+ self.server.run_in_executor(in_executor)
+
+ def erase_screen(self):
+ """
+ Erase output screen.
+ """
+ self.vt100_output.erase_screen()
+ self.vt100_output.cursor_goto(0, 0)
+ self.vt100_output.flush()
+
+ def send(self, data):
+ """
+ Send text to the client.
+ """
+ assert isinstance(data, text_type)
+
+ # When data is send back to the client, we should replace the line
+ # endings. (We didn't allocate a real pseudo terminal, and the telnet
+ # connection is raw, so we are responsible for inserting \r.)
+ self.stdout.write(data.replace('\n', '\r\n'))
+ self.stdout.flush()
+
+ def close(self):
+ """
+ Close the connection.
+ """
+ self.application.client_leaving(self)
+
+ self.conn.close()
+ self.closed = True
+
+
+class _TelnetEventLoopInterface(EventLoop):
+ """
+ Eventloop object to be assigned to `CommandLineInterface`.
+ """
+ def __init__(self, server):
+ self._server = server
+
+ def close(self):
+ " Ignore. "
+
+ def stop(self):
+ " Ignore. "
+
+ def run_in_executor(self, callback):
+ self._server.run_in_executor(callback)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ self._server.call_from_executor(callback)
+
+ def add_reader(self, fd, callback):
+ raise NotImplementedError
+
+ def remove_reader(self, fd):
+ raise NotImplementedError
+
+
+class TelnetServer(object):
+ """
+ Telnet server implementation.
+ """
+ def __init__(self, host='127.0.0.1', port=23, application=None, encoding='utf-8'):
+ assert isinstance(host, text_type)
+ assert isinstance(port, int)
+ assert isinstance(application, TelnetApplication)
+ assert isinstance(encoding, text_type)
+
+ self.host = host
+ self.port = port
+ self.application = application
+ self.encoding = encoding
+
+ self.connections = set()
+
+ self._calls_from_executor = []
+
+ # Create a pipe for inter thread communication.
+ self._schedule_pipe = os.pipe()
+ fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
+
+ @classmethod
+ def create_socket(cls, host, port):
+ # Create and bind socket
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ s.bind((host, port))
+
+ s.listen(4)
+ return s
+
+ def run_in_executor(self, callback):
+ threading.Thread(target=callback).start()
+
+ def call_from_executor(self, callback):
+ self._calls_from_executor.append(callback)
+
+ if self._schedule_pipe:
+ os.write(self._schedule_pipe[1], b'x')
+
+ def _process_callbacks(self):
+ """
+ Process callbacks from `call_from_executor` in eventloop.
+ """
+ # Flush all the pipe content.
+ os.read(self._schedule_pipe[0], 1024)
+
+ # Process calls from executor.
+ calls_from_executor, self._calls_from_executor = self._calls_from_executor, []
+ for c in calls_from_executor:
+ c()
+
+ def run(self):
+ """
+ Run the eventloop for the telnet server.
+ """
+ listen_socket = self.create_socket(self.host, self.port)
+ logger.info('Listening for telnet connections on %s port %r', self.host, self.port)
+
+ try:
+ while True:
+ # Removed closed connections.
+ self.connections = set([c for c in self.connections if not c.closed])
+
+ # Ignore connections handling commands.
+ connections = set([c for c in self.connections if not c.handling_command])
+
+ # Wait for next event.
+ read_list = (
+ [listen_socket, self._schedule_pipe[0]] +
+ [c.conn for c in connections])
+
+ read, _, _ = select.select(read_list, [], [])
+
+ for s in read:
+ # When the socket itself is ready, accept a new connection.
+ if s == listen_socket:
+ self._accept(listen_socket)
+
+ # If we receive something on our "call_from_executor" pipe, process
+ # these callbacks in a thread safe way.
+ elif s == self._schedule_pipe[0]:
+ self._process_callbacks()
+
+ # Handle incoming data on socket.
+ else:
+ self._handle_incoming_data(s)
+ finally:
+ listen_socket.close()
+
+ def _accept(self, listen_socket):
+ """
+ Accept new incoming connection.
+ """
+ conn, addr = listen_socket.accept()
+ connection = TelnetConnection(conn, addr, self.application, self, encoding=self.encoding)
+ self.connections.add(connection)
+
+ logger.info('New connection %r %r', *addr)
+
+ def _handle_incoming_data(self, conn):
+ """
+ Handle incoming data on socket.
+ """
+ connection = [c for c in self.connections if c.conn == conn][0]
+ data = conn.recv(1024)
+ if data:
+ connection.feed(data)
+ else:
+ self.connections.remove(connection)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py
index 3a71e98c8bf..16c1539c528 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/contrib/validators/base.py
@@ -1,34 +1,34 @@
-from __future__ import unicode_literals
-from prompt_toolkit.validation import Validator, ValidationError
-from six import string_types
-
-
-class SentenceValidator(Validator):
- """
- Validate input only when it appears in this list of sentences.
-
- :param sentences: List of sentences.
- :param ignore_case: If True, case-insensitive comparisons.
- """
- def __init__(self, sentences, ignore_case=False, error_message='Invalid input', move_cursor_to_end=False):
- assert all(isinstance(s, string_types) for s in sentences)
- assert isinstance(ignore_case, bool)
- assert isinstance(error_message, string_types)
-
- self.sentences = list(sentences)
- self.ignore_case = ignore_case
- self.error_message = error_message
- self.move_cursor_to_end = move_cursor_to_end
-
- if ignore_case:
+from __future__ import unicode_literals
+from prompt_toolkit.validation import Validator, ValidationError
+from six import string_types
+
+
+class SentenceValidator(Validator):
+ """
+ Validate input only when it appears in this list of sentences.
+
+ :param sentences: List of sentences.
+ :param ignore_case: If True, case-insensitive comparisons.
+ """
+ def __init__(self, sentences, ignore_case=False, error_message='Invalid input', move_cursor_to_end=False):
+ assert all(isinstance(s, string_types) for s in sentences)
+ assert isinstance(ignore_case, bool)
+ assert isinstance(error_message, string_types)
+
+ self.sentences = list(sentences)
+ self.ignore_case = ignore_case
+ self.error_message = error_message
+ self.move_cursor_to_end = move_cursor_to_end
+
+ if ignore_case:
self.sentences = set([s.lower() for s in self.sentences])
-
- def validate(self, document):
- if document.text not in self.sentences:
- if self.move_cursor_to_end:
- index = len(document.text)
- else:
- index = 0
-
+
+ def validate(self, document):
+ if document.text not in self.sentences:
+ if self.move_cursor_to_end:
+ index = len(document.text)
+ else:
+ index = 0
+
raise ValidationError(cursor_position=index,
message=self.error_message)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py
index 68d6829bad3..25d817ddd0d 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/document.py
@@ -1,41 +1,41 @@
-"""
+"""
The `Document` that implements all the text operations/querying.
-"""
-from __future__ import unicode_literals
-
+"""
+from __future__ import unicode_literals
+
import bisect
-import re
-import six
-import string
+import re
+import six
+import string
import weakref
from six.moves import range, map
-
+
from .selection import SelectionType, SelectionState, PasteMode
-from .clipboard import ClipboardData
-
-__all__ = ('Document',)
-
-
-# Regex for finding "words" in documents. (We consider a group of alnum
-# characters a word, but also a group of special characters a word, as long as
-# it doesn't contain a space.)
-# (This is a 'word' in Vi.)
-_FIND_WORD_RE = re.compile(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')
-_FIND_CURRENT_WORD_RE = re.compile(r'^([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')
-_FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^(([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)\s*)')
-
-# Regex for finding "WORDS" in documents.
-# (This is a 'WORD in Vi.)
-_FIND_BIG_WORD_RE = re.compile(r'([^\s]+)')
-_FIND_CURRENT_BIG_WORD_RE = re.compile(r'^([^\s]+)')
-_FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^([^\s]+\s*)')
-
+from .clipboard import ClipboardData
+
+__all__ = ('Document',)
+
+
+# Regex for finding "words" in documents. (We consider a group of alnum
+# characters a word, but also a group of special characters a word, as long as
+# it doesn't contain a space.)
+# (This is a 'word' in Vi.)
+_FIND_WORD_RE = re.compile(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')
+_FIND_CURRENT_WORD_RE = re.compile(r'^([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')
+_FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^(([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)\s*)')
+
+# Regex for finding "WORDS" in documents.
+# (This is a 'WORD in Vi.)
+_FIND_BIG_WORD_RE = re.compile(r'([^\s]+)')
+_FIND_CURRENT_BIG_WORD_RE = re.compile(r'^([^\s]+)')
+_FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE = re.compile(r'^([^\s]+\s*)')
+
# Share the Document._cache between all Document instances.
# (Document instances are considered immutable. That means that if another
# `Document` is constructed with the same text, it should have the same
# `_DocumentCache`.)
_text_to_document_cache = weakref.WeakValueDictionary() # Maps document.text to DocumentCache instance.
-
+
class _ImmutableLineList(list):
"""
@@ -65,42 +65,42 @@ class _DocumentCache(object):
self.line_indexes = None
-class Document(object):
- """
- This is a immutable class around the text and cursor position, and contains
- methods for querying this data, e.g. to give the text before the cursor.
-
- This class is usually instantiated by a :class:`~prompt_toolkit.buffer.Buffer`
- object, and accessed as the `document` property of that class.
-
- :param text: string
- :param cursor_position: int
- :param selection: :class:`.SelectionState`
- """
+class Document(object):
+ """
+ This is a immutable class around the text and cursor position, and contains
+ methods for querying this data, e.g. to give the text before the cursor.
+
+ This class is usually instantiated by a :class:`~prompt_toolkit.buffer.Buffer`
+ object, and accessed as the `document` property of that class.
+
+ :param text: string
+ :param cursor_position: int
+ :param selection: :class:`.SelectionState`
+ """
__slots__ = ('_text', '_cursor_position', '_selection', '_cache')
-
- def __init__(self, text='', cursor_position=None, selection=None):
- assert isinstance(text, six.text_type), 'Got %r' % text
- assert selection is None or isinstance(selection, SelectionState)
-
- # Check cursor position. It can also be right after the end. (Where we
- # insert text.)
- assert cursor_position is None or cursor_position <= len(text), AssertionError(
- 'cursor_position=%r, len_text=%r' % (cursor_position, len(text)))
-
- # By default, if no cursor position was given, make sure to put the
- # cursor position is at the end of the document. This is what makes
- # sense in most places.
- if cursor_position is None:
- cursor_position = len(text)
-
+
+ def __init__(self, text='', cursor_position=None, selection=None):
+ assert isinstance(text, six.text_type), 'Got %r' % text
+ assert selection is None or isinstance(selection, SelectionState)
+
+ # Check cursor position. It can also be right after the end. (Where we
+ # insert text.)
+ assert cursor_position is None or cursor_position <= len(text), AssertionError(
+ 'cursor_position=%r, len_text=%r' % (cursor_position, len(text)))
+
+ # By default, if no cursor position was given, make sure to put the
+ # cursor position is at the end of the document. This is what makes
+ # sense in most places.
+ if cursor_position is None:
+ cursor_position = len(text)
+
# Keep these attributes private. A `Document` really has to be
# considered to be immutable, because otherwise the caching will break
# things. Because of that, we wrap these into read-only properties.
self._text = text
self._cursor_position = cursor_position
self._selection = selection
-
+
# Cache for lines/indexes. (Shared with other Document instances that
# contain the same text.
try:
@@ -115,10 +115,10 @@ class Document(object):
# self._cache = _text_to_document_cache.setdefault(self.text, _DocumentCache())
# assert self._cache
- def __repr__(self):
- return '%s(%r, %r)' % (self.__class__.__name__, self.text, self.cursor_position)
-
- @property
+ def __repr__(self):
+ return '%s(%r, %r)' % (self.__class__.__name__, self.text, self.cursor_position)
+
+ @property
def text(self):
" The document text. "
return self._text
@@ -134,47 +134,47 @@ class Document(object):
return self._selection
@property
- def current_char(self):
- """ Return character under cursor or an empty string. """
- return self._get_char_relative_to_cursor(0) or ''
-
- @property
- def char_before_cursor(self):
- """ Return character before the cursor or an empty string. """
- return self._get_char_relative_to_cursor(-1) or ''
-
- @property
- def text_before_cursor(self):
- return self.text[:self.cursor_position:]
-
- @property
- def text_after_cursor(self):
- return self.text[self.cursor_position:]
-
- @property
- def current_line_before_cursor(self):
- """ Text from the start of the line until the cursor. """
+ def current_char(self):
+ """ Return character under cursor or an empty string. """
+ return self._get_char_relative_to_cursor(0) or ''
+
+ @property
+ def char_before_cursor(self):
+ """ Return character before the cursor or an empty string. """
+ return self._get_char_relative_to_cursor(-1) or ''
+
+ @property
+ def text_before_cursor(self):
+ return self.text[:self.cursor_position:]
+
+ @property
+ def text_after_cursor(self):
+ return self.text[self.cursor_position:]
+
+ @property
+ def current_line_before_cursor(self):
+ """ Text from the start of the line until the cursor. """
_, _, text = self.text_before_cursor.rpartition('\n')
return text
-
- @property
- def current_line_after_cursor(self):
- """ Text from the cursor until the end of the line. """
+
+ @property
+ def current_line_after_cursor(self):
+ """ Text from the cursor until the end of the line. """
text, _, _ = self.text_after_cursor.partition('\n')
return text
-
- @property
- def lines(self):
+
+ @property
+ def lines(self):
"""
Array of all the lines.
"""
- # Cache, because this one is reused very often.
+ # Cache, because this one is reused very often.
if self._cache.lines is None:
self._cache.lines = _ImmutableLineList(self.text.split('\n'))
-
+
return self._cache.lines
-
- @property
+
+ @property
def _line_start_indexes(self):
"""
Array pointing to the start indexes of all the lines.
@@ -203,75 +203,75 @@ class Document(object):
return self._cache.line_indexes
@property
- def lines_from_current(self):
- """
- Array of the lines starting from the current line, until the last line.
- """
- return self.lines[self.cursor_position_row:]
-
- @property
- def line_count(self):
- r""" Return the number of lines in this document. If the document ends
- with a trailing \n, that counts as the beginning of a new line. """
- return len(self.lines)
-
- @property
- def current_line(self):
- """ Return the text on the line where the cursor is. (when the input
- consists of just one line, it equals `text`. """
- return self.current_line_before_cursor + self.current_line_after_cursor
-
- @property
- def leading_whitespace_in_current_line(self):
- """ The leading whitespace in the left margin of the current line. """
- current_line = self.current_line
- length = len(current_line) - len(current_line.lstrip())
- return current_line[:length]
-
- def _get_char_relative_to_cursor(self, offset=0):
- """
- Return character relative to cursor position, or empty string
- """
- try:
- return self.text[self.cursor_position + offset]
- except IndexError:
- return ''
-
- @property
- def on_first_line(self):
- """
- True when we are at the first line.
- """
- return self.cursor_position_row == 0
-
- @property
- def on_last_line(self):
- """
- True when we are at the last line.
- """
- return self.cursor_position_row == self.line_count - 1
-
- @property
- def cursor_position_row(self):
- """
- Current row. (0-based.)
- """
+ def lines_from_current(self):
+ """
+ Array of the lines starting from the current line, until the last line.
+ """
+ return self.lines[self.cursor_position_row:]
+
+ @property
+ def line_count(self):
+ r""" Return the number of lines in this document. If the document ends
+ with a trailing \n, that counts as the beginning of a new line. """
+ return len(self.lines)
+
+ @property
+ def current_line(self):
+ """ Return the text on the line where the cursor is. (when the input
+ consists of just one line, it equals `text`. """
+ return self.current_line_before_cursor + self.current_line_after_cursor
+
+ @property
+ def leading_whitespace_in_current_line(self):
+ """ The leading whitespace in the left margin of the current line. """
+ current_line = self.current_line
+ length = len(current_line) - len(current_line.lstrip())
+ return current_line[:length]
+
+ def _get_char_relative_to_cursor(self, offset=0):
+ """
+ Return character relative to cursor position, or empty string
+ """
+ try:
+ return self.text[self.cursor_position + offset]
+ except IndexError:
+ return ''
+
+ @property
+ def on_first_line(self):
+ """
+ True when we are at the first line.
+ """
+ return self.cursor_position_row == 0
+
+ @property
+ def on_last_line(self):
+ """
+ True when we are at the last line.
+ """
+ return self.cursor_position_row == self.line_count - 1
+
+ @property
+ def cursor_position_row(self):
+ """
+ Current row. (0-based.)
+ """
row, _ = self._find_line_start_index(self.cursor_position)
return row
-
- @property
- def cursor_position_col(self):
- """
- Current column. (0-based.)
- """
+
+ @property
+ def cursor_position_col(self):
+ """
+ Current column. (0-based.)
+ """
# (Don't use self.text_before_cursor to calculate this. Creating
# substrings and doing rsplit is too expensive for getting the cursor
# position.)
_, line_start_index = self._find_line_start_index(self.cursor_position)
return self.cursor_position - line_start_index
-
+
def _find_line_start_index(self, index):
- """
+ """
For the index of a character at a certain line, calculate the index of
the first character on that line.
@@ -284,23 +284,23 @@ class Document(object):
def translate_index_to_position(self, index):
"""
- Given an index for the text, return the corresponding (row, col) tuple.
- (0-based. Returns (0, 0) for index=0.)
- """
+ Given an index for the text, return the corresponding (row, col) tuple.
+ (0-based. Returns (0, 0) for index=0.)
+ """
# Find start of this line.
row, row_index = self._find_line_start_index(index)
col = index - row_index
-
- return row, col
-
- def translate_row_col_to_index(self, row, col):
- """
- Given a (row, col) tuple, return the corresponding index.
- (Row and col params are 0-based.)
+ return row, col
+
+
+ def translate_row_col_to_index(self, row, col):
+ """
+ Given a (row, col) tuple, return the corresponding index.
+ (Row and col params are 0-based.)
Negative row/col values are turned into zero.
- """
+ """
try:
result = self._line_start_indexes[row]
line = self.lines[row]
@@ -311,239 +311,239 @@ class Document(object):
else:
result = self._line_start_indexes[-1]
line = self.lines[-1]
-
+
result += max(0, min(col, len(line)))
- # Keep in range. (len(self.text) is included, because the cursor can be
- # right after the end of the text as well.)
- result = max(0, min(result, len(self.text)))
- return result
-
- @property
- def is_cursor_at_the_end(self):
- """ True when the cursor is at the end of the text. """
- return self.cursor_position == len(self.text)
-
- @property
- def is_cursor_at_the_end_of_line(self):
- """ True when the cursor is at the end of this line. """
+ # Keep in range. (len(self.text) is included, because the cursor can be
+ # right after the end of the text as well.)
+ result = max(0, min(result, len(self.text)))
+ return result
+
+ @property
+ def is_cursor_at_the_end(self):
+ """ True when the cursor is at the end of the text. """
+ return self.cursor_position == len(self.text)
+
+ @property
+ def is_cursor_at_the_end_of_line(self):
+ """ True when the cursor is at the end of this line. """
return self.current_char in ('\n', '')
-
- def has_match_at_current_position(self, sub):
- """
- `True` when this substring is found at the cursor position.
- """
+
+ def has_match_at_current_position(self, sub):
+ """
+ `True` when this substring is found at the cursor position.
+ """
return self.text.find(sub, self.cursor_position) == self.cursor_position
-
- def find(self, sub, in_current_line=False, include_current_position=False,
+
+ def find(self, sub, in_current_line=False, include_current_position=False,
ignore_case=False, count=1):
- """
- Find `text` after the cursor, return position relative to the cursor
- position. Return `None` if nothing was found.
-
- :param count: Find the n-th occurance.
- """
- assert isinstance(ignore_case, bool)
-
- if in_current_line:
- text = self.current_line_after_cursor
- else:
- text = self.text_after_cursor
-
- if not include_current_position:
- if len(text) == 0:
- return # (Otherwise, we always get a match for the empty string.)
- else:
- text = text[1:]
-
- flags = re.IGNORECASE if ignore_case else 0
- iterator = re.finditer(re.escape(sub), text, flags)
-
- try:
- for i, match in enumerate(iterator):
- if i + 1 == count:
- if include_current_position:
- return match.start(0)
- else:
- return match.start(0) + 1
- except StopIteration:
- pass
-
- def find_all(self, sub, ignore_case=False):
- """
- Find all occurances of the substring. Return a list of absolute
- positions in the document.
- """
- flags = re.IGNORECASE if ignore_case else 0
- return [a.start() for a in re.finditer(re.escape(sub), self.text, flags)]
-
- def find_backwards(self, sub, in_current_line=False, ignore_case=False, count=1):
- """
- Find `text` before the cursor, return position relative to the cursor
- position. Return `None` if nothing was found.
-
- :param count: Find the n-th occurance.
- """
- if in_current_line:
- before_cursor = self.current_line_before_cursor[::-1]
- else:
- before_cursor = self.text_before_cursor[::-1]
-
- flags = re.IGNORECASE if ignore_case else 0
- iterator = re.finditer(re.escape(sub[::-1]), before_cursor, flags)
-
- try:
- for i, match in enumerate(iterator):
- if i + 1 == count:
- return - match.start(0) - len(sub)
- except StopIteration:
- pass
-
- def get_word_before_cursor(self, WORD=False):
- """
- Give the word before the cursor.
- If we have whitespace before the cursor this returns an empty string.
- """
- if self.text_before_cursor[-1:].isspace():
- return ''
- else:
- return self.text_before_cursor[self.find_start_of_previous_word(WORD=WORD):]
-
- def find_start_of_previous_word(self, count=1, WORD=False):
- """
- Return an index relative to the cursor position pointing to the start
- of the previous word. Return `None` if nothing was found.
- """
- # Reverse the text before the cursor, in order to do an efficient
- # backwards search.
- text_before_cursor = self.text_before_cursor[::-1]
-
- regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
- iterator = regex.finditer(text_before_cursor)
-
- try:
- for i, match in enumerate(iterator):
- if i + 1 == count:
- return - match.end(1)
- except StopIteration:
- pass
-
- def find_boundaries_of_current_word(self, WORD=False, include_leading_whitespace=False,
- include_trailing_whitespace=False):
- """
- Return the relative boundaries (startpos, endpos) of the current word under the
- cursor. (This is at the current line, because line boundaries obviously
- don't belong to any word.)
- If not on a word, this returns (0,0)
- """
- text_before_cursor = self.current_line_before_cursor[::-1]
- text_after_cursor = self.current_line_after_cursor
-
- def get_regex(include_whitespace):
- return {
- (False, False): _FIND_CURRENT_WORD_RE,
- (False, True): _FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE,
- (True, False): _FIND_CURRENT_BIG_WORD_RE,
- (True, True): _FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE,
- }[(WORD, include_whitespace)]
-
- match_before = get_regex(include_leading_whitespace).search(text_before_cursor)
- match_after = get_regex(include_trailing_whitespace).search(text_after_cursor)
-
- # When there is a match before and after, and we're not looking for
- # WORDs, make sure that both the part before and after the cursor are
- # either in the [a-zA-Z_] alphabet or not. Otherwise, drop the part
- # before the cursor.
- if not WORD and match_before and match_after:
- c1 = self.text[self.cursor_position - 1]
- c2 = self.text[self.cursor_position]
- alphabet = string.ascii_letters + '0123456789_'
-
- if (c1 in alphabet) != (c2 in alphabet):
- match_before = None
-
- return (
- - match_before.end(1) if match_before else 0,
- match_after.end(1) if match_after else 0
- )
-
- def get_word_under_cursor(self, WORD=False):
- """
- Return the word, currently below the cursor.
- This returns an empty string when the cursor is on a whitespace region.
- """
- start, end = self.find_boundaries_of_current_word(WORD=WORD)
- return self.text[self.cursor_position + start: self.cursor_position + end]
-
- def find_next_word_beginning(self, count=1, WORD=False):
- """
- Return an index relative to the cursor position pointing to the start
- of the next word. Return `None` if nothing was found.
- """
+ """
+ Find `text` after the cursor, return position relative to the cursor
+ position. Return `None` if nothing was found.
+
+ :param count: Find the n-th occurance.
+ """
+ assert isinstance(ignore_case, bool)
+
+ if in_current_line:
+ text = self.current_line_after_cursor
+ else:
+ text = self.text_after_cursor
+
+ if not include_current_position:
+ if len(text) == 0:
+ return # (Otherwise, we always get a match for the empty string.)
+ else:
+ text = text[1:]
+
+ flags = re.IGNORECASE if ignore_case else 0
+ iterator = re.finditer(re.escape(sub), text, flags)
+
+ try:
+ for i, match in enumerate(iterator):
+ if i + 1 == count:
+ if include_current_position:
+ return match.start(0)
+ else:
+ return match.start(0) + 1
+ except StopIteration:
+ pass
+
+ def find_all(self, sub, ignore_case=False):
+ """
+ Find all occurances of the substring. Return a list of absolute
+ positions in the document.
+ """
+ flags = re.IGNORECASE if ignore_case else 0
+ return [a.start() for a in re.finditer(re.escape(sub), self.text, flags)]
+
+ def find_backwards(self, sub, in_current_line=False, ignore_case=False, count=1):
+ """
+ Find `text` before the cursor, return position relative to the cursor
+ position. Return `None` if nothing was found.
+
+ :param count: Find the n-th occurance.
+ """
+ if in_current_line:
+ before_cursor = self.current_line_before_cursor[::-1]
+ else:
+ before_cursor = self.text_before_cursor[::-1]
+
+ flags = re.IGNORECASE if ignore_case else 0
+ iterator = re.finditer(re.escape(sub[::-1]), before_cursor, flags)
+
+ try:
+ for i, match in enumerate(iterator):
+ if i + 1 == count:
+ return - match.start(0) - len(sub)
+ except StopIteration:
+ pass
+
+ def get_word_before_cursor(self, WORD=False):
+ """
+ Give the word before the cursor.
+ If we have whitespace before the cursor this returns an empty string.
+ """
+ if self.text_before_cursor[-1:].isspace():
+ return ''
+ else:
+ return self.text_before_cursor[self.find_start_of_previous_word(WORD=WORD):]
+
+ def find_start_of_previous_word(self, count=1, WORD=False):
+ """
+ Return an index relative to the cursor position pointing to the start
+ of the previous word. Return `None` if nothing was found.
+ """
+ # Reverse the text before the cursor, in order to do an efficient
+ # backwards search.
+ text_before_cursor = self.text_before_cursor[::-1]
+
+ regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
+ iterator = regex.finditer(text_before_cursor)
+
+ try:
+ for i, match in enumerate(iterator):
+ if i + 1 == count:
+ return - match.end(1)
+ except StopIteration:
+ pass
+
+ def find_boundaries_of_current_word(self, WORD=False, include_leading_whitespace=False,
+ include_trailing_whitespace=False):
+ """
+ Return the relative boundaries (startpos, endpos) of the current word under the
+ cursor. (This is at the current line, because line boundaries obviously
+ don't belong to any word.)
+ If not on a word, this returns (0,0)
+ """
+ text_before_cursor = self.current_line_before_cursor[::-1]
+ text_after_cursor = self.current_line_after_cursor
+
+ def get_regex(include_whitespace):
+ return {
+ (False, False): _FIND_CURRENT_WORD_RE,
+ (False, True): _FIND_CURRENT_WORD_INCLUDE_TRAILING_WHITESPACE_RE,
+ (True, False): _FIND_CURRENT_BIG_WORD_RE,
+ (True, True): _FIND_CURRENT_BIG_WORD_INCLUDE_TRAILING_WHITESPACE_RE,
+ }[(WORD, include_whitespace)]
+
+ match_before = get_regex(include_leading_whitespace).search(text_before_cursor)
+ match_after = get_regex(include_trailing_whitespace).search(text_after_cursor)
+
+ # When there is a match before and after, and we're not looking for
+ # WORDs, make sure that both the part before and after the cursor are
+ # either in the [a-zA-Z_] alphabet or not. Otherwise, drop the part
+ # before the cursor.
+ if not WORD and match_before and match_after:
+ c1 = self.text[self.cursor_position - 1]
+ c2 = self.text[self.cursor_position]
+ alphabet = string.ascii_letters + '0123456789_'
+
+ if (c1 in alphabet) != (c2 in alphabet):
+ match_before = None
+
+ return (
+ - match_before.end(1) if match_before else 0,
+ match_after.end(1) if match_after else 0
+ )
+
+ def get_word_under_cursor(self, WORD=False):
+ """
+ Return the word, currently below the cursor.
+ This returns an empty string when the cursor is on a whitespace region.
+ """
+ start, end = self.find_boundaries_of_current_word(WORD=WORD)
+ return self.text[self.cursor_position + start: self.cursor_position + end]
+
+ def find_next_word_beginning(self, count=1, WORD=False):
+ """
+ Return an index relative to the cursor position pointing to the start
+ of the next word. Return `None` if nothing was found.
+ """
if count < 0:
return self.find_previous_word_beginning(count=-count, WORD=WORD)
- regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
- iterator = regex.finditer(self.text_after_cursor)
-
- try:
- for i, match in enumerate(iterator):
- # Take first match, unless it's the word on which we're right now.
- if i == 0 and match.start(1) == 0:
- count += 1
-
- if i + 1 == count:
- return match.start(1)
- except StopIteration:
- pass
-
- def find_next_word_ending(self, include_current_position=False, count=1, WORD=False):
- """
- Return an index relative to the cursor position pointing to the end
- of the next word. Return `None` if nothing was found.
- """
+ regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
+ iterator = regex.finditer(self.text_after_cursor)
+
+ try:
+ for i, match in enumerate(iterator):
+ # Take first match, unless it's the word on which we're right now.
+ if i == 0 and match.start(1) == 0:
+ count += 1
+
+ if i + 1 == count:
+ return match.start(1)
+ except StopIteration:
+ pass
+
+ def find_next_word_ending(self, include_current_position=False, count=1, WORD=False):
+ """
+ Return an index relative to the cursor position pointing to the end
+ of the next word. Return `None` if nothing was found.
+ """
if count < 0:
return self.find_previous_word_ending(count=-count, WORD=WORD)
- if include_current_position:
- text = self.text_after_cursor
- else:
- text = self.text_after_cursor[1:]
-
- regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
- iterable = regex.finditer(text)
-
- try:
- for i, match in enumerate(iterable):
- if i + 1 == count:
- value = match.end(1)
-
- if include_current_position:
- return value
- else:
- return value + 1
-
- except StopIteration:
- pass
-
- def find_previous_word_beginning(self, count=1, WORD=False):
- """
- Return an index relative to the cursor position pointing to the start
+ if include_current_position:
+ text = self.text_after_cursor
+ else:
+ text = self.text_after_cursor[1:]
+
+ regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
+ iterable = regex.finditer(text)
+
+ try:
+ for i, match in enumerate(iterable):
+ if i + 1 == count:
+ value = match.end(1)
+
+ if include_current_position:
+ return value
+ else:
+ return value + 1
+
+ except StopIteration:
+ pass
+
+ def find_previous_word_beginning(self, count=1, WORD=False):
+ """
+ Return an index relative to the cursor position pointing to the start
of the previous word. Return `None` if nothing was found.
- """
+ """
if count < 0:
return self.find_next_word_beginning(count=-count, WORD=WORD)
- regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
- iterator = regex.finditer(self.text_before_cursor[::-1])
-
- try:
- for i, match in enumerate(iterator):
- if i + 1 == count:
- return - match.end(1)
- except StopIteration:
- pass
-
+ regex = _FIND_BIG_WORD_RE if WORD else _FIND_WORD_RE
+ iterator = regex.finditer(self.text_before_cursor[::-1])
+
+ try:
+ for i, match in enumerate(iterator):
+ if i + 1 == count:
+ return - match.end(1)
+ except StopIteration:
+ pass
+
def find_previous_word_ending(self, count=1, WORD=False):
"""
Return an index relative to the cursor position pointing to the end
@@ -568,93 +568,93 @@ class Document(object):
except StopIteration:
pass
- def find_next_matching_line(self, match_func, count=1):
- """
- Look downwards for empty lines.
- Return the line index, relative to the current line.
- """
- result = None
-
- for index, line in enumerate(self.lines[self.cursor_position_row + 1:]):
- if match_func(line):
- result = 1 + index
- count -= 1
-
- if count == 0:
- break
-
- return result
-
- def find_previous_matching_line(self, match_func, count=1):
- """
- Look upwards for empty lines.
- Return the line index, relative to the current line.
- """
- result = None
-
- for index, line in enumerate(self.lines[:self.cursor_position_row][::-1]):
- if match_func(line):
- result = -1 - index
- count -= 1
-
- if count == 0:
- break
-
- return result
-
- def get_cursor_left_position(self, count=1):
- """
- Relative position for cursor left.
- """
+ def find_next_matching_line(self, match_func, count=1):
+ """
+ Look downwards for empty lines.
+ Return the line index, relative to the current line.
+ """
+ result = None
+
+ for index, line in enumerate(self.lines[self.cursor_position_row + 1:]):
+ if match_func(line):
+ result = 1 + index
+ count -= 1
+
+ if count == 0:
+ break
+
+ return result
+
+ def find_previous_matching_line(self, match_func, count=1):
+ """
+ Look upwards for empty lines.
+ Return the line index, relative to the current line.
+ """
+ result = None
+
+ for index, line in enumerate(self.lines[:self.cursor_position_row][::-1]):
+ if match_func(line):
+ result = -1 - index
+ count -= 1
+
+ if count == 0:
+ break
+
+ return result
+
+ def get_cursor_left_position(self, count=1):
+ """
+ Relative position for cursor left.
+ """
if count < 0:
return self.get_cursor_right_position(-count)
- return - min(self.cursor_position_col, count)
-
- def get_cursor_right_position(self, count=1):
- """
- Relative position for cursor_right.
- """
+ return - min(self.cursor_position_col, count)
+
+ def get_cursor_right_position(self, count=1):
+ """
+ Relative position for cursor_right.
+ """
if count < 0:
return self.get_cursor_left_position(-count)
- return min(count, len(self.current_line_after_cursor))
-
+ return min(count, len(self.current_line_after_cursor))
+
def get_cursor_up_position(self, count=1, preferred_column=None):
- """
- Return the relative cursor position (character index) where we would be if the
- user pressed the arrow-up button.
+ """
+ Return the relative cursor position (character index) where we would be if the
+ user pressed the arrow-up button.
:param preferred_column: When given, go to this column instead of
staying at the current column.
- """
- assert count >= 1
+ """
+ assert count >= 1
column = self.cursor_position_col if preferred_column is None else preferred_column
-
+
return self.translate_row_col_to_index(
max(0, self.cursor_position_row - count), column) - self.cursor_position
-
+
def get_cursor_down_position(self, count=1, preferred_column=None):
"""
Return the relative cursor position (character index) where we would be if the
user pressed the arrow-down button.
-
+
:param preferred_column: When given, go to this column instead of
staying at the current column.
"""
assert count >= 1
column = self.cursor_position_col if preferred_column is None else preferred_column
-
+
return self.translate_row_col_to_index(
self.cursor_position_row + count, column) - self.cursor_position
-
+
def find_enclosing_bracket_right(self, left_ch, right_ch, end_pos=None):
"""
Find the right bracket enclosing current position. Return the relative
position to the cursor position.
-
+
When `end_pos` is given, don't look past the position.
- """
+ """
if self.current_char == right_ch:
return 0
@@ -678,137 +678,137 @@ class Document(object):
return i - self.cursor_position
def find_enclosing_bracket_left(self, left_ch, right_ch, start_pos=None):
- """
+ """
Find the left bracket enclosing current position. Return the relative
position to the cursor position.
-
+
When `start_pos` is given, don't look past the position.
"""
if self.current_char == left_ch:
return 0
-
+
if start_pos is None:
start_pos = 0
else:
start_pos = max(0, start_pos)
-
+
stack = 1
-
+
# Look backward.
for i in range(self.cursor_position - 1, start_pos - 1, -1):
c = self.text[i]
-
+
if c == right_ch:
stack += 1
elif c == left_ch:
stack -= 1
-
+
if stack == 0:
return i - self.cursor_position
-
+
def find_matching_bracket_position(self, start_pos=None, end_pos=None):
- """
- Return relative cursor position of matching [, (, { or < bracket.
+ """
+ Return relative cursor position of matching [, (, { or < bracket.
When `start_pos` or `end_pos` are given. Don't look past the positions.
- """
-
+ """
+
# Look for a match.
- for A, B in '()', '[]', '{}', '<>':
- if self.current_char == A:
+ for A, B in '()', '[]', '{}', '<>':
+ if self.current_char == A:
return self.find_enclosing_bracket_right(A, B, end_pos=end_pos) or 0
- elif self.current_char == B:
+ elif self.current_char == B:
return self.find_enclosing_bracket_left(A, B, start_pos=start_pos) or 0
-
- return 0
-
- def get_start_of_document_position(self):
- """ Relative position for the start of the document. """
- return - self.cursor_position
-
- def get_end_of_document_position(self):
- """ Relative position for the end of the document. """
- return len(self.text) - self.cursor_position
-
- def get_start_of_line_position(self, after_whitespace=False):
- """ Relative position for the start of this line. """
- if after_whitespace:
- current_line = self.current_line
- return len(current_line) - len(current_line.lstrip()) - self.cursor_position_col
- else:
- return - len(self.current_line_before_cursor)
-
- def get_end_of_line_position(self):
- """ Relative position for the end of this line. """
- return len(self.current_line_after_cursor)
-
- def last_non_blank_of_current_line_position(self):
- """
- Relative position for the last non blank character of this line.
- """
+
+ return 0
+
+ def get_start_of_document_position(self):
+ """ Relative position for the start of the document. """
+ return - self.cursor_position
+
+ def get_end_of_document_position(self):
+ """ Relative position for the end of the document. """
+ return len(self.text) - self.cursor_position
+
+ def get_start_of_line_position(self, after_whitespace=False):
+ """ Relative position for the start of this line. """
+ if after_whitespace:
+ current_line = self.current_line
+ return len(current_line) - len(current_line.lstrip()) - self.cursor_position_col
+ else:
+ return - len(self.current_line_before_cursor)
+
+ def get_end_of_line_position(self):
+ """ Relative position for the end of this line. """
+ return len(self.current_line_after_cursor)
+
+ def last_non_blank_of_current_line_position(self):
+ """
+ Relative position for the last non blank character of this line.
+ """
return len(self.current_line.rstrip()) - self.cursor_position_col - 1
-
- def get_column_cursor_position(self, column):
- """
- Return the relative cursor position for this column at the current
- line. (It will stay between the boundaries of the line in case of a
- larger number.)
- """
- line_length = len(self.current_line)
- current_column = self.cursor_position_col
- column = max(0, min(line_length, column))
-
- return column - current_column
-
+
+ def get_column_cursor_position(self, column):
+ """
+ Return the relative cursor position for this column at the current
+ line. (It will stay between the boundaries of the line in case of a
+ larger number.)
+ """
+ line_length = len(self.current_line)
+ current_column = self.cursor_position_col
+ column = max(0, min(line_length, column))
+
+ return column - current_column
+
def selection_range(self): # XXX: shouldn't this return `None` if there is no selection???
- """
- Return (from, to) tuple of the selection.
- start and end position are included.
-
- This doesn't take the selection type into account. Use
- `selection_ranges` instead.
- """
- if self.selection:
- from_, to = sorted([self.cursor_position, self.selection.original_cursor_position])
- else:
- from_, to = self.cursor_position, self.cursor_position
-
- return from_, to
-
- def selection_ranges(self):
- """
- Return a list of (from, to) tuples for the selection or none if nothing
- was selected. start and end position are always included in the
- selection.
-
- This will yield several (from, to) tuples in case of a BLOCK selection.
- """
- if self.selection:
- from_, to = sorted([self.cursor_position, self.selection.original_cursor_position])
-
- if self.selection.type == SelectionType.BLOCK:
- from_line, from_column = self.translate_index_to_position(from_)
- to_line, to_column = self.translate_index_to_position(to)
- from_column, to_column = sorted([from_column, to_column])
- lines = self.lines
-
- for l in range(from_line, to_line + 1):
- line_length = len(lines[l])
- if from_column < line_length:
- yield (self.translate_row_col_to_index(l, from_column),
- self.translate_row_col_to_index(l, min(line_length - 1, to_column)))
- else:
- # In case of a LINES selection, go to the start/end of the lines.
- if self.selection.type == SelectionType.LINES:
+ """
+ Return (from, to) tuple of the selection.
+ start and end position are included.
+
+ This doesn't take the selection type into account. Use
+ `selection_ranges` instead.
+ """
+ if self.selection:
+ from_, to = sorted([self.cursor_position, self.selection.original_cursor_position])
+ else:
+ from_, to = self.cursor_position, self.cursor_position
+
+ return from_, to
+
+ def selection_ranges(self):
+ """
+ Return a list of (from, to) tuples for the selection or none if nothing
+ was selected. start and end position are always included in the
+ selection.
+
+ This will yield several (from, to) tuples in case of a BLOCK selection.
+ """
+ if self.selection:
+ from_, to = sorted([self.cursor_position, self.selection.original_cursor_position])
+
+ if self.selection.type == SelectionType.BLOCK:
+ from_line, from_column = self.translate_index_to_position(from_)
+ to_line, to_column = self.translate_index_to_position(to)
+ from_column, to_column = sorted([from_column, to_column])
+ lines = self.lines
+
+ for l in range(from_line, to_line + 1):
+ line_length = len(lines[l])
+ if from_column < line_length:
+ yield (self.translate_row_col_to_index(l, from_column),
+ self.translate_row_col_to_index(l, min(line_length - 1, to_column)))
+ else:
+ # In case of a LINES selection, go to the start/end of the lines.
+ if self.selection.type == SelectionType.LINES:
from_ = max(0, self.text.rfind('\n', 0, from_) + 1)
-
+
if self.text.find('\n', to) >= 0:
to = self.text.find('\n', to)
- else:
+ else:
to = len(self.text) - 1
-
- yield from_, to
-
+
+ yield from_, to
+
def selection_range_at_line(self, row):
"""
If the selection spans a portion of the given line, return a (from, to) tuple.
@@ -840,107 +840,107 @@ class Document(object):
return from_column, to_column
- def cut_selection(self):
- """
- Return a (:class:`.Document`, :class:`.ClipboardData`) tuple, where the
- document represents the new document when the selection is cut, and the
- clipboard data, represents whatever has to be put on the clipboard.
- """
- if self.selection:
- cut_parts = []
- remaining_parts = []
- new_cursor_position = self.cursor_position
-
- last_to = 0
- for from_, to in self.selection_ranges():
- if last_to == 0:
- new_cursor_position = from_
-
- remaining_parts.append(self.text[last_to:from_])
- cut_parts.append(self.text[from_:to + 1])
- last_to = to + 1
-
- remaining_parts.append(self.text[last_to:])
-
- cut_text = '\n'.join(cut_parts)
- remaining_text = ''.join(remaining_parts)
-
- # In case of a LINES selection, don't include the trailing newline.
- if self.selection.type == SelectionType.LINES and cut_text.endswith('\n'):
- cut_text = cut_text[:-1]
-
- return (Document(text=remaining_text, cursor_position=new_cursor_position),
- ClipboardData(cut_text, self.selection.type))
- else:
- return self, ClipboardData('')
-
+ def cut_selection(self):
+ """
+ Return a (:class:`.Document`, :class:`.ClipboardData`) tuple, where the
+ document represents the new document when the selection is cut, and the
+ clipboard data, represents whatever has to be put on the clipboard.
+ """
+ if self.selection:
+ cut_parts = []
+ remaining_parts = []
+ new_cursor_position = self.cursor_position
+
+ last_to = 0
+ for from_, to in self.selection_ranges():
+ if last_to == 0:
+ new_cursor_position = from_
+
+ remaining_parts.append(self.text[last_to:from_])
+ cut_parts.append(self.text[from_:to + 1])
+ last_to = to + 1
+
+ remaining_parts.append(self.text[last_to:])
+
+ cut_text = '\n'.join(cut_parts)
+ remaining_text = ''.join(remaining_parts)
+
+ # In case of a LINES selection, don't include the trailing newline.
+ if self.selection.type == SelectionType.LINES and cut_text.endswith('\n'):
+ cut_text = cut_text[:-1]
+
+ return (Document(text=remaining_text, cursor_position=new_cursor_position),
+ ClipboardData(cut_text, self.selection.type))
+ else:
+ return self, ClipboardData('')
+
def paste_clipboard_data(self, data, paste_mode=PasteMode.EMACS, count=1):
- """
- Return a new :class:`.Document` instance which contains the result if
- we would paste this data at the current cursor position.
-
+ """
+ Return a new :class:`.Document` instance which contains the result if
+ we would paste this data at the current cursor position.
+
:param paste_mode: Where to paste. (Before/after/emacs.)
- :param count: When >1, Paste multiple times.
- """
- assert isinstance(data, ClipboardData)
+ :param count: When >1, Paste multiple times.
+ """
+ assert isinstance(data, ClipboardData)
assert paste_mode in (PasteMode.VI_BEFORE, PasteMode.VI_AFTER, PasteMode.EMACS)
-
+
before = (paste_mode == PasteMode.VI_BEFORE)
after = (paste_mode == PasteMode.VI_AFTER)
- if data.type == SelectionType.CHARACTERS:
+ if data.type == SelectionType.CHARACTERS:
if after:
- new_text = (self.text[:self.cursor_position + 1] + data.text * count +
- self.text[self.cursor_position + 1:])
+ new_text = (self.text[:self.cursor_position + 1] + data.text * count +
+ self.text[self.cursor_position + 1:])
else:
new_text = self.text_before_cursor + data.text * count + self.text_after_cursor
-
+
new_cursor_position = self.cursor_position + len(data.text) * count
if before:
new_cursor_position -= 1
- elif data.type == SelectionType.LINES:
- l = self.cursor_position_row
- if before:
- lines = self.lines[:l] + [data.text] * count + self.lines[l:]
- new_text = '\n'.join(lines)
- new_cursor_position = len(''.join(self.lines[:l])) + l
- else:
- lines = self.lines[:l + 1] + [data.text] * count + self.lines[l + 1:]
- new_cursor_position = len(''.join(self.lines[:l + 1])) + l + 1
- new_text = '\n'.join(lines)
-
- elif data.type == SelectionType.BLOCK:
+ elif data.type == SelectionType.LINES:
+ l = self.cursor_position_row
+ if before:
+ lines = self.lines[:l] + [data.text] * count + self.lines[l:]
+ new_text = '\n'.join(lines)
+ new_cursor_position = len(''.join(self.lines[:l])) + l
+ else:
+ lines = self.lines[:l + 1] + [data.text] * count + self.lines[l + 1:]
+ new_cursor_position = len(''.join(self.lines[:l + 1])) + l + 1
+ new_text = '\n'.join(lines)
+
+ elif data.type == SelectionType.BLOCK:
lines = self.lines[:]
- start_line = self.cursor_position_row
- start_column = self.cursor_position_col + (0 if before else 1)
-
- for i, line in enumerate(data.text.split('\n')):
- index = i + start_line
- if index >= len(lines):
- lines.append('')
-
- lines[index] = lines[index].ljust(start_column)
- lines[index] = lines[index][:start_column] + line * count + lines[index][start_column:]
-
- new_text = '\n'.join(lines)
- new_cursor_position = self.cursor_position + (0 if before else 1)
-
- return Document(text=new_text, cursor_position=new_cursor_position)
-
- def empty_line_count_at_the_end(self):
- """
- Return number of empty lines at the end of the document.
- """
- count = 0
- for line in self.lines[::-1]:
- if not line or line.isspace():
- count += 1
- else:
- break
-
- return count
-
+ start_line = self.cursor_position_row
+ start_column = self.cursor_position_col + (0 if before else 1)
+
+ for i, line in enumerate(data.text.split('\n')):
+ index = i + start_line
+ if index >= len(lines):
+ lines.append('')
+
+ lines[index] = lines[index].ljust(start_column)
+ lines[index] = lines[index][:start_column] + line * count + lines[index][start_column:]
+
+ new_text = '\n'.join(lines)
+ new_cursor_position = self.cursor_position + (0 if before else 1)
+
+ return Document(text=new_text, cursor_position=new_cursor_position)
+
+ def empty_line_count_at_the_end(self):
+ """
+ Return number of empty lines at the end of the document.
+ """
+ count = 0
+ for line in self.lines[::-1]:
+ if not line or line.isspace():
+ count += 1
+ else:
+ break
+
+ return count
+
def start_of_paragraph(self, count=1, before=False):
"""
Return the start of the current paragraph. (Relative cursor position.)
@@ -971,31 +971,31 @@ class Document(object):
else:
return len(self.text_after_cursor)
- # Modifiers.
-
- def insert_after(self, text):
- """
- Create a new document, with this text inserted after the buffer.
- It keeps selection ranges and cursor position in sync.
- """
- return Document(
- text=self.text + text,
- cursor_position=self.cursor_position,
- selection=self.selection)
-
- def insert_before(self, text):
- """
- Create a new document, with this text inserted before the buffer.
- It keeps selection ranges and cursor position in sync.
- """
- selection_state = self.selection
-
- if selection_state:
- selection_state = SelectionState(
- original_cursor_position=selection_state.original_cursor_position + len(text),
- type=selection_state.type)
-
- return Document(
- text=text + self.text,
- cursor_position=self.cursor_position + len(text),
- selection=selection_state)
+ # Modifiers.
+
+ def insert_after(self, text):
+ """
+ Create a new document, with this text inserted after the buffer.
+ It keeps selection ranges and cursor position in sync.
+ """
+ return Document(
+ text=self.text + text,
+ cursor_position=self.cursor_position,
+ selection=self.selection)
+
+ def insert_before(self, text):
+ """
+ Create a new document, with this text inserted before the buffer.
+ It keeps selection ranges and cursor position in sync.
+ """
+ selection_state = self.selection
+
+ if selection_state:
+ selection_state = SelectionState(
+ original_cursor_position=selection_state.original_cursor_position + len(text),
+ type=selection_state.type)
+
+ return Document(
+ text=text + self.text,
+ cursor_position=self.cursor_position + len(text),
+ selection=selection_state)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py
index a45060f27a6..6945f44c960 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/enums.py
@@ -1,29 +1,29 @@
-from __future__ import unicode_literals
-
-
-class IncrementalSearchDirection(object):
- FORWARD = 'FORWARD'
- BACKWARD = 'BACKWARD'
-
-
+from __future__ import unicode_literals
+
+
+class IncrementalSearchDirection(object):
+ FORWARD = 'FORWARD'
+ BACKWARD = 'BACKWARD'
+
+
class EditingMode(object):
# The set of key bindings that is active.
VI = 'VI'
EMACS = 'EMACS'
-#: Name of the search buffer.
-SEARCH_BUFFER = 'SEARCH_BUFFER'
-
-#: Name of the default buffer.
-DEFAULT_BUFFER = 'DEFAULT_BUFFER'
-
-#: Name of the system buffer.
-SYSTEM_BUFFER = 'SYSTEM_BUFFER'
-
-# Dummy buffer. This is the buffer returned by
-# `CommandLineInterface.current_buffer` when the top of the `FocusStack` is
-# `None`. This could be the case when there is some widget has the focus and no
-# actual text editing is possible. This buffer should also never be displayed.
-# (It will never contain any actual text.)
-DUMMY_BUFFER = 'DUMMY_BUFFER'
+#: Name of the search buffer.
+SEARCH_BUFFER = 'SEARCH_BUFFER'
+
+#: Name of the default buffer.
+DEFAULT_BUFFER = 'DEFAULT_BUFFER'
+
+#: Name of the system buffer.
+SYSTEM_BUFFER = 'SYSTEM_BUFFER'
+
+# Dummy buffer. This is the buffer returned by
+# `CommandLineInterface.current_buffer` when the top of the `FocusStack` is
+# `None`. This could be the case when there is some widget has the focus and no
+# actual text editing is possible. This buffer should also never be displayed.
+# (It will never contain any actual text.)
+DUMMY_BUFFER = 'DUMMY_BUFFER'
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py
index 1ea41dda60a..ace2b8db497 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_base.py
@@ -1,46 +1,46 @@
-"""
-Eventloop for integration with Python3 asyncio.
-
-Note that we can't use "yield from", because the package should be installable
-under Python 2.6 as well, and it should contain syntactically valid Python 2.6
-code.
-"""
-from __future__ import unicode_literals
-
-__all__ = (
- 'AsyncioTimeout',
-)
-
-
-class AsyncioTimeout(object):
- """
- Call the `timeout` function when the timeout expires.
- Every call of the `reset` method, resets the timeout and starts a new
- timer.
- """
- def __init__(self, timeout, callback, loop):
- self.timeout = timeout
- self.callback = callback
- self.loop = loop
-
- self.counter = 0
- self.running = True
-
- def reset(self):
- """
- Reset the timeout. Starts a new timer.
- """
- self.counter += 1
- local_counter = self.counter
-
- def timer_timeout():
- if self.counter == local_counter and self.running:
- self.callback()
-
- self.loop.call_later(self.timeout, timer_timeout)
-
- def stop(self):
- """
- Ignore timeout. Don't call the callback anymore.
- """
- self.running = False
+"""
+Eventloop for integration with Python3 asyncio.
+
+Note that we can't use "yield from", because the package should be installable
+under Python 2.6 as well, and it should contain syntactically valid Python 2.6
+code.
+"""
+from __future__ import unicode_literals
+
+__all__ = (
+ 'AsyncioTimeout',
+)
+
+
+class AsyncioTimeout(object):
+ """
+ Call the `timeout` function when the timeout expires.
+ Every call of the `reset` method, resets the timeout and starts a new
+ timer.
+ """
+ def __init__(self, timeout, callback, loop):
+ self.timeout = timeout
+ self.callback = callback
+ self.loop = loop
+
+ self.counter = 0
+ self.running = True
+
+ def reset(self):
+ """
+ Reset the timeout. Starts a new timer.
+ """
+ self.counter += 1
+ local_counter = self.counter
+
+ def timer_timeout():
+ if self.counter == local_counter and self.running:
+ self.callback()
+
+ self.loop.call_later(self.timeout, timer_timeout)
+
+ def stop(self):
+ """
+ Ignore timeout. Don't call the callback anymore.
+ """
+ self.running = False
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py
index 26606e84934..426ed96f67d 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_posix.py
@@ -1,113 +1,113 @@
-"""
-Posix asyncio event loop.
-"""
-from __future__ import unicode_literals
-
-from ..terminal.vt100_input import InputStream
-from .asyncio_base import AsyncioTimeout
-from .base import EventLoop, INPUT_TIMEOUT
-from .callbacks import EventLoopCallbacks
-from .posix_utils import PosixStdinReader
-
-import asyncio
-import signal
-
-__all__ = (
- 'PosixAsyncioEventLoop',
-)
-
-
-class PosixAsyncioEventLoop(EventLoop):
- def __init__(self, loop=None):
- self.loop = loop or asyncio.get_event_loop()
- self.closed = False
-
+"""
+Posix asyncio event loop.
+"""
+from __future__ import unicode_literals
+
+from ..terminal.vt100_input import InputStream
+from .asyncio_base import AsyncioTimeout
+from .base import EventLoop, INPUT_TIMEOUT
+from .callbacks import EventLoopCallbacks
+from .posix_utils import PosixStdinReader
+
+import asyncio
+import signal
+
+__all__ = (
+ 'PosixAsyncioEventLoop',
+)
+
+
+class PosixAsyncioEventLoop(EventLoop):
+ def __init__(self, loop=None):
+ self.loop = loop or asyncio.get_event_loop()
+ self.closed = False
+
self._stopped_f = asyncio.Future(loop=self.loop)
-
- @asyncio.coroutine
- def run_as_coroutine(self, stdin, callbacks):
- """
- The input 'event loop'.
- """
- assert isinstance(callbacks, EventLoopCallbacks)
-
- # Create reader class.
- stdin_reader = PosixStdinReader(stdin.fileno())
-
- if self.closed:
- raise Exception('Event loop already closed.')
-
- inputstream = InputStream(callbacks.feed_key)
-
- try:
- # Create a new Future every time.
+
+ @asyncio.coroutine
+ def run_as_coroutine(self, stdin, callbacks):
+ """
+ The input 'event loop'.
+ """
+ assert isinstance(callbacks, EventLoopCallbacks)
+
+ # Create reader class.
+ stdin_reader = PosixStdinReader(stdin.fileno())
+
+ if self.closed:
+ raise Exception('Event loop already closed.')
+
+ inputstream = InputStream(callbacks.feed_key)
+
+ try:
+ # Create a new Future every time.
self._stopped_f = asyncio.Future(loop=self.loop)
-
- # Handle input timouts
- def timeout_handler():
- """
- When no input has been received for INPUT_TIMEOUT seconds,
- flush the input stream and fire the timeout event.
- """
- inputstream.flush()
-
- callbacks.input_timeout()
-
- timeout = AsyncioTimeout(INPUT_TIMEOUT, timeout_handler, self.loop)
-
- # Catch sigwinch
- def received_winch():
- self.call_from_executor(callbacks.terminal_size_changed)
-
- self.loop.add_signal_handler(signal.SIGWINCH, received_winch)
-
- # Read input data.
- def stdin_ready():
- data = stdin_reader.read()
- inputstream.feed(data)
- timeout.reset()
-
+
+ # Handle input timouts
+ def timeout_handler():
+ """
+ When no input has been received for INPUT_TIMEOUT seconds,
+ flush the input stream and fire the timeout event.
+ """
+ inputstream.flush()
+
+ callbacks.input_timeout()
+
+ timeout = AsyncioTimeout(INPUT_TIMEOUT, timeout_handler, self.loop)
+
+ # Catch sigwinch
+ def received_winch():
+ self.call_from_executor(callbacks.terminal_size_changed)
+
+ self.loop.add_signal_handler(signal.SIGWINCH, received_winch)
+
+ # Read input data.
+ def stdin_ready():
+ data = stdin_reader.read()
+ inputstream.feed(data)
+ timeout.reset()
+
# Quit when the input stream was closed.
if stdin_reader.closed:
self.stop()
- self.loop.add_reader(stdin.fileno(), stdin_ready)
-
- # Block this coroutine until stop() has been called.
- for f in self._stopped_f:
- yield f
-
- finally:
- # Clean up.
- self.loop.remove_reader(stdin.fileno())
- self.loop.remove_signal_handler(signal.SIGWINCH)
-
- # Don't trigger any timeout events anymore.
- timeout.stop()
-
- def stop(self):
- # Trigger the 'Stop' future.
- self._stopped_f.set_result(True)
-
- def close(self):
- # Note: we should not close the asyncio loop itself, because that one
- # was not created here.
- self.closed = True
-
- def run_in_executor(self, callback):
- self.loop.run_in_executor(None, callback)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- """
- Call this function in the main event loop.
- Similar to Twisted's ``callFromThread``.
- """
- self.loop.call_soon_threadsafe(callback)
-
- def add_reader(self, fd, callback):
- " Start watching the file descriptor for read availability. "
- self.loop.add_reader(fd, callback)
-
- def remove_reader(self, fd):
- " Stop watching the file descriptor for read availability. "
- self.loop.remove_reader(fd)
+ self.loop.add_reader(stdin.fileno(), stdin_ready)
+
+ # Block this coroutine until stop() has been called.
+ for f in self._stopped_f:
+ yield f
+
+ finally:
+ # Clean up.
+ self.loop.remove_reader(stdin.fileno())
+ self.loop.remove_signal_handler(signal.SIGWINCH)
+
+ # Don't trigger any timeout events anymore.
+ timeout.stop()
+
+ def stop(self):
+ # Trigger the 'Stop' future.
+ self._stopped_f.set_result(True)
+
+ def close(self):
+ # Note: we should not close the asyncio loop itself, because that one
+ # was not created here.
+ self.closed = True
+
+ def run_in_executor(self, callback):
+ self.loop.run_in_executor(None, callback)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ """
+ Call this function in the main event loop.
+ Similar to Twisted's ``callFromThread``.
+ """
+ self.loop.call_soon_threadsafe(callback)
+
+ def add_reader(self, fd, callback):
+ " Start watching the file descriptor for read availability. "
+ self.loop.add_reader(fd, callback)
+
+ def remove_reader(self, fd):
+ " Stop watching the file descriptor for read availability. "
+ self.loop.remove_reader(fd)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py
index adc538afe99..45f5f526798 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/asyncio_win32.py
@@ -1,83 +1,83 @@
-"""
-Win32 asyncio event loop.
-
-Windows notes:
-- Somehow it doesn't seem to work with the 'ProactorEventLoop'.
-"""
-from __future__ import unicode_literals
-
-from .base import EventLoop, INPUT_TIMEOUT
-from ..terminal.win32_input import ConsoleInputReader
-from .callbacks import EventLoopCallbacks
-from .asyncio_base import AsyncioTimeout
-
-import asyncio
-
-__all__ = (
- 'Win32AsyncioEventLoop',
-)
-
-
-class Win32AsyncioEventLoop(EventLoop):
- def __init__(self, loop=None):
- self._console_input_reader = ConsoleInputReader()
- self.running = False
- self.closed = False
- self.loop = loop or asyncio.get_event_loop()
-
- @asyncio.coroutine
- def run_as_coroutine(self, stdin, callbacks):
- """
- The input 'event loop'.
- """
- # Note: We cannot use "yield from", because this package also
- # installs on Python 2.
- assert isinstance(callbacks, EventLoopCallbacks)
-
- if self.closed:
- raise Exception('Event loop already closed.')
-
- timeout = AsyncioTimeout(INPUT_TIMEOUT, callbacks.input_timeout, self.loop)
- self.running = True
-
- try:
- while self.running:
- timeout.reset()
-
- # Get keys
- try:
- g = iter(self.loop.run_in_executor(None, self._console_input_reader.read))
- while True:
- yield next(g)
- except StopIteration as e:
- keys = e.args[0]
-
- # Feed keys to input processor.
- for k in keys:
- callbacks.feed_key(k)
- finally:
- timeout.stop()
-
- def stop(self):
- self.running = False
-
- def close(self):
- # Note: we should not close the asyncio loop itself, because that one
- # was not created here.
- self.closed = True
-
+"""
+Win32 asyncio event loop.
+
+Windows notes:
+- Somehow it doesn't seem to work with the 'ProactorEventLoop'.
+"""
+from __future__ import unicode_literals
+
+from .base import EventLoop, INPUT_TIMEOUT
+from ..terminal.win32_input import ConsoleInputReader
+from .callbacks import EventLoopCallbacks
+from .asyncio_base import AsyncioTimeout
+
+import asyncio
+
+__all__ = (
+ 'Win32AsyncioEventLoop',
+)
+
+
+class Win32AsyncioEventLoop(EventLoop):
+ def __init__(self, loop=None):
+ self._console_input_reader = ConsoleInputReader()
+ self.running = False
+ self.closed = False
+ self.loop = loop or asyncio.get_event_loop()
+
+ @asyncio.coroutine
+ def run_as_coroutine(self, stdin, callbacks):
+ """
+ The input 'event loop'.
+ """
+ # Note: We cannot use "yield from", because this package also
+ # installs on Python 2.
+ assert isinstance(callbacks, EventLoopCallbacks)
+
+ if self.closed:
+ raise Exception('Event loop already closed.')
+
+ timeout = AsyncioTimeout(INPUT_TIMEOUT, callbacks.input_timeout, self.loop)
+ self.running = True
+
+ try:
+ while self.running:
+ timeout.reset()
+
+ # Get keys
+ try:
+ g = iter(self.loop.run_in_executor(None, self._console_input_reader.read))
+ while True:
+ yield next(g)
+ except StopIteration as e:
+ keys = e.args[0]
+
+ # Feed keys to input processor.
+ for k in keys:
+ callbacks.feed_key(k)
+ finally:
+ timeout.stop()
+
+ def stop(self):
+ self.running = False
+
+ def close(self):
+ # Note: we should not close the asyncio loop itself, because that one
+ # was not created here.
+ self.closed = True
+
self._console_input_reader.close()
- def run_in_executor(self, callback):
- self.loop.run_in_executor(None, callback)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- self.loop.call_soon_threadsafe(callback)
-
- def add_reader(self, fd, callback):
- " Start watching the file descriptor for read availability. "
- self.loop.add_reader(fd, callback)
-
- def remove_reader(self, fd):
- " Stop watching the file descriptor for read availability. "
- self.loop.remove_reader(fd)
+ def run_in_executor(self, callback):
+ self.loop.run_in_executor(None, callback)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ self.loop.call_soon_threadsafe(callback)
+
+ def add_reader(self, fd, callback):
+ " Start watching the file descriptor for read availability. "
+ self.loop.add_reader(fd, callback)
+
+ def remove_reader(self, fd):
+ " Stop watching the file descriptor for read availability. "
+ self.loop.remove_reader(fd)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py
index 0be339ca7cd..db86face668 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/base.py
@@ -1,85 +1,85 @@
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-__all__ = (
- 'EventLoop',
- 'INPUT_TIMEOUT',
-)
-
-
-#: When to trigger the `onInputTimeout` event.
-INPUT_TIMEOUT = .5
-
-
-class EventLoop(with_metaclass(ABCMeta, object)):
- """
- Eventloop interface.
- """
- def run(self, stdin, callbacks):
- """
- Run the eventloop until stop() is called. Report all
- input/timeout/terminal-resize events to the callbacks.
-
- :param stdin: :class:`~prompt_toolkit.input.Input` instance.
- :param callbacks: :class:`~prompt_toolkit.eventloop.callbacks.EventLoopCallbacks` instance.
- """
- raise NotImplementedError("This eventloop doesn't implement synchronous 'run()'.")
-
- def run_as_coroutine(self, stdin, callbacks):
- """
- Similar to `run`, but this is a coroutine. (For asyncio integration.)
- """
- raise NotImplementedError("This eventloop doesn't implement 'run_as_coroutine()'.")
-
- @abstractmethod
- def stop(self):
- """
- Stop the `run` call. (Normally called by
- :class:`~prompt_toolkit.interface.CommandLineInterface`, when a result
- is available, or Abort/Quit has been called.)
- """
-
- @abstractmethod
- def close(self):
- """
- Clean up of resources. Eventloop cannot be reused a second time after
- this call.
- """
-
- @abstractmethod
- def add_reader(self, fd, callback):
- """
- Start watching the file descriptor for read availability and then call
- the callback.
- """
-
- @abstractmethod
- def remove_reader(self, fd):
- """
- Stop watching the file descriptor for read availability.
- """
-
- @abstractmethod
- def run_in_executor(self, callback):
- """
- Run a long running function in a background thread. (This is
- recommended for code that could block the event loop.)
- Similar to Twisted's ``deferToThread``.
- """
-
- @abstractmethod
- def call_from_executor(self, callback, _max_postpone_until=None):
- """
- Call this function in the main event loop. Similar to Twisted's
- ``callFromThread``.
-
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+__all__ = (
+ 'EventLoop',
+ 'INPUT_TIMEOUT',
+)
+
+
+#: When to trigger the `onInputTimeout` event.
+INPUT_TIMEOUT = .5
+
+
+class EventLoop(with_metaclass(ABCMeta, object)):
+ """
+ Eventloop interface.
+ """
+ def run(self, stdin, callbacks):
+ """
+ Run the eventloop until stop() is called. Report all
+ input/timeout/terminal-resize events to the callbacks.
+
+ :param stdin: :class:`~prompt_toolkit.input.Input` instance.
+ :param callbacks: :class:`~prompt_toolkit.eventloop.callbacks.EventLoopCallbacks` instance.
+ """
+ raise NotImplementedError("This eventloop doesn't implement synchronous 'run()'.")
+
+ def run_as_coroutine(self, stdin, callbacks):
+ """
+ Similar to `run`, but this is a coroutine. (For asyncio integration.)
+ """
+ raise NotImplementedError("This eventloop doesn't implement 'run_as_coroutine()'.")
+
+ @abstractmethod
+ def stop(self):
+ """
+ Stop the `run` call. (Normally called by
+ :class:`~prompt_toolkit.interface.CommandLineInterface`, when a result
+ is available, or Abort/Quit has been called.)
+ """
+
+ @abstractmethod
+ def close(self):
+ """
+ Clean up of resources. Eventloop cannot be reused a second time after
+ this call.
+ """
+
+ @abstractmethod
+ def add_reader(self, fd, callback):
+ """
+ Start watching the file descriptor for read availability and then call
+ the callback.
+ """
+
+ @abstractmethod
+ def remove_reader(self, fd):
+ """
+ Stop watching the file descriptor for read availability.
+ """
+
+ @abstractmethod
+ def run_in_executor(self, callback):
+ """
+ Run a long running function in a background thread. (This is
+ recommended for code that could block the event loop.)
+ Similar to Twisted's ``deferToThread``.
+ """
+
+ @abstractmethod
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ """
+ Call this function in the main event loop. Similar to Twisted's
+ ``callFromThread``.
+
:param _max_postpone_until: `None` or `time.time` value. For interal
- use. If the eventloop is saturated, consider this task to be low
- priority and postpone maximum until this timestamp. (For instance,
- repaint is done using low priority.)
+ use. If the eventloop is saturated, consider this task to be low
+ priority and postpone maximum until this timestamp. (For instance,
+ repaint is done using low priority.)
Note: In the past, this used to be a datetime.datetime instance,
but apparently, executing `time.time` is more efficient: it
does fewer system calls. (It doesn't read /etc/localtime.)
- """
+ """
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py
index 068d900f62f..04adab6fd49 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/callbacks.py
@@ -1,29 +1,29 @@
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-__all__ = (
- 'EventLoopCallbacks',
-)
-
-
-class EventLoopCallbacks(with_metaclass(ABCMeta, object)):
- """
- This is the glue between the :class:`~prompt_toolkit.eventloop.base.EventLoop`
- and :class:`~prompt_toolkit.interface.CommandLineInterface`.
-
- :meth:`~prompt_toolkit.eventloop.base.EventLoop.run` takes an
- :class:`.EventLoopCallbacks` instance and operates on that one, driving the
- interface.
- """
- @abstractmethod
- def terminal_size_changed(self):
- pass
-
- @abstractmethod
- def input_timeout(self):
- pass
-
- @abstractmethod
- def feed_key(self, key):
- pass
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+__all__ = (
+ 'EventLoopCallbacks',
+)
+
+
+class EventLoopCallbacks(with_metaclass(ABCMeta, object)):
+ """
+ This is the glue between the :class:`~prompt_toolkit.eventloop.base.EventLoop`
+ and :class:`~prompt_toolkit.interface.CommandLineInterface`.
+
+ :meth:`~prompt_toolkit.eventloop.base.EventLoop.run` takes an
+ :class:`.EventLoopCallbacks` instance and operates on that one, driving the
+ interface.
+ """
+ @abstractmethod
+ def terminal_size_changed(self):
+ pass
+
+ @abstractmethod
+ def input_timeout(self):
+ pass
+
+ @abstractmethod
+ def feed_key(self, key):
+ pass
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py
index c49d5876a14..bab1f4c003a 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/inputhook.py
@@ -1,80 +1,80 @@
-"""
-Similar to `PyOS_InputHook` of the Python API. Some eventloops can have an
-inputhook to allow easy integration with other event loops.
-
-When the eventloop of prompt-toolkit is idle, it can call such a hook. This
-hook can call another eventloop that runs for a short while, for instance to
-keep a graphical user interface responsive.
-
-It's the responsibility of this hook to exit when there is input ready.
-There are two ways to detect when input is ready:
-
-- Call the `input_is_ready` method periodically. Quit when this returns `True`.
-
-- Add the `fileno` as a watch to the external eventloop. Quit when file descriptor
- becomes readable. (But don't read from it.)
-
- Note that this is not the same as checking for `sys.stdin.fileno()`. The
- eventloop of prompt-toolkit allows thread-based executors, for example for
- asynchronous autocompletion. When the completion for instance is ready, we
- also want prompt-toolkit to gain control again in order to display that.
-
-An alternative to using input hooks, is to create a custom `EventLoop` class that
-controls everything.
-"""
-from __future__ import unicode_literals
-import os
-import threading
+"""
+Similar to `PyOS_InputHook` of the Python API. Some eventloops can have an
+inputhook to allow easy integration with other event loops.
+
+When the eventloop of prompt-toolkit is idle, it can call such a hook. This
+hook can call another eventloop that runs for a short while, for instance to
+keep a graphical user interface responsive.
+
+It's the responsibility of this hook to exit when there is input ready.
+There are two ways to detect when input is ready:
+
+- Call the `input_is_ready` method periodically. Quit when this returns `True`.
+
+- Add the `fileno` as a watch to the external eventloop. Quit when file descriptor
+ becomes readable. (But don't read from it.)
+
+ Note that this is not the same as checking for `sys.stdin.fileno()`. The
+ eventloop of prompt-toolkit allows thread-based executors, for example for
+ asynchronous autocompletion. When the completion for instance is ready, we
+ also want prompt-toolkit to gain control again in order to display that.
+
+An alternative to using input hooks, is to create a custom `EventLoop` class that
+controls everything.
+"""
+from __future__ import unicode_literals
+import os
+import threading
from prompt_toolkit.utils import is_windows
from .select import select_fds
-
-__all__ = (
- 'InputHookContext',
-)
-
-
-class InputHookContext(object):
- """
- Given as a parameter to the inputhook.
- """
- def __init__(self, inputhook):
- assert callable(inputhook)
-
- self.inputhook = inputhook
- self._input_is_ready = None
-
- self._r, self._w = os.pipe()
-
- def input_is_ready(self):
- """
- Return True when the input is ready.
- """
- return self._input_is_ready(wait=False)
-
- def fileno(self):
- """
- File descriptor that will become ready when the event loop needs to go on.
- """
- return self._r
-
- def call_inputhook(self, input_is_ready_func):
- """
- Call the inputhook. (Called by a prompt-toolkit eventloop.)
- """
- self._input_is_ready = input_is_ready_func
-
- # Start thread that activates this pipe when there is input to process.
- def thread():
- input_is_ready_func(wait=True)
- os.write(self._w, b'x')
-
- threading.Thread(target=thread).start()
-
- # Call inputhook.
- self.inputhook(self)
-
- # Flush the read end of the pipe.
- try:
+
+__all__ = (
+ 'InputHookContext',
+)
+
+
+class InputHookContext(object):
+ """
+ Given as a parameter to the inputhook.
+ """
+ def __init__(self, inputhook):
+ assert callable(inputhook)
+
+ self.inputhook = inputhook
+ self._input_is_ready = None
+
+ self._r, self._w = os.pipe()
+
+ def input_is_ready(self):
+ """
+ Return True when the input is ready.
+ """
+ return self._input_is_ready(wait=False)
+
+ def fileno(self):
+ """
+ File descriptor that will become ready when the event loop needs to go on.
+ """
+ return self._r
+
+ def call_inputhook(self, input_is_ready_func):
+ """
+ Call the inputhook. (Called by a prompt-toolkit eventloop.)
+ """
+ self._input_is_ready = input_is_ready_func
+
+ # Start thread that activates this pipe when there is input to process.
+ def thread():
+ input_is_ready_func(wait=True)
+ os.write(self._w, b'x')
+
+ threading.Thread(target=thread).start()
+
+ # Call inputhook.
+ self.inputhook(self)
+
+ # Flush the read end of the pipe.
+ try:
# Before calling 'os.read', call select.select. This is required
# when the gevent monkey patch has been applied. 'os.read' is never
# monkey patched and won't be cooperative, so that would block all
@@ -88,20 +88,20 @@ class InputHookContext(object):
if not is_windows():
select_fds([self._r], timeout=None)
- os.read(self._r, 1024)
- except OSError:
- # This happens when the window resizes and a SIGWINCH was received.
- # We get 'Error: [Errno 4] Interrupted system call'
- # Just ignore.
- pass
- self._input_is_ready = None
-
- def close(self):
- """
- Clean up resources.
- """
- if self._r:
- os.close(self._r)
- os.close(self._w)
-
- self._r = self._w = None
+ os.read(self._r, 1024)
+ except OSError:
+ # This happens when the window resizes and a SIGWINCH was received.
+ # We get 'Error: [Errno 4] Interrupted system call'
+ # Just ignore.
+ pass
+ self._input_is_ready = None
+
+ def close(self):
+ """
+ Clean up resources.
+ """
+ if self._r:
+ os.close(self._r)
+ os.close(self._w)
+
+ self._r = self._w = None
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
index a2ef2ac3d8f..f631dbd8915 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
@@ -1,244 +1,244 @@
-from __future__ import unicode_literals
-import fcntl
-import os
-import signal
-import threading
+from __future__ import unicode_literals
+import fcntl
+import os
+import signal
+import threading
import time
-
-from prompt_toolkit.terminal.vt100_input import InputStream
-from prompt_toolkit.utils import DummyContext, in_main_thread
-from prompt_toolkit.input import Input
-from .base import EventLoop, INPUT_TIMEOUT
-from .callbacks import EventLoopCallbacks
-from .inputhook import InputHookContext
-from .posix_utils import PosixStdinReader
-from .utils import TimeIt
+
+from prompt_toolkit.terminal.vt100_input import InputStream
+from prompt_toolkit.utils import DummyContext, in_main_thread
+from prompt_toolkit.input import Input
+from .base import EventLoop, INPUT_TIMEOUT
+from .callbacks import EventLoopCallbacks
+from .inputhook import InputHookContext
+from .posix_utils import PosixStdinReader
+from .utils import TimeIt
from .select import AutoSelector, Selector, fd_to_int
-
-__all__ = (
- 'PosixEventLoop',
-)
-
+
+__all__ = (
+ 'PosixEventLoop',
+)
+
_now = time.time
-
-
-class PosixEventLoop(EventLoop):
- """
- Event loop for posix systems (Linux, Mac os X).
- """
+
+
+class PosixEventLoop(EventLoop):
+ """
+ Event loop for posix systems (Linux, Mac os X).
+ """
def __init__(self, inputhook=None, selector=AutoSelector):
- assert inputhook is None or callable(inputhook)
+ assert inputhook is None or callable(inputhook)
assert issubclass(selector, Selector)
-
- self.running = False
- self.closed = False
- self._running = False
- self._callbacks = None
-
- self._calls_from_executor = []
- self._read_fds = {} # Maps fd to handler.
+
+ self.running = False
+ self.closed = False
+ self._running = False
+ self._callbacks = None
+
+ self._calls_from_executor = []
+ self._read_fds = {} # Maps fd to handler.
self.selector = selector()
-
- # Create a pipe for inter thread communication.
- self._schedule_pipe = os.pipe()
- fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
-
- # Create inputhook context.
- self._inputhook_context = InputHookContext(inputhook) if inputhook else None
-
- def run(self, stdin, callbacks):
- """
- The input 'event loop'.
- """
- assert isinstance(stdin, Input)
- assert isinstance(callbacks, EventLoopCallbacks)
- assert not self._running
-
- if self.closed:
- raise Exception('Event loop already closed.')
-
- self._running = True
- self._callbacks = callbacks
-
- inputstream = InputStream(callbacks.feed_key)
- current_timeout = [INPUT_TIMEOUT] # Nonlocal
-
- # Create reader class.
- stdin_reader = PosixStdinReader(stdin.fileno())
-
- # Only attach SIGWINCH signal handler in main thread.
- # (It's not possible to attach signal handlers in other threads. In
- # that case we should rely on a the main thread to call this manually
- # instead.)
- if in_main_thread():
- ctx = call_on_sigwinch(self.received_winch)
- else:
- ctx = DummyContext()
-
- def read_from_stdin():
- " Read user input. "
- # Feed input text.
- data = stdin_reader.read()
- inputstream.feed(data)
-
- # Set timeout again.
- current_timeout[0] = INPUT_TIMEOUT
-
+
+ # Create a pipe for inter thread communication.
+ self._schedule_pipe = os.pipe()
+ fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
+
+ # Create inputhook context.
+ self._inputhook_context = InputHookContext(inputhook) if inputhook else None
+
+ def run(self, stdin, callbacks):
+ """
+ The input 'event loop'.
+ """
+ assert isinstance(stdin, Input)
+ assert isinstance(callbacks, EventLoopCallbacks)
+ assert not self._running
+
+ if self.closed:
+ raise Exception('Event loop already closed.')
+
+ self._running = True
+ self._callbacks = callbacks
+
+ inputstream = InputStream(callbacks.feed_key)
+ current_timeout = [INPUT_TIMEOUT] # Nonlocal
+
+ # Create reader class.
+ stdin_reader = PosixStdinReader(stdin.fileno())
+
+ # Only attach SIGWINCH signal handler in main thread.
+ # (It's not possible to attach signal handlers in other threads. In
+ # that case we should rely on a the main thread to call this manually
+ # instead.)
+ if in_main_thread():
+ ctx = call_on_sigwinch(self.received_winch)
+ else:
+ ctx = DummyContext()
+
+ def read_from_stdin():
+ " Read user input. "
+ # Feed input text.
+ data = stdin_reader.read()
+ inputstream.feed(data)
+
+ # Set timeout again.
+ current_timeout[0] = INPUT_TIMEOUT
+
# Quit when the input stream was closed.
if stdin_reader.closed:
self.stop()
- self.add_reader(stdin, read_from_stdin)
- self.add_reader(self._schedule_pipe[0], None)
-
- with ctx:
- while self._running:
- # Call inputhook.
+ self.add_reader(stdin, read_from_stdin)
+ self.add_reader(self._schedule_pipe[0], None)
+
+ with ctx:
+ while self._running:
+ # Call inputhook.
if self._inputhook_context:
with TimeIt() as inputhook_timer:
- def ready(wait):
- " True when there is input ready. The inputhook should return control. "
- return self._ready_for_reading(current_timeout[0] if wait else 0) != []
- self._inputhook_context.call_inputhook(ready)
+ def ready(wait):
+ " True when there is input ready. The inputhook should return control. "
+ return self._ready_for_reading(current_timeout[0] if wait else 0) != []
+ self._inputhook_context.call_inputhook(ready)
inputhook_duration = inputhook_timer.duration
else:
inputhook_duration = 0
-
- # Calculate remaining timeout. (The inputhook consumed some of the time.)
- if current_timeout[0] is None:
- remaining_timeout = None
- else:
+
+ # Calculate remaining timeout. (The inputhook consumed some of the time.)
+ if current_timeout[0] is None:
+ remaining_timeout = None
+ else:
remaining_timeout = max(0, current_timeout[0] - inputhook_duration)
-
- # Wait until input is ready.
- fds = self._ready_for_reading(remaining_timeout)
-
- # When any of the FDs are ready. Call the appropriate callback.
- if fds:
- # Create lists of high/low priority tasks. The main reason
- # for this is to allow painting the UI to happen as soon as
- # possible, but when there are many events happening, we
- # don't want to call the UI renderer 1000x per second. If
- # the eventloop is completely saturated with many CPU
- # intensive tasks (like processing input/output), we say
- # that drawing the UI can be postponed a little, to make
- # CPU available. This will be a low priority task in that
- # case.
- tasks = []
- low_priority_tasks = []
+
+ # Wait until input is ready.
+ fds = self._ready_for_reading(remaining_timeout)
+
+ # When any of the FDs are ready. Call the appropriate callback.
+ if fds:
+ # Create lists of high/low priority tasks. The main reason
+ # for this is to allow painting the UI to happen as soon as
+ # possible, but when there are many events happening, we
+ # don't want to call the UI renderer 1000x per second. If
+ # the eventloop is completely saturated with many CPU
+ # intensive tasks (like processing input/output), we say
+ # that drawing the UI can be postponed a little, to make
+ # CPU available. This will be a low priority task in that
+ # case.
+ tasks = []
+ low_priority_tasks = []
now = None # Lazy load time. (Fewer system calls.)
-
- for fd in fds:
- # For the 'call_from_executor' fd, put each pending
- # item on either the high or low priority queue.
- if fd == self._schedule_pipe[0]:
- for c, max_postpone_until in self._calls_from_executor:
+
+ for fd in fds:
+ # For the 'call_from_executor' fd, put each pending
+ # item on either the high or low priority queue.
+ if fd == self._schedule_pipe[0]:
+ for c, max_postpone_until in self._calls_from_executor:
if max_postpone_until is None:
# Execute now.
- tasks.append(c)
- else:
+ tasks.append(c)
+ else:
# Execute soon, if `max_postpone_until` is in the future.
now = now or _now()
if max_postpone_until < now:
tasks.append(c)
else:
low_priority_tasks.append((c, max_postpone_until))
- self._calls_from_executor = []
-
- # Flush all the pipe content.
- os.read(self._schedule_pipe[0], 1024)
- else:
- handler = self._read_fds.get(fd)
- if handler:
- tasks.append(handler)
-
- # When there are high priority tasks, run all these.
- # Schedule low priority tasks for the next iteration.
- if tasks:
- for t in tasks:
- t()
-
- # Postpone low priority tasks.
- for t, max_postpone_until in low_priority_tasks:
- self.call_from_executor(t, _max_postpone_until=max_postpone_until)
- else:
- # Currently there are only low priority tasks -> run them right now.
- for t, _ in low_priority_tasks:
- t()
-
- else:
- # Flush all pending keys on a timeout. (This is most
- # important to flush the vt100 'Escape' key early when
- # nothing else follows.)
- inputstream.flush()
-
- # Fire input timeout event.
- callbacks.input_timeout()
- current_timeout[0] = None
-
- self.remove_reader(stdin)
- self.remove_reader(self._schedule_pipe[0])
-
- self._callbacks = None
-
- def _ready_for_reading(self, timeout=None):
- """
- Return the file descriptors that are ready for reading.
- """
+ self._calls_from_executor = []
+
+ # Flush all the pipe content.
+ os.read(self._schedule_pipe[0], 1024)
+ else:
+ handler = self._read_fds.get(fd)
+ if handler:
+ tasks.append(handler)
+
+ # When there are high priority tasks, run all these.
+ # Schedule low priority tasks for the next iteration.
+ if tasks:
+ for t in tasks:
+ t()
+
+ # Postpone low priority tasks.
+ for t, max_postpone_until in low_priority_tasks:
+ self.call_from_executor(t, _max_postpone_until=max_postpone_until)
+ else:
+ # Currently there are only low priority tasks -> run them right now.
+ for t, _ in low_priority_tasks:
+ t()
+
+ else:
+ # Flush all pending keys on a timeout. (This is most
+ # important to flush the vt100 'Escape' key early when
+ # nothing else follows.)
+ inputstream.flush()
+
+ # Fire input timeout event.
+ callbacks.input_timeout()
+ current_timeout[0] = None
+
+ self.remove_reader(stdin)
+ self.remove_reader(self._schedule_pipe[0])
+
+ self._callbacks = None
+
+ def _ready_for_reading(self, timeout=None):
+ """
+ Return the file descriptors that are ready for reading.
+ """
fds = self.selector.select(timeout)
return fds
-
- def received_winch(self):
- """
- Notify the event loop that SIGWINCH has been received
- """
- # Process signal asynchronously, because this handler can write to the
- # output, and doing this inside the signal handler causes easily
- # reentrant calls, giving runtime errors..
-
- # Furthur, this has to be thread safe. When the CommandLineInterface
- # runs not in the main thread, this function still has to be called
- # from the main thread. (The only place where we can install signal
- # handlers.)
- def process_winch():
- if self._callbacks:
- self._callbacks.terminal_size_changed()
-
- self.call_from_executor(process_winch)
-
- def run_in_executor(self, callback):
- """
- Run a long running function in a background thread.
- (This is recommended for code that could block the event loop.)
- Similar to Twisted's ``deferToThread``.
- """
- # Wait until the main thread is idle.
- # We start the thread by using `call_from_executor`. The event loop
- # favours processing input over `calls_from_executor`, so the thread
- # will not start until there is no more input to process and the main
- # thread becomes idle for an instant. This is good, because Python
- # threading favours CPU over I/O -- an autocompletion thread in the
- # background would cause a significantly slow down of the main thread.
- # It is mostly noticable when pasting large portions of text while
- # having real time autocompletion while typing on.
- def start_executor():
- threading.Thread(target=callback).start()
- self.call_from_executor(start_executor)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- """
- Call this function in the main event loop.
- Similar to Twisted's ``callFromThread``.
-
+
+ def received_winch(self):
+ """
+ Notify the event loop that SIGWINCH has been received
+ """
+ # Process signal asynchronously, because this handler can write to the
+ # output, and doing this inside the signal handler causes easily
+ # reentrant calls, giving runtime errors..
+
+ # Furthur, this has to be thread safe. When the CommandLineInterface
+ # runs not in the main thread, this function still has to be called
+ # from the main thread. (The only place where we can install signal
+ # handlers.)
+ def process_winch():
+ if self._callbacks:
+ self._callbacks.terminal_size_changed()
+
+ self.call_from_executor(process_winch)
+
+ def run_in_executor(self, callback):
+ """
+ Run a long running function in a background thread.
+ (This is recommended for code that could block the event loop.)
+ Similar to Twisted's ``deferToThread``.
+ """
+ # Wait until the main thread is idle.
+ # We start the thread by using `call_from_executor`. The event loop
+ # favours processing input over `calls_from_executor`, so the thread
+ # will not start until there is no more input to process and the main
+ # thread becomes idle for an instant. This is good, because Python
+ # threading favours CPU over I/O -- an autocompletion thread in the
+ # background would cause a significantly slow down of the main thread.
+ # It is mostly noticable when pasting large portions of text while
+ # having real time autocompletion while typing on.
+ def start_executor():
+ threading.Thread(target=callback).start()
+ self.call_from_executor(start_executor)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ """
+ Call this function in the main event loop.
+ Similar to Twisted's ``callFromThread``.
+
:param _max_postpone_until: `None` or `time.time` value. For interal
- use. If the eventloop is saturated, consider this task to be low
- priority and postpone maximum until this timestamp. (For instance,
- repaint is done using low priority.)
- """
+ use. If the eventloop is saturated, consider this task to be low
+ priority and postpone maximum until this timestamp. (For instance,
+ repaint is done using low priority.)
+ """
assert _max_postpone_until is None or isinstance(_max_postpone_until, float)
- self._calls_from_executor.append((callback, _max_postpone_until))
-
- if self._schedule_pipe:
+ self._calls_from_executor.append((callback, _max_postpone_until))
+
+ if self._schedule_pipe:
try:
os.write(self._schedule_pipe[1], b'x')
except (AttributeError, IndexError, OSError):
@@ -247,60 +247,60 @@ class PosixEventLoop(EventLoop):
# - We catch `OSError` (actually BrokenPipeError), because the
# main thread could have closed the pipe already.
pass
-
- def stop(self):
- """
- Stop the event loop.
- """
- self._running = False
-
- def close(self):
- self.closed = True
-
- # Close pipes.
- schedule_pipe = self._schedule_pipe
- self._schedule_pipe = None
-
- if schedule_pipe:
- os.close(schedule_pipe[0])
- os.close(schedule_pipe[1])
-
- if self._inputhook_context:
- self._inputhook_context.close()
-
- def add_reader(self, fd, callback):
- " Add read file descriptor to the event loop. "
+
+ def stop(self):
+ """
+ Stop the event loop.
+ """
+ self._running = False
+
+ def close(self):
+ self.closed = True
+
+ # Close pipes.
+ schedule_pipe = self._schedule_pipe
+ self._schedule_pipe = None
+
+ if schedule_pipe:
+ os.close(schedule_pipe[0])
+ os.close(schedule_pipe[1])
+
+ if self._inputhook_context:
+ self._inputhook_context.close()
+
+ def add_reader(self, fd, callback):
+ " Add read file descriptor to the event loop. "
fd = fd_to_int(fd)
- self._read_fds[fd] = callback
+ self._read_fds[fd] = callback
self.selector.register(fd)
-
- def remove_reader(self, fd):
- " Remove read file descriptor from the event loop. "
+
+ def remove_reader(self, fd):
+ " Remove read file descriptor from the event loop. "
fd = fd_to_int(fd)
- if fd in self._read_fds:
- del self._read_fds[fd]
-
+ if fd in self._read_fds:
+ del self._read_fds[fd]
+
self.selector.unregister(fd)
-
-
-class call_on_sigwinch(object):
- """
- Context manager which Installs a SIGWINCH callback.
- (This signal occurs when the terminal size changes.)
- """
- def __init__(self, callback):
- self.callback = callback
- self.previous_callback = None
-
- def __enter__(self):
- self.previous_callback = signal.signal(signal.SIGWINCH, lambda *a: self.callback())
-
- def __exit__(self, *a, **kw):
- if self.previous_callback is None:
- # Normally, `signal.signal` should never return `None`.
- # For some reason it happens here:
- # https://github.com/jonathanslenders/python-prompt-toolkit/pull/174
- signal.signal(signal.SIGWINCH, 0)
- else:
- signal.signal(signal.SIGWINCH, self.previous_callback)
+
+
+class call_on_sigwinch(object):
+ """
+ Context manager which Installs a SIGWINCH callback.
+ (This signal occurs when the terminal size changes.)
+ """
+ def __init__(self, callback):
+ self.callback = callback
+ self.previous_callback = None
+
+ def __enter__(self):
+ self.previous_callback = signal.signal(signal.SIGWINCH, lambda *a: self.callback())
+
+ def __exit__(self, *a, **kw):
+ if self.previous_callback is None:
+ # Normally, `signal.signal` should never return `None`.
+ # For some reason it happens here:
+ # https://github.com/jonathanslenders/python-prompt-toolkit/pull/174
+ signal.signal(signal.SIGWINCH, 0)
+ else:
+ signal.signal(signal.SIGWINCH, self.previous_callback)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py
index af040650f03..320df438ca2 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix_utils.py
@@ -1,18 +1,18 @@
-from __future__ import unicode_literals
-
-from codecs import getincrementaldecoder
-import os
+from __future__ import unicode_literals
+
+from codecs import getincrementaldecoder
+import os
import six
-
-__all__ = (
- 'PosixStdinReader',
-)
-
-
-class PosixStdinReader(object):
- """
- Wrapper around stdin which reads (nonblocking) the next available 1024
- bytes and decodes it.
+
+__all__ = (
+ 'PosixStdinReader',
+)
+
+
+class PosixStdinReader(object):
+ """
+ Wrapper around stdin which reads (nonblocking) the next available 1024
+ bytes and decodes it.
Note that you can't be sure that the input file is closed if the ``read``
function returns an empty string. When ``errors=ignore`` is passed,
@@ -29,54 +29,54 @@ class PosixStdinReader(object):
unrecognised bytes to the key bindings. Some terminals, like lxterminal
and Guake, use the 'Mxx' notation to send mouse events, where each 'x'
can be any possible byte.
- """
+ """
# By default, we want to 'ignore' errors here. The input stream can be full
# of junk. One occurrence of this that I had was when using iTerm2 on OS X,
# with "Option as Meta" checked (You should choose "Option as +Esc".)
def __init__(self, stdin_fd,
errors=('ignore' if six.PY2 else 'surrogateescape')):
- assert isinstance(stdin_fd, int)
- self.stdin_fd = stdin_fd
+ assert isinstance(stdin_fd, int)
+ self.stdin_fd = stdin_fd
self.errors = errors
-
- # Create incremental decoder for decoding stdin.
- # We can not just do `os.read(stdin.fileno(), 1024).decode('utf-8')`, because
- # it could be that we are in the middle of a utf-8 byte sequence.
- self._stdin_decoder_cls = getincrementaldecoder('utf-8')
+
+ # Create incremental decoder for decoding stdin.
+ # We can not just do `os.read(stdin.fileno(), 1024).decode('utf-8')`, because
+ # it could be that we are in the middle of a utf-8 byte sequence.
+ self._stdin_decoder_cls = getincrementaldecoder('utf-8')
self._stdin_decoder = self._stdin_decoder_cls(errors=errors)
-
+
#: True when there is nothing anymore to read.
self.closed = False
- def read(self, count=1024):
- # By default we choose a rather small chunk size, because reading
- # big amounts of input at once, causes the event loop to process
- # all these key bindings also at once without going back to the
- # loop. This will make the application feel unresponsive.
- """
- Read the input and return it as a string.
+ def read(self, count=1024):
+ # By default we choose a rather small chunk size, because reading
+ # big amounts of input at once, causes the event loop to process
+ # all these key bindings also at once without going back to the
+ # loop. This will make the application feel unresponsive.
+ """
+ Read the input and return it as a string.
Return the text. Note that this can return an empty string, even when
the input stream was not yet closed. This means that something went
wrong during the decoding.
- """
+ """
if self.closed:
return b''
- # Note: the following works better than wrapping `self.stdin` like
- # `codecs.getreader('utf-8')(stdin)` and doing `read(1)`.
- # Somehow that causes some latency when the escape
- # character is pressed. (Especially on combination with the `select`.)
- try:
- data = os.read(self.stdin_fd, count)
+ # Note: the following works better than wrapping `self.stdin` like
+ # `codecs.getreader('utf-8')(stdin)` and doing `read(1)`.
+ # Somehow that causes some latency when the escape
+ # character is pressed. (Especially on combination with the `select`.)
+ try:
+ data = os.read(self.stdin_fd, count)
# Nothing more to read, stream is closed.
if data == b'':
self.closed = True
return ''
- except OSError:
- # In case of SIGWINCH
- data = b''
-
+ except OSError:
+ # In case of SIGWINCH
+ data = b''
+
return self._stdin_decoder.decode(data)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py
index 56b4646d1cb..ff3a4cfd697 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/utils.py
@@ -1,23 +1,23 @@
-from __future__ import unicode_literals
-import time
-
-__all__ = (
- 'TimeIt',
-)
-
-
-class TimeIt(object):
- """
- Context manager that times the duration of the code body.
- The `duration` attribute will contain the execution time in seconds.
- """
- def __init__(self):
- self.duration = None
-
- def __enter__(self):
- self.start = time.time()
- return self
-
- def __exit__(self, *args):
- self.end = time.time()
- self.duration = self.end - self.start
+from __future__ import unicode_literals
+import time
+
+__all__ = (
+ 'TimeIt',
+)
+
+
+class TimeIt(object):
+ """
+ Context manager that times the duration of the code body.
+ The `duration` attribute will contain the execution time in seconds.
+ """
+ def __init__(self):
+ self.duration = None
+
+ def __enter__(self):
+ self.start = time.time()
+ return self
+
+ def __exit__(self, *args):
+ self.end = time.time()
+ self.duration = self.end - self.start
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py
index 273c277de9f..18e356f0882 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/win32.py
@@ -1,187 +1,187 @@
-"""
-Win32 event loop.
-
-Windows notes:
- - Somehow it doesn't seem to work with the 'ProactorEventLoop'.
-"""
-from __future__ import unicode_literals
-
-from ..terminal.win32_input import ConsoleInputReader
-from ..win32_types import SECURITY_ATTRIBUTES
-from .base import EventLoop, INPUT_TIMEOUT
-from .inputhook import InputHookContext
-from .utils import TimeIt
-
-from ctypes import windll, pointer
-from ctypes.wintypes import DWORD, BOOL, HANDLE
-
+"""
+Win32 event loop.
+
+Windows notes:
+ - Somehow it doesn't seem to work with the 'ProactorEventLoop'.
+"""
+from __future__ import unicode_literals
+
+from ..terminal.win32_input import ConsoleInputReader
+from ..win32_types import SECURITY_ATTRIBUTES
+from .base import EventLoop, INPUT_TIMEOUT
+from .inputhook import InputHookContext
+from .utils import TimeIt
+
+from ctypes import windll, pointer
+from ctypes.wintypes import DWORD, BOOL, HANDLE
+
import msvcrt
-import threading
-
-__all__ = (
- 'Win32EventLoop',
-)
-
-WAIT_TIMEOUT = 0x00000102
-INPUT_TIMEOUT_MS = int(1000 * INPUT_TIMEOUT)
-
-
-class Win32EventLoop(EventLoop):
- """
- Event loop for Windows systems.
+import threading
+
+__all__ = (
+ 'Win32EventLoop',
+)
+
+WAIT_TIMEOUT = 0x00000102
+INPUT_TIMEOUT_MS = int(1000 * INPUT_TIMEOUT)
+
+
+class Win32EventLoop(EventLoop):
+ """
+ Event loop for Windows systems.
:param recognize_paste: When True, try to discover paste actions and turn
the event into a BracketedPaste.
- """
+ """
def __init__(self, inputhook=None, recognize_paste=True):
- assert inputhook is None or callable(inputhook)
-
+ assert inputhook is None or callable(inputhook)
+
self._event = HANDLE(_create_event())
self._console_input_reader = ConsoleInputReader(recognize_paste=recognize_paste)
- self._calls_from_executor = []
-
- self.closed = False
- self._running = False
-
+ self._calls_from_executor = []
+
+ self.closed = False
+ self._running = False
+
# Additional readers.
self._read_fds = {} # Maps fd to handler.
- # Create inputhook context.
- self._inputhook_context = InputHookContext(inputhook) if inputhook else None
-
- def run(self, stdin, callbacks):
- if self.closed:
- raise Exception('Event loop already closed.')
-
- current_timeout = INPUT_TIMEOUT_MS
- self._running = True
-
- while self._running:
- # Call inputhook.
- with TimeIt() as inputhook_timer:
- if self._inputhook_context:
- def ready(wait):
- " True when there is input ready. The inputhook should return control. "
- return bool(self._ready_for_reading(current_timeout if wait else 0))
- self._inputhook_context.call_inputhook(ready)
-
- # Calculate remaining timeout. (The inputhook consumed some of the time.)
- if current_timeout == -1:
- remaining_timeout = -1
- else:
- remaining_timeout = max(0, current_timeout - int(1000 * inputhook_timer.duration))
-
- # Wait for the next event.
- handle = self._ready_for_reading(remaining_timeout)
-
+ # Create inputhook context.
+ self._inputhook_context = InputHookContext(inputhook) if inputhook else None
+
+ def run(self, stdin, callbacks):
+ if self.closed:
+ raise Exception('Event loop already closed.')
+
+ current_timeout = INPUT_TIMEOUT_MS
+ self._running = True
+
+ while self._running:
+ # Call inputhook.
+ with TimeIt() as inputhook_timer:
+ if self._inputhook_context:
+ def ready(wait):
+ " True when there is input ready. The inputhook should return control. "
+ return bool(self._ready_for_reading(current_timeout if wait else 0))
+ self._inputhook_context.call_inputhook(ready)
+
+ # Calculate remaining timeout. (The inputhook consumed some of the time.)
+ if current_timeout == -1:
+ remaining_timeout = -1
+ else:
+ remaining_timeout = max(0, current_timeout - int(1000 * inputhook_timer.duration))
+
+ # Wait for the next event.
+ handle = self._ready_for_reading(remaining_timeout)
+
if handle == self._console_input_reader.handle.value:
- # When stdin is ready, read input and reset timeout timer.
- keys = self._console_input_reader.read()
- for k in keys:
- callbacks.feed_key(k)
- current_timeout = INPUT_TIMEOUT_MS
-
+ # When stdin is ready, read input and reset timeout timer.
+ keys = self._console_input_reader.read()
+ for k in keys:
+ callbacks.feed_key(k)
+ current_timeout = INPUT_TIMEOUT_MS
+
elif handle == self._event.value:
- # When the Windows Event has been trigger, process the messages in the queue.
- windll.kernel32.ResetEvent(self._event)
- self._process_queued_calls_from_executor()
-
+ # When the Windows Event has been trigger, process the messages in the queue.
+ windll.kernel32.ResetEvent(self._event)
+ self._process_queued_calls_from_executor()
+
elif handle in self._read_fds:
callback = self._read_fds[handle]
callback()
- else:
- # Fire input timeout event.
- callbacks.input_timeout()
- current_timeout = -1
-
- def _ready_for_reading(self, timeout=None):
- """
- Return the handle that is ready for reading or `None` on timeout.
- """
+ else:
+ # Fire input timeout event.
+ callbacks.input_timeout()
+ current_timeout = -1
+
+ def _ready_for_reading(self, timeout=None):
+ """
+ Return the handle that is ready for reading or `None` on timeout.
+ """
handles = [self._event, self._console_input_reader.handle]
handles.extend(self._read_fds.keys())
return _wait_for_handles(handles, timeout)
-
- def stop(self):
- self._running = False
-
- def close(self):
- self.closed = True
-
- # Clean up Event object.
- windll.kernel32.CloseHandle(self._event)
-
- if self._inputhook_context:
- self._inputhook_context.close()
-
+
+ def stop(self):
+ self._running = False
+
+ def close(self):
+ self.closed = True
+
+ # Clean up Event object.
+ windll.kernel32.CloseHandle(self._event)
+
+ if self._inputhook_context:
+ self._inputhook_context.close()
+
self._console_input_reader.close()
- def run_in_executor(self, callback):
- """
- Run a long running function in a background thread.
- (This is recommended for code that could block the event loop.)
- Similar to Twisted's ``deferToThread``.
- """
- # Wait until the main thread is idle for an instant before starting the
- # executor. (Like in eventloop/posix.py, we start the executor using
- # `call_from_executor`.)
- def start_executor():
- threading.Thread(target=callback).start()
- self.call_from_executor(start_executor)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- """
- Call this function in the main event loop.
- Similar to Twisted's ``callFromThread``.
- """
- # Append to list of pending callbacks.
- self._calls_from_executor.append(callback)
-
- # Set Windows event.
- windll.kernel32.SetEvent(self._event)
-
- def _process_queued_calls_from_executor(self):
- # Process calls from executor.
- calls_from_executor, self._calls_from_executor = self._calls_from_executor, []
- for c in calls_from_executor:
- c()
-
- def add_reader(self, fd, callback):
- " Start watching the file descriptor for read availability. "
+ def run_in_executor(self, callback):
+ """
+ Run a long running function in a background thread.
+ (This is recommended for code that could block the event loop.)
+ Similar to Twisted's ``deferToThread``.
+ """
+ # Wait until the main thread is idle for an instant before starting the
+ # executor. (Like in eventloop/posix.py, we start the executor using
+ # `call_from_executor`.)
+ def start_executor():
+ threading.Thread(target=callback).start()
+ self.call_from_executor(start_executor)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ """
+ Call this function in the main event loop.
+ Similar to Twisted's ``callFromThread``.
+ """
+ # Append to list of pending callbacks.
+ self._calls_from_executor.append(callback)
+
+ # Set Windows event.
+ windll.kernel32.SetEvent(self._event)
+
+ def _process_queued_calls_from_executor(self):
+ # Process calls from executor.
+ calls_from_executor, self._calls_from_executor = self._calls_from_executor, []
+ for c in calls_from_executor:
+ c()
+
+ def add_reader(self, fd, callback):
+ " Start watching the file descriptor for read availability. "
h = msvcrt.get_osfhandle(fd)
self._read_fds[h] = callback
-
- def remove_reader(self, fd):
- " Stop watching the file descriptor for read availability. "
+
+ def remove_reader(self, fd):
+ " Stop watching the file descriptor for read availability. "
h = msvcrt.get_osfhandle(fd)
if h in self._read_fds:
del self._read_fds[h]
-
-
-def _wait_for_handles(handles, timeout=-1):
- """
- Waits for multiple handles. (Similar to 'select') Returns the handle which is ready.
- Returns `None` on timeout.
-
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
- """
- arrtype = HANDLE * len(handles)
- handle_array = arrtype(*handles)
-
- ret = windll.kernel32.WaitForMultipleObjects(
- len(handle_array), handle_array, BOOL(False), DWORD(timeout))
-
- if ret == WAIT_TIMEOUT:
- return None
- else:
- h = handle_array[ret]
- return h
-
-
-def _create_event():
- """
- Creates a Win32 unnamed Event .
-
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
- """
- return windll.kernel32.CreateEventA(pointer(SECURITY_ATTRIBUTES()), BOOL(True), BOOL(False), None)
+
+
+def _wait_for_handles(handles, timeout=-1):
+ """
+ Waits for multiple handles. (Similar to 'select') Returns the handle which is ready.
+ Returns `None` on timeout.
+
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
+ """
+ arrtype = HANDLE * len(handles)
+ handle_array = arrtype(*handles)
+
+ ret = windll.kernel32.WaitForMultipleObjects(
+ len(handle_array), handle_array, BOOL(False), DWORD(timeout))
+
+ if ret == WAIT_TIMEOUT:
+ return None
+ else:
+ h = handle_array[ret]
+ return h
+
+
+def _create_event():
+ """
+ Creates a Win32 unnamed Event .
+
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
+ """
+ return windll.kernel32.CreateEventA(pointer(SECURITY_ATTRIBUTES()), BOOL(True), BOOL(False), None)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py
index 2f57dbd6808..d3f14efc1c6 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/__init__.py
@@ -1,36 +1,36 @@
-"""
-Filters decide whether something is active or not (they decide about a boolean
-state). This is used to enable/disable features, like key bindings, parts of
-the layout and other stuff. For instance, we could have a `HasSearch` filter
-attached to some part of the layout, in order to show that part of the user
-interface only while the user is searching.
-
-Filters are made to avoid having to attach callbacks to all event in order to
-propagate state. However, they are lazy, they don't automatically propagate the
-state of what they are observing. Only when a filter is called (it's actually a
-callable), it will calculate its value. So, its not really reactive
-programming, but it's made to fit for this framework.
-
-One class of filters observe a `CommandLineInterface` instance. However, they
-are not attached to such an instance. (We have to pass this instance to the
-filter when calling it.) The reason for this is to allow declarative
-programming: for key bindings, we can attach a filter to a key binding without
-knowing yet which `CommandLineInterface` instance it will observe in the end.
-Examples are `HasSearch` or `IsExiting`.
-
-Another class of filters doesn't take anything as input. And a third class of
-filters are universal, for instance `Always` and `Never`.
-It is impossible to mix the first and the second class, because that would mean
-mixing filters with a different signature.
-
-Filters can be chained using ``&`` and ``|`` operations, and inverted using the
-``~`` operator, for instance::
-
- filter = HasFocus('default') & ~ HasSelection()
-"""
-from __future__ import unicode_literals
-
-from .base import *
-from .cli import *
-from .types import *
-from .utils import *
+"""
+Filters decide whether something is active or not (they decide about a boolean
+state). This is used to enable/disable features, like key bindings, parts of
+the layout and other stuff. For instance, we could have a `HasSearch` filter
+attached to some part of the layout, in order to show that part of the user
+interface only while the user is searching.
+
+Filters are made to avoid having to attach callbacks to all event in order to
+propagate state. However, they are lazy, they don't automatically propagate the
+state of what they are observing. Only when a filter is called (it's actually a
+callable), it will calculate its value. So, its not really reactive
+programming, but it's made to fit for this framework.
+
+One class of filters observe a `CommandLineInterface` instance. However, they
+are not attached to such an instance. (We have to pass this instance to the
+filter when calling it.) The reason for this is to allow declarative
+programming: for key bindings, we can attach a filter to a key binding without
+knowing yet which `CommandLineInterface` instance it will observe in the end.
+Examples are `HasSearch` or `IsExiting`.
+
+Another class of filters doesn't take anything as input. And a third class of
+filters are universal, for instance `Always` and `Never`.
+It is impossible to mix the first and the second class, because that would mean
+mixing filters with a different signature.
+
+Filters can be chained using ``&`` and ``|`` operations, and inverted using the
+``~`` operator, for instance::
+
+ filter = HasFocus('default') & ~ HasSelection()
+"""
+from __future__ import unicode_literals
+
+from .base import *
+from .cli import *
+from .types import *
+from .utils import *
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py
index 7bbdd434983..6a1a1d0b10e 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/base.py
@@ -1,79 +1,79 @@
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
from prompt_toolkit.utils import test_callable_args
-
-
-__all__ = (
- 'Filter',
- 'Never',
- 'Always',
- 'Condition',
-)
-
-
-class Filter(with_metaclass(ABCMeta, object)):
- """
- Filter to activate/deactivate a feature, depending on a condition.
- The return value of ``__call__`` will tell if the feature should be active.
- """
- @abstractmethod
- def __call__(self, *a, **kw):
- """
- The actual call to evaluate the filter.
- """
- return True
-
- def __and__(self, other):
- """
- Chaining of filters using the & operator.
- """
+
+
+__all__ = (
+ 'Filter',
+ 'Never',
+ 'Always',
+ 'Condition',
+)
+
+
+class Filter(with_metaclass(ABCMeta, object)):
+ """
+ Filter to activate/deactivate a feature, depending on a condition.
+ The return value of ``__call__`` will tell if the feature should be active.
+ """
+ @abstractmethod
+ def __call__(self, *a, **kw):
+ """
+ The actual call to evaluate the filter.
+ """
+ return True
+
+ def __and__(self, other):
+ """
+ Chaining of filters using the & operator.
+ """
return _and_cache[self, other]
-
- def __or__(self, other):
- """
- Chaining of filters using the | operator.
- """
+
+ def __or__(self, other):
+ """
+ Chaining of filters using the | operator.
+ """
return _or_cache[self, other]
-
- def __invert__(self):
- """
- Inverting of filters using the ~ operator.
- """
+
+ def __invert__(self):
+ """
+ Inverting of filters using the ~ operator.
+ """
return _invert_cache[self]
-
- def __bool__(self):
- """
- By purpose, we don't allow bool(...) operations directly on a filter,
- because because the meaning is ambigue.
-
- Executing a filter has to be done always by calling it. Providing
- defaults for `None` values should be done through an `is None` check
- instead of for instance ``filter1 or Always()``.
- """
- raise TypeError
-
- __nonzero__ = __bool__ # For Python 2.
-
+
+ def __bool__(self):
+ """
+ By purpose, we don't allow bool(...) operations directly on a filter,
+ because because the meaning is ambigue.
+
+ Executing a filter has to be done always by calling it. Providing
+ defaults for `None` values should be done through an `is None` check
+ instead of for instance ``filter1 or Always()``.
+ """
+ raise TypeError
+
+ __nonzero__ = __bool__ # For Python 2.
+
def test_args(self, *args):
- """
+ """
Test whether this filter can be called with the following argument list.
- """
+ """
return test_callable_args(self.__call__, args)
-
-
-class _AndCache(dict):
- """
- Cache for And operation between filters.
- (Filter classes are stateless, so we can reuse them.)
-
- Note: This could be a memory leak if we keep creating filters at runtime.
- If that is True, the filters should be weakreffed (not the tuple of
- filters), and tuples should be removed when one of these filters is
- removed. In practise however, there is a finite amount of filters.
- """
- def __missing__(self, filters):
+
+
+class _AndCache(dict):
+ """
+ Cache for And operation between filters.
+ (Filter classes are stateless, so we can reuse them.)
+
+ Note: This could be a memory leak if we keep creating filters at runtime.
+ If that is True, the filters should be weakreffed (not the tuple of
+ filters), and tuples should be removed when one of these filters is
+ removed. In practise however, there is a finite amount of filters.
+ """
+ def __missing__(self, filters):
a, b = filters
assert isinstance(b, Filter), 'Expecting filter, got %r' % b
@@ -82,14 +82,14 @@ class _AndCache(dict):
elif isinstance(b, Never) or isinstance(a, Always):
return b
- result = _AndList(filters)
- self[filters] = result
- return result
-
-
-class _OrCache(dict):
- """ Cache for Or operation between filters. """
- def __missing__(self, filters):
+ result = _AndList(filters)
+ self[filters] = result
+ return result
+
+
+class _OrCache(dict):
+ """ Cache for Or operation between filters. """
+ def __missing__(self, filters):
a, b = filters
assert isinstance(b, Filter), 'Expecting filter, got %r' % b
@@ -98,11 +98,11 @@ class _OrCache(dict):
elif isinstance(b, Never) or isinstance(a, Always):
return a
- result = _OrList(filters)
- self[filters] = result
- return result
-
-
+ result = _OrList(filters)
+ self[filters] = result
+ return result
+
+
class _InvertCache(dict):
""" Cache for inversion operator. """
def __missing__(self, filter):
@@ -111,124 +111,124 @@ class _InvertCache(dict):
return result
-_and_cache = _AndCache()
-_or_cache = _OrCache()
+_and_cache = _AndCache()
+_or_cache = _OrCache()
_invert_cache = _InvertCache()
-
-
-class _AndList(Filter):
- """
- Result of &-operation between several filters.
- """
- def __init__(self, filters):
- all_filters = []
-
- for f in filters:
- if isinstance(f, _AndList): # Turn nested _AndLists into one.
- all_filters.extend(f.filters)
- else:
- all_filters.append(f)
-
- self.filters = all_filters
-
+
+
+class _AndList(Filter):
+ """
+ Result of &-operation between several filters.
+ """
+ def __init__(self, filters):
+ all_filters = []
+
+ for f in filters:
+ if isinstance(f, _AndList): # Turn nested _AndLists into one.
+ all_filters.extend(f.filters)
+ else:
+ all_filters.append(f)
+
+ self.filters = all_filters
+
def test_args(self, *args):
return all(f.test_args(*args) for f in self.filters)
-
- def __call__(self, *a, **kw):
- return all(f(*a, **kw) for f in self.filters)
-
- def __repr__(self):
- return '&'.join(repr(f) for f in self.filters)
-
-
-class _OrList(Filter):
- """
- Result of |-operation between several filters.
- """
- def __init__(self, filters):
- all_filters = []
-
- for f in filters:
- if isinstance(f, _OrList): # Turn nested _OrLists into one.
- all_filters.extend(f.filters)
- else:
- all_filters.append(f)
-
- self.filters = all_filters
-
+
+ def __call__(self, *a, **kw):
+ return all(f(*a, **kw) for f in self.filters)
+
+ def __repr__(self):
+ return '&'.join(repr(f) for f in self.filters)
+
+
+class _OrList(Filter):
+ """
+ Result of |-operation between several filters.
+ """
+ def __init__(self, filters):
+ all_filters = []
+
+ for f in filters:
+ if isinstance(f, _OrList): # Turn nested _OrLists into one.
+ all_filters.extend(f.filters)
+ else:
+ all_filters.append(f)
+
+ self.filters = all_filters
+
def test_args(self, *args):
return all(f.test_args(*args) for f in self.filters)
-
- def __call__(self, *a, **kw):
- return any(f(*a, **kw) for f in self.filters)
-
- def __repr__(self):
- return '|'.join(repr(f) for f in self.filters)
-
-
-class _Invert(Filter):
- """
- Negation of another filter.
- """
- def __init__(self, filter):
- self.filter = filter
-
- def __call__(self, *a, **kw):
- return not self.filter(*a, **kw)
-
- def __repr__(self):
- return '~%r' % self.filter
-
+
+ def __call__(self, *a, **kw):
+ return any(f(*a, **kw) for f in self.filters)
+
+ def __repr__(self):
+ return '|'.join(repr(f) for f in self.filters)
+
+
+class _Invert(Filter):
+ """
+ Negation of another filter.
+ """
+ def __init__(self, filter):
+ self.filter = filter
+
+ def __call__(self, *a, **kw):
+ return not self.filter(*a, **kw)
+
+ def __repr__(self):
+ return '~%r' % self.filter
+
def test_args(self, *args):
return self.filter.test_args(*args)
-
-
-class Always(Filter):
- """
- Always enable feature.
- """
- def __call__(self, *a, **kw):
- return True
-
- def __invert__(self):
- return Never()
-
-
-class Never(Filter):
- """
- Never enable feature.
- """
- def __call__(self, *a, **kw):
- return False
-
- def __invert__(self):
- return Always()
-
-
-class Condition(Filter):
- """
- Turn any callable (which takes a cli and returns a boolean) into a Filter.
-
- This can be used as a decorator::
-
- @Condition
- def feature_is_active(cli): # `feature_is_active` becomes a Filter.
- return True
-
- :param func: Callable which takes either a
- :class:`~prompt_toolkit.interface.CommandLineInterface` or nothing and
- returns a boolean. (Depending on what it takes, this will become a
- :class:`.Filter` or :class:`~prompt_toolkit.filters.CLIFilter`.)
- """
- def __init__(self, func):
- assert callable(func)
- self.func = func
-
- def __call__(self, *a, **kw):
- return self.func(*a, **kw)
-
- def __repr__(self):
- return 'Condition(%r)' % self.func
-
+
+
+class Always(Filter):
+ """
+ Always enable feature.
+ """
+ def __call__(self, *a, **kw):
+ return True
+
+ def __invert__(self):
+ return Never()
+
+
+class Never(Filter):
+ """
+ Never enable feature.
+ """
+ def __call__(self, *a, **kw):
+ return False
+
+ def __invert__(self):
+ return Always()
+
+
+class Condition(Filter):
+ """
+ Turn any callable (which takes a cli and returns a boolean) into a Filter.
+
+ This can be used as a decorator::
+
+ @Condition
+ def feature_is_active(cli): # `feature_is_active` becomes a Filter.
+ return True
+
+ :param func: Callable which takes either a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` or nothing and
+ returns a boolean. (Depending on what it takes, this will become a
+ :class:`.Filter` or :class:`~prompt_toolkit.filters.CLIFilter`.)
+ """
+ def __init__(self, func):
+ assert callable(func)
+ self.func = func
+
+ def __call__(self, *a, **kw):
+ return self.func(*a, **kw)
+
+ def __repr__(self):
+ return 'Condition(%r)' % self.func
+
def test_args(self, *a):
return test_callable_args(self.func, a)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py
index 76adc8ef4bb..c0b07317beb 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/cli.py
@@ -1,26 +1,26 @@
-"""
-Filters that accept a `CommandLineInterface` as argument.
-"""
-from __future__ import unicode_literals
-from .base import Filter
+"""
+Filters that accept a `CommandLineInterface` as argument.
+"""
+from __future__ import unicode_literals
+from .base import Filter
from prompt_toolkit.enums import EditingMode
from prompt_toolkit.key_binding.vi_state import InputMode as ViInputMode
from prompt_toolkit.cache import memoized
-
-__all__ = (
- 'HasArg',
- 'HasCompletions',
- 'HasFocus',
- 'InFocusStack',
- 'HasSearch',
- 'HasSelection',
- 'HasValidationError',
- 'IsAborting',
- 'IsDone',
- 'IsMultiline',
- 'IsReadOnly',
- 'IsReturning',
- 'RendererHeightIsKnown',
+
+__all__ = (
+ 'HasArg',
+ 'HasCompletions',
+ 'HasFocus',
+ 'InFocusStack',
+ 'HasSearch',
+ 'HasSelection',
+ 'HasValidationError',
+ 'IsAborting',
+ 'IsDone',
+ 'IsMultiline',
+ 'IsReadOnly',
+ 'IsReturning',
+ 'RendererHeightIsKnown',
'InEditingMode',
# Vi modes.
@@ -37,197 +37,197 @@ __all__ = (
'EmacsMode',
'EmacsInsertMode',
'EmacsSelectionMode',
-)
-
-
+)
+
+
@memoized()
-class HasFocus(Filter):
- """
- Enable when this buffer has the focus.
- """
- def __init__(self, buffer_name):
+class HasFocus(Filter):
+ """
+ Enable when this buffer has the focus.
+ """
+ def __init__(self, buffer_name):
self._buffer_name = buffer_name
-
+
@property
def buffer_name(self):
" The given buffer name. (Read-only) "
return self._buffer_name
- def __call__(self, cli):
- return cli.current_buffer_name == self.buffer_name
-
- def __repr__(self):
- return 'HasFocus(%r)' % self.buffer_name
-
-
+ def __call__(self, cli):
+ return cli.current_buffer_name == self.buffer_name
+
+ def __repr__(self):
+ return 'HasFocus(%r)' % self.buffer_name
+
+
@memoized()
-class InFocusStack(Filter):
- """
- Enable when this buffer appears on the focus stack.
- """
- def __init__(self, buffer_name):
+class InFocusStack(Filter):
+ """
+ Enable when this buffer appears on the focus stack.
+ """
+ def __init__(self, buffer_name):
self._buffer_name = buffer_name
-
+
@property
def buffer_name(self):
" The given buffer name. (Read-only) "
return self._buffer_name
- def __call__(self, cli):
- return self.buffer_name in cli.buffers.focus_stack
-
- def __repr__(self):
- return 'InFocusStack(%r)' % self.buffer_name
-
-
+ def __call__(self, cli):
+ return self.buffer_name in cli.buffers.focus_stack
+
+ def __repr__(self):
+ return 'InFocusStack(%r)' % self.buffer_name
+
+
@memoized()
-class HasSelection(Filter):
- """
- Enable when the current buffer has a selection.
- """
- def __call__(self, cli):
- return bool(cli.current_buffer.selection_state)
-
- def __repr__(self):
- return 'HasSelection()'
-
-
+class HasSelection(Filter):
+ """
+ Enable when the current buffer has a selection.
+ """
+ def __call__(self, cli):
+ return bool(cli.current_buffer.selection_state)
+
+ def __repr__(self):
+ return 'HasSelection()'
+
+
@memoized()
-class HasCompletions(Filter):
- """
- Enable when the current buffer has completions.
- """
- def __call__(self, cli):
- return cli.current_buffer.complete_state is not None
-
- def __repr__(self):
- return 'HasCompletions()'
-
-
+class HasCompletions(Filter):
+ """
+ Enable when the current buffer has completions.
+ """
+ def __call__(self, cli):
+ return cli.current_buffer.complete_state is not None
+
+ def __repr__(self):
+ return 'HasCompletions()'
+
+
@memoized()
-class IsMultiline(Filter):
- """
- Enable in multiline mode.
- """
- def __call__(self, cli):
- return cli.current_buffer.is_multiline()
-
- def __repr__(self):
- return 'IsMultiline()'
-
-
+class IsMultiline(Filter):
+ """
+ Enable in multiline mode.
+ """
+ def __call__(self, cli):
+ return cli.current_buffer.is_multiline()
+
+ def __repr__(self):
+ return 'IsMultiline()'
+
+
@memoized()
-class IsReadOnly(Filter):
- """
- True when the current buffer is read only.
- """
- def __call__(self, cli):
- return cli.current_buffer.read_only()
-
- def __repr__(self):
- return 'IsReadOnly()'
-
-
+class IsReadOnly(Filter):
+ """
+ True when the current buffer is read only.
+ """
+ def __call__(self, cli):
+ return cli.current_buffer.read_only()
+
+ def __repr__(self):
+ return 'IsReadOnly()'
+
+
@memoized()
-class HasValidationError(Filter):
- """
- Current buffer has validation error.
- """
- def __call__(self, cli):
- return cli.current_buffer.validation_error is not None
-
- def __repr__(self):
- return 'HasValidationError()'
-
-
+class HasValidationError(Filter):
+ """
+ Current buffer has validation error.
+ """
+ def __call__(self, cli):
+ return cli.current_buffer.validation_error is not None
+
+ def __repr__(self):
+ return 'HasValidationError()'
+
+
@memoized()
-class HasArg(Filter):
- """
- Enable when the input processor has an 'arg'.
- """
- def __call__(self, cli):
- return cli.input_processor.arg is not None
-
- def __repr__(self):
- return 'HasArg()'
-
-
+class HasArg(Filter):
+ """
+ Enable when the input processor has an 'arg'.
+ """
+ def __call__(self, cli):
+ return cli.input_processor.arg is not None
+
+ def __repr__(self):
+ return 'HasArg()'
+
+
@memoized()
-class HasSearch(Filter):
- """
- Incremental search is active.
- """
- def __call__(self, cli):
- return cli.is_searching
-
- def __repr__(self):
- return 'HasSearch()'
-
-
+class HasSearch(Filter):
+ """
+ Incremental search is active.
+ """
+ def __call__(self, cli):
+ return cli.is_searching
+
+ def __repr__(self):
+ return 'HasSearch()'
+
+
@memoized()
-class IsReturning(Filter):
- """
- When a return value has been set.
- """
- def __call__(self, cli):
- return cli.is_returning
-
- def __repr__(self):
- return 'IsReturning()'
-
-
+class IsReturning(Filter):
+ """
+ When a return value has been set.
+ """
+ def __call__(self, cli):
+ return cli.is_returning
+
+ def __repr__(self):
+ return 'IsReturning()'
+
+
@memoized()
-class IsAborting(Filter):
- """
- True when aborting. (E.g. Control-C pressed.)
- """
- def __call__(self, cli):
- return cli.is_aborting
-
- def __repr__(self):
- return 'IsAborting()'
-
-
+class IsAborting(Filter):
+ """
+ True when aborting. (E.g. Control-C pressed.)
+ """
+ def __call__(self, cli):
+ return cli.is_aborting
+
+ def __repr__(self):
+ return 'IsAborting()'
+
+
@memoized()
-class IsExiting(Filter):
- """
- True when exiting. (E.g. Control-D pressed.)
- """
- def __call__(self, cli):
- return cli.is_exiting
-
- def __repr__(self):
- return 'IsExiting()'
-
-
+class IsExiting(Filter):
+ """
+ True when exiting. (E.g. Control-D pressed.)
+ """
+ def __call__(self, cli):
+ return cli.is_exiting
+
+ def __repr__(self):
+ return 'IsExiting()'
+
+
@memoized()
-class IsDone(Filter):
- """
- True when the CLI is returning, aborting or exiting.
- """
- def __call__(self, cli):
- return cli.is_done
-
- def __repr__(self):
- return 'IsDone()'
-
-
+class IsDone(Filter):
+ """
+ True when the CLI is returning, aborting or exiting.
+ """
+ def __call__(self, cli):
+ return cli.is_done
+
+ def __repr__(self):
+ return 'IsDone()'
+
+
@memoized()
-class RendererHeightIsKnown(Filter):
- """
- Only True when the renderer knows it's real height.
-
- (On VT100 terminals, we have to wait for a CPR response, before we can be
- sure of the available height between the cursor position and the bottom of
- the terminal. And usually it's nicer to wait with drawing bottom toolbars
- until we receive the height, in order to avoid flickering -- first drawing
- somewhere in the middle, and then again at the bottom.)
- """
- def __call__(self, cli):
- return cli.renderer.height_is_known
-
- def __repr__(self):
- return 'RendererHeightIsKnown()'
+class RendererHeightIsKnown(Filter):
+ """
+ Only True when the renderer knows it's real height.
+
+ (On VT100 terminals, we have to wait for a CPR response, before we can be
+ sure of the available height between the cursor position and the bottom of
+ the terminal. And usually it's nicer to wait with drawing bottom toolbars
+ until we receive the height, in order to avoid flickering -- first drawing
+ somewhere in the middle, and then again at the bottom.)
+ """
+ def __call__(self, cli):
+ return cli.renderer.height_is_known
+
+ def __repr__(self):
+ return 'RendererHeightIsKnown()'
@memoized()
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py
index caf600bb9b8..3e89c39c01f 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/types.py
@@ -1,55 +1,55 @@
-from __future__ import unicode_literals
-from six import with_metaclass
+from __future__ import unicode_literals
+from six import with_metaclass
from collections import defaultdict
import weakref
-
-__all__ = (
- 'CLIFilter',
- 'SimpleFilter',
-)
-
+
+__all__ = (
+ 'CLIFilter',
+ 'SimpleFilter',
+)
+
# Cache for _FilterTypeMeta. (Don't test the same __instancecheck__ twice as
# long as the object lives. -- We do this a lot and calling 'test_args' is
# expensive.)
_instance_check_cache = defaultdict(weakref.WeakKeyDictionary)
-class _FilterTypeMeta(type):
- def __instancecheck__(cls, instance):
+class _FilterTypeMeta(type):
+ def __instancecheck__(cls, instance):
cache = _instance_check_cache[tuple(cls.arguments_list)]
-
+
def get():
" The actual test. "
if not hasattr(instance, 'test_args'):
return False
return instance.test_args(*cls.arguments_list)
-
+
try:
return cache[instance]
except KeyError:
result = get()
cache[instance] = result
return result
-
-
-class _FilterType(with_metaclass(_FilterTypeMeta)):
- def __new__(cls):
- raise NotImplementedError('This class should not be initiated.')
-
-
-class CLIFilter(_FilterType):
- """
- Abstract base class for filters that accept a
- :class:`~prompt_toolkit.interface.CommandLineInterface` argument. It cannot
- be instantiated, it's only to be used for instance assertions, e.g.::
-
- isinstance(my_filter, CliFilter)
- """
- arguments_list = ['cli']
-
-
-class SimpleFilter(_FilterType):
- """
- Abstract base class for filters that don't accept any arguments.
- """
- arguments_list = []
+
+
+class _FilterType(with_metaclass(_FilterTypeMeta)):
+ def __new__(cls):
+ raise NotImplementedError('This class should not be initiated.')
+
+
+class CLIFilter(_FilterType):
+ """
+ Abstract base class for filters that accept a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` argument. It cannot
+ be instantiated, it's only to be used for instance assertions, e.g.::
+
+ isinstance(my_filter, CliFilter)
+ """
+ arguments_list = ['cli']
+
+
+class SimpleFilter(_FilterType):
+ """
+ Abstract base class for filters that don't accept any arguments.
+ """
+ arguments_list = []
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py
index b3a66df2c5f..836d2956e78 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/filters/utils.py
@@ -1,39 +1,39 @@
-from __future__ import unicode_literals
-from .base import Always, Never
-from .types import SimpleFilter, CLIFilter
-
-__all__ = (
- 'to_cli_filter',
- 'to_simple_filter',
-)
-
-_always = Always()
-_never = Never()
-
-
-def to_simple_filter(bool_or_filter):
- """
- Accept both booleans and CLIFilters as input and
- turn it into a SimpleFilter.
- """
+from __future__ import unicode_literals
+from .base import Always, Never
+from .types import SimpleFilter, CLIFilter
+
+__all__ = (
+ 'to_cli_filter',
+ 'to_simple_filter',
+)
+
+_always = Always()
+_never = Never()
+
+
+def to_simple_filter(bool_or_filter):
+ """
+ Accept both booleans and CLIFilters as input and
+ turn it into a SimpleFilter.
+ """
if not isinstance(bool_or_filter, (bool, SimpleFilter)):
raise TypeError('Expecting a bool or a SimpleFilter instance. Got %r' % bool_or_filter)
-
- return {
- True: _always,
- False: _never,
- }.get(bool_or_filter, bool_or_filter)
-
-
-def to_cli_filter(bool_or_filter):
- """
- Accept both booleans and CLIFilters as input and
- turn it into a CLIFilter.
- """
+
+ return {
+ True: _always,
+ False: _never,
+ }.get(bool_or_filter, bool_or_filter)
+
+
+def to_cli_filter(bool_or_filter):
+ """
+ Accept both booleans and CLIFilters as input and
+ turn it into a CLIFilter.
+ """
if not isinstance(bool_or_filter, (bool, CLIFilter)):
raise TypeError('Expecting a bool or a CLIFilter instance. Got %r' % bool_or_filter)
-
- return {
- True: _always,
- False: _never,
- }.get(bool_or_filter, bool_or_filter)
+
+ return {
+ True: _always,
+ False: _never,
+ }.get(bool_or_filter, bool_or_filter)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py
index ab971ee05c6..d1eb5f2730a 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/history.py
@@ -1,120 +1,120 @@
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-import datetime
-import os
-
-__all__ = (
- 'FileHistory',
- 'History',
- 'InMemoryHistory',
-)
-
-
-class History(with_metaclass(ABCMeta, object)):
- """
- Base ``History`` interface.
- """
- @abstractmethod
- def append(self, string):
- " Append string to history. "
-
- @abstractmethod
- def __getitem__(self, key):
- " Return one item of the history. It should be accessible like a `list`. "
-
- @abstractmethod
- def __iter__(self):
- " Iterate through all the items of the history. Cronologically. "
-
- @abstractmethod
- def __len__(self):
- " Return the length of the history. "
-
- def __bool__(self):
- """
- Never evaluate to False, even when the history is empty.
- (Python calls __len__ if __bool__ is not implemented.)
- This is mainly to allow lazy evaluation::
-
- x = history or InMemoryHistory()
- """
- return True
-
- __nonzero__ = __bool__ # For Python 2.
-
-
-class InMemoryHistory(History):
- """
- :class:`.History` class that keeps a list of all strings in memory.
- """
- def __init__(self):
- self.strings = []
-
- def append(self, string):
- self.strings.append(string)
-
- def __getitem__(self, key):
- return self.strings[key]
-
- def __iter__(self):
- return iter(self.strings)
-
- def __len__(self):
- return len(self.strings)
-
-
-class FileHistory(History):
- """
- :class:`.History` class that stores all strings in a file.
- """
- def __init__(self, filename):
- self.strings = []
- self.filename = filename
-
- self._load()
-
- def _load(self):
- lines = []
-
- def add():
- if lines:
- # Join and drop trailing newline.
- string = ''.join(lines)[:-1]
-
- self.strings.append(string)
-
- if os.path.exists(self.filename):
- with open(self.filename, 'rb') as f:
- for line in f:
- line = line.decode('utf-8')
-
- if line.startswith('+'):
- lines.append(line[1:])
- else:
- add()
- lines = []
-
- add()
-
- def append(self, string):
- self.strings.append(string)
-
- # Save to file.
- with open(self.filename, 'ab') as f:
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+import datetime
+import os
+
+__all__ = (
+ 'FileHistory',
+ 'History',
+ 'InMemoryHistory',
+)
+
+
+class History(with_metaclass(ABCMeta, object)):
+ """
+ Base ``History`` interface.
+ """
+ @abstractmethod
+ def append(self, string):
+ " Append string to history. "
+
+ @abstractmethod
+ def __getitem__(self, key):
+ " Return one item of the history. It should be accessible like a `list`. "
+
+ @abstractmethod
+ def __iter__(self):
+ " Iterate through all the items of the history. Cronologically. "
+
+ @abstractmethod
+ def __len__(self):
+ " Return the length of the history. "
+
+ def __bool__(self):
+ """
+ Never evaluate to False, even when the history is empty.
+ (Python calls __len__ if __bool__ is not implemented.)
+ This is mainly to allow lazy evaluation::
+
+ x = history or InMemoryHistory()
+ """
+ return True
+
+ __nonzero__ = __bool__ # For Python 2.
+
+
+class InMemoryHistory(History):
+ """
+ :class:`.History` class that keeps a list of all strings in memory.
+ """
+ def __init__(self):
+ self.strings = []
+
+ def append(self, string):
+ self.strings.append(string)
+
+ def __getitem__(self, key):
+ return self.strings[key]
+
+ def __iter__(self):
+ return iter(self.strings)
+
+ def __len__(self):
+ return len(self.strings)
+
+
+class FileHistory(History):
+ """
+ :class:`.History` class that stores all strings in a file.
+ """
+ def __init__(self, filename):
+ self.strings = []
+ self.filename = filename
+
+ self._load()
+
+ def _load(self):
+ lines = []
+
+ def add():
+ if lines:
+ # Join and drop trailing newline.
+ string = ''.join(lines)[:-1]
+
+ self.strings.append(string)
+
+ if os.path.exists(self.filename):
+ with open(self.filename, 'rb') as f:
+ for line in f:
+ line = line.decode('utf-8')
+
+ if line.startswith('+'):
+ lines.append(line[1:])
+ else:
+ add()
+ lines = []
+
+ add()
+
+ def append(self, string):
+ self.strings.append(string)
+
+ # Save to file.
+ with open(self.filename, 'ab') as f:
def write(t):
f.write(t.encode('utf-8'))
-
- write('\n# %s\n' % datetime.datetime.now())
- for line in string.split('\n'):
- write('+%s\n' % line)
-
- def __getitem__(self, key):
- return self.strings[key]
-
- def __iter__(self):
- return iter(self.strings)
-
- def __len__(self):
- return len(self.strings)
+
+ write('\n# %s\n' % datetime.datetime.now())
+ for line in string.split('\n'):
+ write('+%s\n' % line)
+
+ def __getitem__(self, key):
+ return self.strings[key]
+
+ def __iter__(self):
+ return iter(self.strings)
+
+ def __len__(self):
+ return len(self.strings)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py
index ad6d4cf696e..f123732560e 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/input.py
@@ -1,68 +1,68 @@
-"""
-Abstraction of CLI Input.
-"""
-from __future__ import unicode_literals
-
-from .utils import DummyContext, is_windows
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
+"""
+Abstraction of CLI Input.
+"""
+from __future__ import unicode_literals
+
+from .utils import DummyContext, is_windows
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
import io
-import os
-import sys
-
-if is_windows():
- from .terminal.win32_input import raw_mode, cooked_mode
-else:
- from .terminal.vt100_input import raw_mode, cooked_mode
-
-__all__ = (
- 'Input',
- 'StdinInput',
- 'PipeInput',
-)
-
-
-class Input(with_metaclass(ABCMeta, object)):
- """
- Abstraction for any input.
-
- An instance of this class can be given to the constructor of a
- :class:`~prompt_toolkit.interface.CommandLineInterface` and will also be
- passed to the :class:`~prompt_toolkit.eventloop.base.EventLoop`.
- """
- @abstractmethod
- def fileno(self):
- """
- Fileno for putting this in an event loop.
- """
-
- @abstractmethod
- def read(self):
- """
- Return text from the input.
- """
-
- @abstractmethod
- def raw_mode(self):
- """
- Context manager that turns the input into raw mode.
- """
-
- @abstractmethod
- def cooked_mode(self):
- """
- Context manager that turns the input into cooked mode.
- """
-
-
-class StdinInput(Input):
- """
- Simple wrapper around stdin.
- """
- def __init__(self, stdin=None):
- self.stdin = stdin or sys.stdin
-
+import os
+import sys
+
+if is_windows():
+ from .terminal.win32_input import raw_mode, cooked_mode
+else:
+ from .terminal.vt100_input import raw_mode, cooked_mode
+
+__all__ = (
+ 'Input',
+ 'StdinInput',
+ 'PipeInput',
+)
+
+
+class Input(with_metaclass(ABCMeta, object)):
+ """
+ Abstraction for any input.
+
+ An instance of this class can be given to the constructor of a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` and will also be
+ passed to the :class:`~prompt_toolkit.eventloop.base.EventLoop`.
+ """
+ @abstractmethod
+ def fileno(self):
+ """
+ Fileno for putting this in an event loop.
+ """
+
+ @abstractmethod
+ def read(self):
+ """
+ Return text from the input.
+ """
+
+ @abstractmethod
+ def raw_mode(self):
+ """
+ Context manager that turns the input into raw mode.
+ """
+
+ @abstractmethod
+ def cooked_mode(self):
+ """
+ Context manager that turns the input into cooked mode.
+ """
+
+
+class StdinInput(Input):
+ """
+ Simple wrapper around stdin.
+ """
+ def __init__(self, stdin=None):
+ self.stdin = stdin or sys.stdin
+
# The input object should be a TTY.
assert self.stdin.isatty()
@@ -78,54 +78,54 @@ class StdinInput(Input):
else:
raise io.UnsupportedOperation('Stdin is not a terminal.')
- def __repr__(self):
- return 'StdinInput(stdin=%r)' % (self.stdin,)
-
- def raw_mode(self):
- return raw_mode(self.stdin.fileno())
-
- def cooked_mode(self):
- return cooked_mode(self.stdin.fileno())
-
- def fileno(self):
- return self.stdin.fileno()
-
- def read(self):
- return self.stdin.read()
-
-
-class PipeInput(Input):
- """
- Input that is send through a pipe.
- This is useful if we want to send the input programatically into the
- interface, but still use the eventloop.
-
- Usage::
-
- input = PipeInput()
- input.send('inputdata')
- """
- def __init__(self):
- self._r, self._w = os.pipe()
-
- def fileno(self):
- return self._r
-
- def read(self):
- return os.read(self._r)
-
+ def __repr__(self):
+ return 'StdinInput(stdin=%r)' % (self.stdin,)
+
+ def raw_mode(self):
+ return raw_mode(self.stdin.fileno())
+
+ def cooked_mode(self):
+ return cooked_mode(self.stdin.fileno())
+
+ def fileno(self):
+ return self.stdin.fileno()
+
+ def read(self):
+ return self.stdin.read()
+
+
+class PipeInput(Input):
+ """
+ Input that is send through a pipe.
+ This is useful if we want to send the input programatically into the
+ interface, but still use the eventloop.
+
+ Usage::
+
+ input = PipeInput()
+ input.send('inputdata')
+ """
+ def __init__(self):
+ self._r, self._w = os.pipe()
+
+ def fileno(self):
+ return self._r
+
+ def read(self):
+ return os.read(self._r)
+
def send_text(self, data):
" Send text to the input. "
- os.write(self._w, data.encode('utf-8'))
-
+ os.write(self._w, data.encode('utf-8'))
+
# Deprecated alias for `send_text`.
send = send_text
- def raw_mode(self):
- return DummyContext()
-
- def cooked_mode(self):
- return DummyContext()
+ def raw_mode(self):
+ return DummyContext()
+
+ def cooked_mode(self):
+ return DummyContext()
def close(self):
" Close pipe fds. "
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py
index 0632fa4c1ae..e1e0e563930 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/interface.py
@@ -1,89 +1,89 @@
-"""
-The main `CommandLineInterface` class and logic.
-"""
-from __future__ import unicode_literals
-
-import functools
-import os
-import signal
-import six
-import sys
-import textwrap
-import threading
+"""
+The main `CommandLineInterface` class and logic.
+"""
+from __future__ import unicode_literals
+
+import functools
+import os
+import signal
+import six
+import sys
+import textwrap
+import threading
import time
import types
-import weakref
-
+import weakref
+
from subprocess import Popen
-from .application import Application, AbortAction
-from .buffer import Buffer
-from .buffer_mapping import BufferMapping
+from .application import Application, AbortAction
+from .buffer import Buffer
+from .buffer_mapping import BufferMapping
from .completion import CompleteEvent, get_common_complete_suffix
-from .enums import SEARCH_BUFFER
-from .eventloop.base import EventLoop
-from .eventloop.callbacks import EventLoopCallbacks
-from .filters import Condition
-from .input import StdinInput, Input
-from .key_binding.input_processor import InputProcessor
+from .enums import SEARCH_BUFFER
+from .eventloop.base import EventLoop
+from .eventloop.callbacks import EventLoopCallbacks
+from .filters import Condition
+from .input import StdinInput, Input
+from .key_binding.input_processor import InputProcessor
from .key_binding.input_processor import KeyPress
from .key_binding.registry import Registry
from .key_binding.vi_state import ViState
from .keys import Keys
-from .output import Output
-from .renderer import Renderer, print_tokens
-from .search_state import SearchState
+from .output import Output
+from .renderer import Renderer, print_tokens
+from .search_state import SearchState
from .utils import Event
-
-# Following import is required for backwards compatibility.
-from .buffer import AcceptAction
-
-__all__ = (
- 'AbortAction',
- 'CommandLineInterface',
-)
-
-
-class CommandLineInterface(object):
- """
- Wrapper around all the other classes, tying everything together.
-
- Typical usage::
-
- application = Application(...)
- cli = CommandLineInterface(application, eventloop)
- result = cli.run()
- print(result)
-
- :param application: :class:`~prompt_toolkit.application.Application` instance.
- :param eventloop: The :class:`~prompt_toolkit.eventloop.base.EventLoop` to
+
+# Following import is required for backwards compatibility.
+from .buffer import AcceptAction
+
+__all__ = (
+ 'AbortAction',
+ 'CommandLineInterface',
+)
+
+
+class CommandLineInterface(object):
+ """
+ Wrapper around all the other classes, tying everything together.
+
+ Typical usage::
+
+ application = Application(...)
+ cli = CommandLineInterface(application, eventloop)
+ result = cli.run()
+ print(result)
+
+ :param application: :class:`~prompt_toolkit.application.Application` instance.
+ :param eventloop: The :class:`~prompt_toolkit.eventloop.base.EventLoop` to
be used when `run` is called. The easiest way to create
an eventloop is by calling
:meth:`~prompt_toolkit.shortcuts.create_eventloop`.
- :param input: :class:`~prompt_toolkit.input.Input` instance.
- :param output: :class:`~prompt_toolkit.output.Output` instance. (Probably
- Vt100_Output or Win32Output.)
- """
- def __init__(self, application, eventloop=None, input=None, output=None):
- assert isinstance(application, Application)
+ :param input: :class:`~prompt_toolkit.input.Input` instance.
+ :param output: :class:`~prompt_toolkit.output.Output` instance. (Probably
+ Vt100_Output or Win32Output.)
+ """
+ def __init__(self, application, eventloop=None, input=None, output=None):
+ assert isinstance(application, Application)
assert isinstance(eventloop, EventLoop), 'Passing an eventloop is required.'
- assert output is None or isinstance(output, Output)
- assert input is None or isinstance(input, Input)
-
+ assert output is None or isinstance(output, Output)
+ assert input is None or isinstance(input, Input)
+
from .shortcuts import create_output
-
- self.application = application
+
+ self.application = application
self.eventloop = eventloop
- self._is_running = False
-
- # Inputs and outputs.
- self.output = output or create_output()
- self.input = input or StdinInput(sys.stdin)
-
- #: The input buffers.
- assert isinstance(application.buffers, BufferMapping)
- self.buffers = application.buffers
-
+ self._is_running = False
+
+ # Inputs and outputs.
+ self.output = output or create_output()
+ self.input = input or StdinInput(sys.stdin)
+
+ #: The input buffers.
+ assert isinstance(application.buffers, BufferMapping)
+ self.buffers = application.buffers
+
#: EditingMode.VI or EditingMode.EMACS
self.editing_mode = application.editing_mode
@@ -93,38 +93,38 @@ class CommandLineInterface(object):
#: Vi state. (For Vi key bindings.)
self.vi_state = ViState()
- #: The `Renderer` instance.
- # Make sure that the same stdout is used, when a custom renderer has been passed.
- self.renderer = Renderer(
- self.application.style,
- self.output,
- use_alternate_screen=application.use_alternate_screen,
- mouse_support=application.mouse_support)
-
- #: Render counter. This one is increased every time the UI is rendered.
- #: It can be used as a key for caching certain information during one
- #: rendering.
- self.render_counter = 0
-
- #: When there is high CPU, postpone the renderering max x seconds.
- #: '0' means: don't postpone. '.5' means: try to draw at least twice a second.
- self.max_render_postpone_time = 0 # E.g. .5
-
- # Invalidate flag. When 'True', a repaint has been scheduled.
- self._invalidated = False
-
- #: The `InputProcessor` instance.
- self.input_processor = InputProcessor(application.key_bindings_registry, weakref.ref(self))
-
- self._async_completers = {} # Map buffer name to completer function.
-
- # Pointer to sub CLI. (In chain of CLI instances.)
- self._sub_cli = None # None or other CommandLineInterface instance.
-
- # Call `add_buffer` for each buffer.
- for name, b in self.buffers.items():
- self.add_buffer(name, b)
-
+ #: The `Renderer` instance.
+ # Make sure that the same stdout is used, when a custom renderer has been passed.
+ self.renderer = Renderer(
+ self.application.style,
+ self.output,
+ use_alternate_screen=application.use_alternate_screen,
+ mouse_support=application.mouse_support)
+
+ #: Render counter. This one is increased every time the UI is rendered.
+ #: It can be used as a key for caching certain information during one
+ #: rendering.
+ self.render_counter = 0
+
+ #: When there is high CPU, postpone the renderering max x seconds.
+ #: '0' means: don't postpone. '.5' means: try to draw at least twice a second.
+ self.max_render_postpone_time = 0 # E.g. .5
+
+ # Invalidate flag. When 'True', a repaint has been scheduled.
+ self._invalidated = False
+
+ #: The `InputProcessor` instance.
+ self.input_processor = InputProcessor(application.key_bindings_registry, weakref.ref(self))
+
+ self._async_completers = {} # Map buffer name to completer function.
+
+ # Pointer to sub CLI. (In chain of CLI instances.)
+ self._sub_cli = None # None or other CommandLineInterface instance.
+
+ # Call `add_buffer` for each buffer.
+ for name, b in self.buffers.items():
+ self.add_buffer(name, b)
+
# Events.
self.on_buffer_changed = Event(self, application.on_buffer_changed)
self.on_initialize = Event(self, application.on_initialize)
@@ -134,59 +134,59 @@ class CommandLineInterface(object):
self.on_reset = Event(self, application.on_reset)
self.on_start = Event(self, application.on_start)
self.on_stop = Event(self, application.on_stop)
-
- # Trigger initialize callback.
+
+ # Trigger initialize callback.
self.reset()
self.on_initialize += self.application.on_initialize
self.on_initialize.fire()
-
- @property
- def layout(self):
- return self.application.layout
-
- @property
- def clipboard(self):
- return self.application.clipboard
-
+
+ @property
+ def layout(self):
+ return self.application.layout
+
+ @property
+ def clipboard(self):
+ return self.application.clipboard
+
@property
def pre_run_callables(self):
return self.application.pre_run_callables
- def add_buffer(self, name, buffer, focus=False):
- """
- Insert a new buffer.
- """
- assert isinstance(buffer, Buffer)
- self.buffers[name] = buffer
-
- if focus:
- self.buffers.focus(name)
-
- # Create asynchronous completer / auto suggestion.
- auto_suggest_function = self._create_auto_suggest_function(buffer)
- completer_function = self._create_async_completer(buffer)
- self._async_completers[name] = completer_function
-
- # Complete/suggest on text insert.
- def create_on_insert_handler():
- """
- Wrapper around the asynchronous completer and auto suggestion, that
- ensures that it's only called while typing if the
- `complete_while_typing` filter is enabled.
- """
+ def add_buffer(self, name, buffer, focus=False):
+ """
+ Insert a new buffer.
+ """
+ assert isinstance(buffer, Buffer)
+ self.buffers[name] = buffer
+
+ if focus:
+ self.buffers.focus(name)
+
+ # Create asynchronous completer / auto suggestion.
+ auto_suggest_function = self._create_auto_suggest_function(buffer)
+ completer_function = self._create_async_completer(buffer)
+ self._async_completers[name] = completer_function
+
+ # Complete/suggest on text insert.
+ def create_on_insert_handler():
+ """
+ Wrapper around the asynchronous completer and auto suggestion, that
+ ensures that it's only called while typing if the
+ `complete_while_typing` filter is enabled.
+ """
def on_text_insert(_):
- # Only complete when "complete_while_typing" is enabled.
- if buffer.completer and buffer.complete_while_typing():
- completer_function()
-
- # Call auto_suggest.
- if buffer.auto_suggest:
- auto_suggest_function()
-
- return on_text_insert
-
- buffer.on_text_insert += create_on_insert_handler()
-
+ # Only complete when "complete_while_typing" is enabled.
+ if buffer.completer and buffer.complete_while_typing():
+ completer_function()
+
+ # Call auto_suggest.
+ if buffer.auto_suggest:
+ auto_suggest_function()
+
+ return on_text_insert
+
+ buffer.on_text_insert += create_on_insert_handler()
+
def buffer_changed(_):
"""
When the text in a buffer changes.
@@ -199,140 +199,140 @@ class CommandLineInterface(object):
buffer.on_text_changed += buffer_changed
- def start_completion(self, buffer_name=None, select_first=False,
- select_last=False, insert_common_part=False,
- complete_event=None):
- """
- Start asynchronous autocompletion of this buffer.
- (This will do nothing if a previous completion was still in progress.)
- """
- buffer_name = buffer_name or self.current_buffer_name
- completer = self._async_completers.get(buffer_name)
-
- if completer:
- completer(select_first=select_first,
- select_last=select_last,
- insert_common_part=insert_common_part,
- complete_event=CompleteEvent(completion_requested=True))
-
- @property
- def current_buffer_name(self):
- """
- The name of the current :class:`.Buffer`. (Or `None`.)
- """
- return self.buffers.current_name(self)
-
- @property
- def current_buffer(self):
- """
- The currently focussed :class:`~.Buffer`.
-
- (This returns a dummy :class:`.Buffer` when none of the actual buffers
- has the focus. In this case, it's really not practical to check for
- `None` values or catch exceptions every time.)
- """
- return self.buffers.current(self)
-
- def focus(self, buffer_name):
- """
- Focus the buffer with the given name on the focus stack.
- """
- self.buffers.focus(self, buffer_name)
-
- def push_focus(self, buffer_name):
- """
- Push to the focus stack.
- """
- self.buffers.push_focus(self, buffer_name)
-
- def pop_focus(self):
- """
- Pop from the focus stack.
- """
- self.buffers.pop_focus(self)
-
- @property
- def terminal_title(self):
- """
- Return the current title to be displayed in the terminal.
- When this in `None`, the terminal title remains the original.
- """
- result = self.application.get_title()
-
- # Make sure that this function returns a unicode object,
- # and not a byte string.
- assert result is None or isinstance(result, six.text_type)
- return result
-
- @property
- def is_searching(self):
- """
- True when we are searching.
- """
- return self.current_buffer_name == SEARCH_BUFFER
-
- def reset(self, reset_current_buffer=False):
- """
- Reset everything, for reading the next input.
-
+ def start_completion(self, buffer_name=None, select_first=False,
+ select_last=False, insert_common_part=False,
+ complete_event=None):
+ """
+ Start asynchronous autocompletion of this buffer.
+ (This will do nothing if a previous completion was still in progress.)
+ """
+ buffer_name = buffer_name or self.current_buffer_name
+ completer = self._async_completers.get(buffer_name)
+
+ if completer:
+ completer(select_first=select_first,
+ select_last=select_last,
+ insert_common_part=insert_common_part,
+ complete_event=CompleteEvent(completion_requested=True))
+
+ @property
+ def current_buffer_name(self):
+ """
+ The name of the current :class:`.Buffer`. (Or `None`.)
+ """
+ return self.buffers.current_name(self)
+
+ @property
+ def current_buffer(self):
+ """
+ The currently focussed :class:`~.Buffer`.
+
+ (This returns a dummy :class:`.Buffer` when none of the actual buffers
+ has the focus. In this case, it's really not practical to check for
+ `None` values or catch exceptions every time.)
+ """
+ return self.buffers.current(self)
+
+ def focus(self, buffer_name):
+ """
+ Focus the buffer with the given name on the focus stack.
+ """
+ self.buffers.focus(self, buffer_name)
+
+ def push_focus(self, buffer_name):
+ """
+ Push to the focus stack.
+ """
+ self.buffers.push_focus(self, buffer_name)
+
+ def pop_focus(self):
+ """
+ Pop from the focus stack.
+ """
+ self.buffers.pop_focus(self)
+
+ @property
+ def terminal_title(self):
+ """
+ Return the current title to be displayed in the terminal.
+ When this in `None`, the terminal title remains the original.
+ """
+ result = self.application.get_title()
+
+ # Make sure that this function returns a unicode object,
+ # and not a byte string.
+ assert result is None or isinstance(result, six.text_type)
+ return result
+
+ @property
+ def is_searching(self):
+ """
+ True when we are searching.
+ """
+ return self.current_buffer_name == SEARCH_BUFFER
+
+ def reset(self, reset_current_buffer=False):
+ """
+ Reset everything, for reading the next input.
+
:param reset_current_buffer: XXX: not used anymore. The reason for
having this option in the past was when this CommandLineInterface
is run multiple times, that we could reset the buffer content from
the previous run. This is now handled in the AcceptAction.
- """
- # Notice that we don't reset the buffers. (This happens just before
- # returning, and when we have multiple buffers, we clearly want the
- # content in the other buffers to remain unchanged between several
- # calls of `run`. (And the same is true for the focus stack.)
-
- self._exit_flag = False
- self._abort_flag = False
-
- self._return_value = None
-
- self.renderer.reset()
- self.input_processor.reset()
- self.layout.reset()
+ """
+ # Notice that we don't reset the buffers. (This happens just before
+ # returning, and when we have multiple buffers, we clearly want the
+ # content in the other buffers to remain unchanged between several
+ # calls of `run`. (And the same is true for the focus stack.)
+
+ self._exit_flag = False
+ self._abort_flag = False
+
+ self._return_value = None
+
+ self.renderer.reset()
+ self.input_processor.reset()
+ self.layout.reset()
self.vi_state.reset()
-
- # Search new search state. (Does also remember what has to be
- # highlighted.)
- self.search_state = SearchState(ignore_case=Condition(lambda: self.is_ignoring_case))
-
- # Trigger reset event.
+
+ # Search new search state. (Does also remember what has to be
+ # highlighted.)
+ self.search_state = SearchState(ignore_case=Condition(lambda: self.is_ignoring_case))
+
+ # Trigger reset event.
self.on_reset.fire()
-
- @property
- def in_paste_mode(self):
- """ True when we are in paste mode. """
- return self.application.paste_mode(self)
-
- @property
- def is_ignoring_case(self):
- """ True when we currently ignore casing. """
- return self.application.ignore_case(self)
-
- def invalidate(self):
- """
- Thread safe way of sending a repaint trigger to the input event loop.
- """
- # Never schedule a second redraw, when a previous one has not yet been
- # executed. (This should protect against other threads calling
- # 'invalidate' many times, resulting in 100% CPU.)
- if self._invalidated:
- return
- else:
- self._invalidated = True
-
- # Trigger event.
- self.on_invalidate.fire()
-
- if self.eventloop is not None:
- def redraw():
- self._invalidated = False
- self._redraw()
-
- # Call redraw in the eventloop (thread safe).
+
+ @property
+ def in_paste_mode(self):
+ """ True when we are in paste mode. """
+ return self.application.paste_mode(self)
+
+ @property
+ def is_ignoring_case(self):
+ """ True when we currently ignore casing. """
+ return self.application.ignore_case(self)
+
+ def invalidate(self):
+ """
+ Thread safe way of sending a repaint trigger to the input event loop.
+ """
+ # Never schedule a second redraw, when a previous one has not yet been
+ # executed. (This should protect against other threads calling
+ # 'invalidate' many times, resulting in 100% CPU.)
+ if self._invalidated:
+ return
+ else:
+ self._invalidated = True
+
+ # Trigger event.
+ self.on_invalidate.fire()
+
+ if self.eventloop is not None:
+ def redraw():
+ self._invalidated = False
+ self._redraw()
+
+ # Call redraw in the eventloop (thread safe).
# Usually with the high priority, in order to make the application
# feel responsive, but this can be tuned by changing the value of
# `max_render_postpone_time`.
@@ -340,38 +340,38 @@ class CommandLineInterface(object):
_max_postpone_until = time.time() + self.max_render_postpone_time
else:
_max_postpone_until = None
-
+
self.eventloop.call_from_executor(
redraw, _max_postpone_until=_max_postpone_until)
- # Depracated alias for 'invalidate'.
- request_redraw = invalidate
-
- def _redraw(self):
- """
- Render the command line again. (Not thread safe!) (From other threads,
- or if unsure, use :meth:`.CommandLineInterface.invalidate`.)
- """
- # Only draw when no sub application was started.
- if self._is_running and self._sub_cli is None:
- self.render_counter += 1
- self.renderer.render(self, self.layout, is_done=self.is_done)
-
+ # Depracated alias for 'invalidate'.
+ request_redraw = invalidate
+
+ def _redraw(self):
+ """
+ Render the command line again. (Not thread safe!) (From other threads,
+ or if unsure, use :meth:`.CommandLineInterface.invalidate`.)
+ """
+ # Only draw when no sub application was started.
+ if self._is_running and self._sub_cli is None:
+ self.render_counter += 1
+ self.renderer.render(self, self.layout, is_done=self.is_done)
+
# Fire render event.
self.on_render.fire()
- def _on_resize(self):
- """
- When the window size changes, we erase the current output and request
- again the cursor position. When the CPR answer arrives, the output is
- drawn again.
- """
- # Erase, request position (when cursor is at the start position)
- # and redraw again. -- The order is important.
+ def _on_resize(self):
+ """
+ When the window size changes, we erase the current output and request
+ again the cursor position. When the CPR answer arrives, the output is
+ drawn again.
+ """
+ # Erase, request position (when cursor is at the start position)
+ # and redraw again. -- The order is important.
self.renderer.erase(leave_alternate_screen=False, erase_title=False)
- self.renderer.request_absolute_cursor_position()
- self._redraw()
-
+ self.renderer.request_absolute_cursor_position()
+ self._redraw()
+
def _load_next_buffer_indexes(self):
for buff, index in self._next_buffer_indexes.items():
if buff in self.buffers:
@@ -388,34 +388,34 @@ class CommandLineInterface(object):
del self.pre_run_callables[:]
def run(self, reset_current_buffer=False, pre_run=None):
- """
- Read input from the command line.
- This runs the eventloop until a return value has been set.
-
+ """
+ Read input from the command line.
+ This runs the eventloop until a return value has been set.
+
:param reset_current_buffer: XXX: Not used anymore.
- :param pre_run: Callable that is called right after the reset has taken
- place. This allows custom initialisation.
- """
- assert pre_run is None or callable(pre_run)
-
- try:
- self._is_running = True
-
+ :param pre_run: Callable that is called right after the reset has taken
+ place. This allows custom initialisation.
+ """
+ assert pre_run is None or callable(pre_run)
+
+ try:
+ self._is_running = True
+
self.on_start.fire()
self.reset()
-
- # Call pre_run.
+
+ # Call pre_run.
self._pre_run(pre_run)
-
- # Run eventloop in raw mode.
- with self.input.raw_mode():
- self.renderer.request_absolute_cursor_position()
- self._redraw()
-
- self.eventloop.run(self.input, self.create_eventloop_callbacks())
- finally:
- # Clean up renderer. (This will leave the alternate screen, if we use
- # that.)
+
+ # Run eventloop in raw mode.
+ with self.input.raw_mode():
+ self.renderer.request_absolute_cursor_position()
+ self._redraw()
+
+ self.eventloop.run(self.input, self.create_eventloop_callbacks())
+ finally:
+ # Clean up renderer. (This will leave the alternate screen, if we use
+ # that.)
# If exit/abort haven't been called set, but another exception was
# thrown instead for some reason, make sure that we redraw in exit
@@ -424,48 +424,48 @@ class CommandLineInterface(object):
self._exit_flag = True
self._redraw()
- self.renderer.reset()
+ self.renderer.reset()
self.on_stop.fire()
- self._is_running = False
-
- # Return result.
- return self.return_value()
-
- try:
- # The following `run_async` function is compiled at runtime
- # because it contains syntax which is not supported on older Python
- # versions. (A 'return' inside a generator.)
- six.exec_(textwrap.dedent('''
- def run_async(self, reset_current_buffer=True, pre_run=None):
- """
- Same as `run`, but this returns a coroutine.
-
- This is only available on Python >3.3, with asyncio.
- """
+ self._is_running = False
+
+ # Return result.
+ return self.return_value()
+
+ try:
+ # The following `run_async` function is compiled at runtime
+ # because it contains syntax which is not supported on older Python
+ # versions. (A 'return' inside a generator.)
+ six.exec_(textwrap.dedent('''
+ def run_async(self, reset_current_buffer=True, pre_run=None):
+ """
+ Same as `run`, but this returns a coroutine.
+
+ This is only available on Python >3.3, with asyncio.
+ """
# Inline import, because it slows down startup when asyncio is not
# needed.
import asyncio
-
+
@asyncio.coroutine
def run():
assert pre_run is None or callable(pre_run)
-
+
try:
self._is_running = True
-
+
self.on_start.fire()
self.reset()
-
+
# Call pre_run.
self._pre_run(pre_run)
-
+
with self.input.raw_mode():
self.renderer.request_absolute_cursor_position()
self._redraw()
-
+
yield from self.eventloop.run_as_coroutine(
self.input, self.create_eventloop_callbacks())
-
+
return self.return_value()
finally:
if not self.is_done:
@@ -477,181 +477,181 @@ class CommandLineInterface(object):
self._is_running = False
return run()
- '''))
- except SyntaxError:
- # Python2, or early versions of Python 3.
- def run_async(self, reset_current_buffer=True, pre_run=None):
- """
- Same as `run`, but this returns a coroutine.
-
- This is only available on Python >3.3, with asyncio.
- """
- raise NotImplementedError
-
+ '''))
+ except SyntaxError:
+ # Python2, or early versions of Python 3.
+ def run_async(self, reset_current_buffer=True, pre_run=None):
+ """
+ Same as `run`, but this returns a coroutine.
+
+ This is only available on Python >3.3, with asyncio.
+ """
+ raise NotImplementedError
+
def run_sub_application(self, application, done_callback=None, erase_when_done=False,
_from_application_generator=False):
# `erase_when_done` is deprecated, set Application.erase_when_done instead.
- """
- Run a sub :class:`~prompt_toolkit.application.Application`.
-
- This will suspend the main application and display the sub application
- until that one returns a value. The value is returned by calling
- `done_callback` with the result.
-
- The sub application will share the same I/O of the main application.
- That means, it uses the same input and output channels and it shares
- the same event loop.
-
- .. note:: Technically, it gets another Eventloop instance, but that is
- only a proxy to our main event loop. The reason is that calling
- 'stop' --which returns the result of an application when it's
- done-- is handled differently.
- """
- assert isinstance(application, Application)
- assert done_callback is None or callable(done_callback)
-
- if self._sub_cli is not None:
- raise RuntimeError('Another sub application started already.')
-
- # Erase current application.
+ """
+ Run a sub :class:`~prompt_toolkit.application.Application`.
+
+ This will suspend the main application and display the sub application
+ until that one returns a value. The value is returned by calling
+ `done_callback` with the result.
+
+ The sub application will share the same I/O of the main application.
+ That means, it uses the same input and output channels and it shares
+ the same event loop.
+
+ .. note:: Technically, it gets another Eventloop instance, but that is
+ only a proxy to our main event loop. The reason is that calling
+ 'stop' --which returns the result of an application when it's
+ done-- is handled differently.
+ """
+ assert isinstance(application, Application)
+ assert done_callback is None or callable(done_callback)
+
+ if self._sub_cli is not None:
+ raise RuntimeError('Another sub application started already.')
+
+ # Erase current application.
if not _from_application_generator:
self.renderer.erase()
-
- # Callback when the sub app is done.
- def done():
- # Redraw sub app in done state.
- # and reset the renderer. (This reset will also quit the alternate
- # screen, if the sub application used that.)
- sub_cli._redraw()
+
+ # Callback when the sub app is done.
+ def done():
+ # Redraw sub app in done state.
+ # and reset the renderer. (This reset will also quit the alternate
+ # screen, if the sub application used that.)
+ sub_cli._redraw()
if erase_when_done or application.erase_when_done:
sub_cli.renderer.erase()
- sub_cli.renderer.reset()
- sub_cli._is_running = False # Don't render anymore.
-
- self._sub_cli = None
-
- # Restore main application.
+ sub_cli.renderer.reset()
+ sub_cli._is_running = False # Don't render anymore.
+
+ self._sub_cli = None
+
+ # Restore main application.
if not _from_application_generator:
self.renderer.request_absolute_cursor_position()
self._redraw()
-
- # Deliver result.
- if done_callback:
- done_callback(sub_cli.return_value())
-
- # Create sub CommandLineInterface.
- sub_cli = CommandLineInterface(
- application=application,
- eventloop=_SubApplicationEventLoop(self, done),
- input=self.input,
- output=self.output)
- sub_cli._is_running = True # Allow rendering of sub app.
-
- sub_cli._redraw()
- self._sub_cli = sub_cli
-
- def exit(self):
- """
- Set exit. When Control-D has been pressed.
- """
- on_exit = self.application.on_exit
- self._exit_flag = True
- self._redraw()
-
- if on_exit == AbortAction.RAISE_EXCEPTION:
- def eof_error():
- raise EOFError()
- self._set_return_callable(eof_error)
-
- elif on_exit == AbortAction.RETRY:
- self.reset()
- self.renderer.request_absolute_cursor_position()
- self.current_buffer.reset()
-
- elif on_exit == AbortAction.RETURN_NONE:
- self.set_return_value(None)
-
- def abort(self):
- """
- Set abort. When Control-C has been pressed.
- """
- on_abort = self.application.on_abort
- self._abort_flag = True
- self._redraw()
-
- if on_abort == AbortAction.RAISE_EXCEPTION:
- def keyboard_interrupt():
- raise KeyboardInterrupt()
- self._set_return_callable(keyboard_interrupt)
-
- elif on_abort == AbortAction.RETRY:
- self.reset()
- self.renderer.request_absolute_cursor_position()
- self.current_buffer.reset()
-
- elif on_abort == AbortAction.RETURN_NONE:
- self.set_return_value(None)
-
- # Deprecated aliase for exit/abort.
- set_exit = exit
- set_abort = abort
-
- def set_return_value(self, document):
- """
- Set a return value. The eventloop can retrieve the result it by calling
- `return_value`.
- """
- self._set_return_callable(lambda: document)
- self._redraw() # Redraw in "done" state, after the return value has been set.
-
- def _set_return_callable(self, value):
- assert callable(value)
- self._return_value = value
-
- if self.eventloop:
- self.eventloop.stop()
-
+
+ # Deliver result.
+ if done_callback:
+ done_callback(sub_cli.return_value())
+
+ # Create sub CommandLineInterface.
+ sub_cli = CommandLineInterface(
+ application=application,
+ eventloop=_SubApplicationEventLoop(self, done),
+ input=self.input,
+ output=self.output)
+ sub_cli._is_running = True # Allow rendering of sub app.
+
+ sub_cli._redraw()
+ self._sub_cli = sub_cli
+
+ def exit(self):
+ """
+ Set exit. When Control-D has been pressed.
+ """
+ on_exit = self.application.on_exit
+ self._exit_flag = True
+ self._redraw()
+
+ if on_exit == AbortAction.RAISE_EXCEPTION:
+ def eof_error():
+ raise EOFError()
+ self._set_return_callable(eof_error)
+
+ elif on_exit == AbortAction.RETRY:
+ self.reset()
+ self.renderer.request_absolute_cursor_position()
+ self.current_buffer.reset()
+
+ elif on_exit == AbortAction.RETURN_NONE:
+ self.set_return_value(None)
+
+ def abort(self):
+ """
+ Set abort. When Control-C has been pressed.
+ """
+ on_abort = self.application.on_abort
+ self._abort_flag = True
+ self._redraw()
+
+ if on_abort == AbortAction.RAISE_EXCEPTION:
+ def keyboard_interrupt():
+ raise KeyboardInterrupt()
+ self._set_return_callable(keyboard_interrupt)
+
+ elif on_abort == AbortAction.RETRY:
+ self.reset()
+ self.renderer.request_absolute_cursor_position()
+ self.current_buffer.reset()
+
+ elif on_abort == AbortAction.RETURN_NONE:
+ self.set_return_value(None)
+
+ # Deprecated aliase for exit/abort.
+ set_exit = exit
+ set_abort = abort
+
+ def set_return_value(self, document):
+ """
+ Set a return value. The eventloop can retrieve the result it by calling
+ `return_value`.
+ """
+ self._set_return_callable(lambda: document)
+ self._redraw() # Redraw in "done" state, after the return value has been set.
+
+ def _set_return_callable(self, value):
+ assert callable(value)
+ self._return_value = value
+
+ if self.eventloop:
+ self.eventloop.stop()
+
def run_in_terminal(self, func, render_cli_done=False, cooked_mode=True):
- """
- Run function on the terminal above the prompt.
-
- What this does is first hiding the prompt, then running this callable
- (which can safely output to the terminal), and then again rendering the
- prompt which causes the output of this function to scroll above the
- prompt.
-
- :param func: The callable to execute.
- :param render_cli_done: When True, render the interface in the
- 'Done' state first, then execute the function. If False,
- erase the interface first.
+ """
+ Run function on the terminal above the prompt.
+
+ What this does is first hiding the prompt, then running this callable
+ (which can safely output to the terminal), and then again rendering the
+ prompt which causes the output of this function to scroll above the
+ prompt.
+
+ :param func: The callable to execute.
+ :param render_cli_done: When True, render the interface in the
+ 'Done' state first, then execute the function. If False,
+ erase the interface first.
:param cooked_mode: When True (the default), switch the input to
cooked mode while executing the function.
-
- :returns: the result of `func`.
- """
- # Draw interface in 'done' state, or erase.
- if render_cli_done:
- self._return_value = True
- self._redraw()
- self.renderer.reset() # Make sure to disable mouse mode, etc...
- else:
- self.renderer.erase()
+
+ :returns: the result of `func`.
+ """
+ # Draw interface in 'done' state, or erase.
+ if render_cli_done:
+ self._return_value = True
+ self._redraw()
+ self.renderer.reset() # Make sure to disable mouse mode, etc...
+ else:
+ self.renderer.erase()
self._return_value = None
-
- # Run system command.
+
+ # Run system command.
if cooked_mode:
with self.input.cooked_mode():
result = func()
else:
- result = func()
-
- # Redraw interface again.
- self.renderer.reset()
- self.renderer.request_absolute_cursor_position()
- self._redraw()
-
- return result
-
+ result = func()
+
+ # Redraw interface again.
+ self.renderer.reset()
+ self.renderer.request_absolute_cursor_position()
+ self._redraw()
+
+ return result
+
def run_application_generator(self, coroutine, render_cli_done=False):
"""
EXPERIMENTAL
@@ -709,13 +709,13 @@ class CommandLineInterface(object):
# Start processing coroutine.
step_next()
- def run_system_command(self, command):
- """
- Run system command (While hiding the prompt. When finished, all the
- output will scroll above the prompt.)
-
- :param command: Shell command to be executed.
- """
+ def run_system_command(self, command):
+ """
+ Run system command (While hiding the prompt. When finished, all the
+ output will scroll above the prompt.)
+
+ :param command: Shell command to be executed.
+ """
def wait_for_enter():
"""
Create a sub application to wait for the enter key press.
@@ -737,10 +737,10 @@ class CommandLineInterface(object):
key_bindings_registry=registry)
self.run_sub_application(application)
- def run():
+ def run():
# Try to use the same input/output file descriptors as the one,
# used to run this application.
- try:
+ try:
input_fd = self.input.fileno()
except AttributeError:
input_fd = sys.stdin.fileno()
@@ -748,7 +748,7 @@ class CommandLineInterface(object):
output_fd = self.output.fileno()
except AttributeError:
output_fd = sys.stdout.fileno()
-
+
# Run sub process.
# XXX: This will still block the event loop.
p = Popen(command, shell=True,
@@ -758,23 +758,23 @@ class CommandLineInterface(object):
# Wait for the user to press enter.
wait_for_enter()
- self.run_in_terminal(run)
-
+ self.run_in_terminal(run)
+
def suspend_to_background(self, suspend_group=True):
- """
- (Not thread safe -- to be called from inside the key bindings.)
- Suspend process.
+ """
+ (Not thread safe -- to be called from inside the key bindings.)
+ Suspend process.
:param suspend_group: When true, suspend the whole process group.
(This is the default, and probably what you want.)
- """
- # Only suspend when the opperating system supports it.
- # (Not on Windows.)
- if hasattr(signal, 'SIGTSTP'):
- def run():
- # Send `SIGSTP` to own process.
- # This will cause it to suspend.
-
+ """
+ # Only suspend when the opperating system supports it.
+ # (Not on Windows.)
+ if hasattr(signal, 'SIGTSTP'):
+ def run():
+ # Send `SIGSTP` to own process.
+ # This will cause it to suspend.
+
# Usually we want the whole process group to be suspended. This
# handles the case when input is piped from another process.
if suspend_group:
@@ -782,59 +782,59 @@ class CommandLineInterface(object):
else:
os.kill(os.getpid(), signal.SIGTSTP)
- self.run_in_terminal(run)
-
- def print_tokens(self, tokens, style=None):
- """
- Print a list of (Token, text) tuples to the output.
- (When the UI is running, this method has to be called through
- `run_in_terminal`, otherwise it will destroy the UI.)
-
- :param style: Style class to use. Defaults to the active style in the CLI.
- """
- print_tokens(self.output, tokens, style or self.application.style)
-
- @property
- def is_exiting(self):
- """
- ``True`` when the exit flag as been set.
- """
- return self._exit_flag
-
- @property
- def is_aborting(self):
- """
- ``True`` when the abort flag as been set.
- """
- return self._abort_flag
-
- @property
- def is_returning(self):
- """
- ``True`` when a return value has been set.
- """
- return self._return_value is not None
-
- def return_value(self):
- """
- Get the return value. Not that this method can throw an exception.
- """
- # Note that it's a method, not a property, because it can throw
- # exceptions.
- if self._return_value:
- return self._return_value()
-
- @property
- def is_done(self):
- return self.is_exiting or self.is_aborting or self.is_returning
-
- def _create_async_completer(self, buffer):
- """
- Create function for asynchronous autocompletion.
- (Autocomplete in other thread.)
- """
- complete_thread_running = [False] # By ref.
-
+ self.run_in_terminal(run)
+
+ def print_tokens(self, tokens, style=None):
+ """
+ Print a list of (Token, text) tuples to the output.
+ (When the UI is running, this method has to be called through
+ `run_in_terminal`, otherwise it will destroy the UI.)
+
+ :param style: Style class to use. Defaults to the active style in the CLI.
+ """
+ print_tokens(self.output, tokens, style or self.application.style)
+
+ @property
+ def is_exiting(self):
+ """
+ ``True`` when the exit flag as been set.
+ """
+ return self._exit_flag
+
+ @property
+ def is_aborting(self):
+ """
+ ``True`` when the abort flag as been set.
+ """
+ return self._abort_flag
+
+ @property
+ def is_returning(self):
+ """
+ ``True`` when a return value has been set.
+ """
+ return self._return_value is not None
+
+ def return_value(self):
+ """
+ Get the return value. Not that this method can throw an exception.
+ """
+ # Note that it's a method, not a property, because it can throw
+ # exceptions.
+ if self._return_value:
+ return self._return_value()
+
+ @property
+ def is_done(self):
+ return self.is_exiting or self.is_aborting or self.is_returning
+
+ def _create_async_completer(self, buffer):
+ """
+ Create function for asynchronous autocompletion.
+ (Autocomplete in other thread.)
+ """
+ complete_thread_running = [False] # By ref.
+
def completion_does_nothing(document, completion):
"""
Return `True` if applying this completion doesn't have any effect.
@@ -845,32 +845,32 @@ class CommandLineInterface(object):
len(text_before_cursor) + completion.start_position:]
return replaced_text == completion.text
- def async_completer(select_first=False, select_last=False,
- insert_common_part=False, complete_event=None):
- document = buffer.document
- complete_event = complete_event or CompleteEvent(text_inserted=True)
-
- # Don't start two threads at the same time.
- if complete_thread_running[0]:
- return
-
- # Don't complete when we already have completions.
- if buffer.complete_state or not buffer.completer:
- return
-
- # Otherwise, get completions in other thread.
- complete_thread_running[0] = True
-
- def run():
- completions = list(buffer.completer.get_completions(document, complete_event))
-
- def callback():
- """
- Set the new complete_state in a safe way. Don't replace an
- existing complete_state if we had one. (The user could have
- pressed 'Tab' in the meantime. Also don't set it if the text
- was changed in the meantime.
- """
+ def async_completer(select_first=False, select_last=False,
+ insert_common_part=False, complete_event=None):
+ document = buffer.document
+ complete_event = complete_event or CompleteEvent(text_inserted=True)
+
+ # Don't start two threads at the same time.
+ if complete_thread_running[0]:
+ return
+
+ # Don't complete when we already have completions.
+ if buffer.complete_state or not buffer.completer:
+ return
+
+ # Otherwise, get completions in other thread.
+ complete_thread_running[0] = True
+
+ def run():
+ completions = list(buffer.completer.get_completions(document, complete_event))
+
+ def callback():
+ """
+ Set the new complete_state in a safe way. Don't replace an
+ existing complete_state if we had one. (The user could have
+ pressed 'Tab' in the meantime. Also don't set it if the text
+ was changed in the meantime.
+ """
complete_thread_running[0] = False
# When there is only one completion, which has nothing to add, ignore it.
@@ -878,21 +878,21 @@ class CommandLineInterface(object):
completion_does_nothing(document, completions[0])):
del completions[:]
- # Set completions if the text was not yet changed.
- if buffer.text == document.text and \
- buffer.cursor_position == document.cursor_position and \
- not buffer.complete_state:
-
- set_completions = True
- select_first_anyway = False
-
+ # Set completions if the text was not yet changed.
+ if buffer.text == document.text and \
+ buffer.cursor_position == document.cursor_position and \
+ not buffer.complete_state:
+
+ set_completions = True
+ select_first_anyway = False
+
# When the common part has to be inserted, and there
- # is a common part.
- if insert_common_part:
- common_part = get_common_complete_suffix(document, completions)
- if common_part:
+ # is a common part.
+ if insert_common_part:
+ common_part = get_common_complete_suffix(document, completions)
+ if common_part:
# Insert the common part, update completions.
- buffer.insert_text(common_part)
+ buffer.insert_text(common_part)
if len(completions) > 1:
# (Don't call `async_completer` again, but
# recalculate completions. See:
@@ -902,289 +902,289 @@ class CommandLineInterface(object):
for c in completions]
else:
set_completions = False
- else:
- # When we were asked to insert the "common"
- # prefix, but there was no common suffix but
- # still exactly one match, then select the
- # first. (It could be that we have a completion
+ else:
+ # When we were asked to insert the "common"
+ # prefix, but there was no common suffix but
+ # still exactly one match, then select the
+ # first. (It could be that we have a completion
# which does * expansion, like '*.py', with
- # exactly one match.)
- if len(completions) == 1:
- select_first_anyway = True
-
- if set_completions:
- buffer.set_completions(
- completions=completions,
- go_to_first=select_first or select_first_anyway,
- go_to_last=select_last)
- self.invalidate()
+ # exactly one match.)
+ if len(completions) == 1:
+ select_first_anyway = True
+
+ if set_completions:
+ buffer.set_completions(
+ completions=completions,
+ go_to_first=select_first or select_first_anyway,
+ go_to_last=select_last)
+ self.invalidate()
elif not buffer.complete_state:
- # Otherwise, restart thread.
- async_completer()
-
- if self.eventloop:
- self.eventloop.call_from_executor(callback)
-
- self.eventloop.run_in_executor(run)
- return async_completer
-
- def _create_auto_suggest_function(self, buffer):
- """
- Create function for asynchronous auto suggestion.
- (AutoSuggest in other thread.)
- """
- suggest_thread_running = [False] # By ref.
-
- def async_suggestor():
- document = buffer.document
-
- # Don't start two threads at the same time.
- if suggest_thread_running[0]:
- return
-
- # Don't suggest when we already have a suggestion.
- if buffer.suggestion or not buffer.auto_suggest:
- return
-
- # Otherwise, get completions in other thread.
- suggest_thread_running[0] = True
-
- def run():
- suggestion = buffer.auto_suggest.get_suggestion(self, buffer, document)
-
- def callback():
+ # Otherwise, restart thread.
+ async_completer()
+
+ if self.eventloop:
+ self.eventloop.call_from_executor(callback)
+
+ self.eventloop.run_in_executor(run)
+ return async_completer
+
+ def _create_auto_suggest_function(self, buffer):
+ """
+ Create function for asynchronous auto suggestion.
+ (AutoSuggest in other thread.)
+ """
+ suggest_thread_running = [False] # By ref.
+
+ def async_suggestor():
+ document = buffer.document
+
+ # Don't start two threads at the same time.
+ if suggest_thread_running[0]:
+ return
+
+ # Don't suggest when we already have a suggestion.
+ if buffer.suggestion or not buffer.auto_suggest:
+ return
+
+ # Otherwise, get completions in other thread.
+ suggest_thread_running[0] = True
+
+ def run():
+ suggestion = buffer.auto_suggest.get_suggestion(self, buffer, document)
+
+ def callback():
suggest_thread_running[0] = False
- # Set suggestion only if the text was not yet changed.
- if buffer.text == document.text and \
- buffer.cursor_position == document.cursor_position:
-
- # Set suggestion and redraw interface.
- buffer.suggestion = suggestion
- self.invalidate()
- else:
- # Otherwise, restart thread.
- async_suggestor()
-
- if self.eventloop:
- self.eventloop.call_from_executor(callback)
-
- self.eventloop.run_in_executor(run)
- return async_suggestor
-
- def stdout_proxy(self, raw=False):
- """
- Create an :class:`_StdoutProxy` class which can be used as a patch for
- `sys.stdout`. Writing to this proxy will make sure that the text
- appears above the prompt, and that it doesn't destroy the output from
- the renderer.
-
- :param raw: (`bool`) When True, vt100 terminal escape sequences are not
- removed/escaped.
- """
- return _StdoutProxy(self, raw=raw)
-
+ # Set suggestion only if the text was not yet changed.
+ if buffer.text == document.text and \
+ buffer.cursor_position == document.cursor_position:
+
+ # Set suggestion and redraw interface.
+ buffer.suggestion = suggestion
+ self.invalidate()
+ else:
+ # Otherwise, restart thread.
+ async_suggestor()
+
+ if self.eventloop:
+ self.eventloop.call_from_executor(callback)
+
+ self.eventloop.run_in_executor(run)
+ return async_suggestor
+
+ def stdout_proxy(self, raw=False):
+ """
+ Create an :class:`_StdoutProxy` class which can be used as a patch for
+ `sys.stdout`. Writing to this proxy will make sure that the text
+ appears above the prompt, and that it doesn't destroy the output from
+ the renderer.
+
+ :param raw: (`bool`) When True, vt100 terminal escape sequences are not
+ removed/escaped.
+ """
+ return _StdoutProxy(self, raw=raw)
+
def patch_stdout_context(self, raw=False, patch_stdout=True, patch_stderr=True):
- """
- Return a context manager that will replace ``sys.stdout`` with a proxy
- that makes sure that all printed text will appear above the prompt, and
- that it doesn't destroy the output from the renderer.
+ """
+ Return a context manager that will replace ``sys.stdout`` with a proxy
+ that makes sure that all printed text will appear above the prompt, and
+ that it doesn't destroy the output from the renderer.
:param patch_stdout: Replace `sys.stdout`.
:param patch_stderr: Replace `sys.stderr`.
- """
+ """
return _PatchStdoutContext(
self.stdout_proxy(raw=raw),
patch_stdout=patch_stdout, patch_stderr=patch_stderr)
-
- def create_eventloop_callbacks(self):
- return _InterfaceEventLoopCallbacks(self)
-
-
-class _InterfaceEventLoopCallbacks(EventLoopCallbacks):
- """
- Callbacks on the :class:`.CommandLineInterface` object, to which an
- eventloop can talk.
- """
- def __init__(self, cli):
- assert isinstance(cli, CommandLineInterface)
- self.cli = cli
-
- @property
- def _active_cli(self):
- """
- Return the active `CommandLineInterface`.
- """
- cli = self.cli
-
- # If there is a sub CLI. That one is always active.
- while cli._sub_cli:
- cli = cli._sub_cli
-
- return cli
-
- def terminal_size_changed(self):
- """
- Report terminal size change. This will trigger a redraw.
- """
- self._active_cli._on_resize()
-
- def input_timeout(self):
- cli = self._active_cli
+
+ def create_eventloop_callbacks(self):
+ return _InterfaceEventLoopCallbacks(self)
+
+
+class _InterfaceEventLoopCallbacks(EventLoopCallbacks):
+ """
+ Callbacks on the :class:`.CommandLineInterface` object, to which an
+ eventloop can talk.
+ """
+ def __init__(self, cli):
+ assert isinstance(cli, CommandLineInterface)
+ self.cli = cli
+
+ @property
+ def _active_cli(self):
+ """
+ Return the active `CommandLineInterface`.
+ """
+ cli = self.cli
+
+ # If there is a sub CLI. That one is always active.
+ while cli._sub_cli:
+ cli = cli._sub_cli
+
+ return cli
+
+ def terminal_size_changed(self):
+ """
+ Report terminal size change. This will trigger a redraw.
+ """
+ self._active_cli._on_resize()
+
+ def input_timeout(self):
+ cli = self._active_cli
cli.on_input_timeout.fire()
-
- def feed_key(self, key_press):
- """
- Feed a key press to the CommandLineInterface.
- """
+
+ def feed_key(self, key_press):
+ """
+ Feed a key press to the CommandLineInterface.
+ """
assert isinstance(key_press, KeyPress)
cli = self._active_cli
- # Feed the key and redraw.
+ # Feed the key and redraw.
# (When the CLI is in 'done' state, it should return to the event loop
# as soon as possible. Ignore all key presses beyond this point.)
if not cli.is_done:
cli.input_processor.feed(key_press)
cli.input_processor.process_keys()
-
-
-class _PatchStdoutContext(object):
+
+
+class _PatchStdoutContext(object):
def __init__(self, new_stdout, patch_stdout=True, patch_stderr=True):
- self.new_stdout = new_stdout
+ self.new_stdout = new_stdout
self.patch_stdout = patch_stdout
self.patch_stderr = patch_stderr
-
- def __enter__(self):
- self.original_stdout = sys.stdout
+
+ def __enter__(self):
+ self.original_stdout = sys.stdout
self.original_stderr = sys.stderr
-
+
if self.patch_stdout:
sys.stdout = self.new_stdout
if self.patch_stderr:
sys.stderr = self.new_stdout
- def __exit__(self, *a, **kw):
+ def __exit__(self, *a, **kw):
if self.patch_stdout:
sys.stdout = self.original_stdout
-
+
if self.patch_stderr:
sys.stderr = self.original_stderr
-
-
-class _StdoutProxy(object):
- """
- Proxy for stdout, as returned by
- :class:`CommandLineInterface.stdout_proxy`.
- """
- def __init__(self, cli, raw=False):
- assert isinstance(cli, CommandLineInterface)
- assert isinstance(raw, bool)
-
- self._lock = threading.RLock()
- self._cli = cli
- self._raw = raw
- self._buffer = []
-
- self.errors = sys.__stdout__.errors
- self.encoding = sys.__stdout__.encoding
-
- def _do(self, func):
- if self._cli._is_running:
- run_in_terminal = functools.partial(self._cli.run_in_terminal, func)
- self._cli.eventloop.call_from_executor(run_in_terminal)
- else:
- func()
-
- def _write(self, data):
- """
- Note: print()-statements cause to multiple write calls.
- (write('line') and write('\n')). Of course we don't want to call
- `run_in_terminal` for every individual call, because that's too
- expensive, and as long as the newline hasn't been written, the
- text itself is again overwritter by the rendering of the input
- command line. Therefor, we have a little buffer which holds the
- text until a newline is written to stdout.
- """
- if '\n' in data:
- # When there is a newline in the data, write everything before the
- # newline, including the newline itself.
- before, after = data.rsplit('\n', 1)
- to_write = self._buffer + [before, '\n']
- self._buffer = [after]
-
- def run():
- for s in to_write:
- if self._raw:
- self._cli.output.write_raw(s)
- else:
- self._cli.output.write(s)
- self._do(run)
- else:
- # Otherwise, cache in buffer.
- self._buffer.append(data)
-
- def write(self, data):
- with self._lock:
- self._write(data)
-
- def _flush(self):
- def run():
- for s in self._buffer:
- if self._raw:
- self._cli.output.write_raw(s)
- else:
- self._cli.output.write(s)
- self._buffer = []
- self._cli.output.flush()
- self._do(run)
-
- def flush(self):
- """
- Flush buffered output.
- """
- with self._lock:
- self._flush()
-
-
-class _SubApplicationEventLoop(EventLoop):
- """
- Eventloop used by sub applications.
-
- A sub application is an `Application` that is "spawned" by a parent
- application. The parent application is suspended temporarily and the sub
- application is displayed instead.
-
- It doesn't need it's own event loop. The `EventLoopCallbacks` from the
- parent application are redirected to the sub application. So if the event
- loop that is run by the parent application detects input, the callbacks
- will make sure that it's forwarded to the sub application.
-
- When the sub application has a return value set, it will terminate
- by calling the `stop` method of this event loop. This is used to
- transfer control back to the parent application.
- """
- def __init__(self, cli, stop_callback):
- assert isinstance(cli, CommandLineInterface)
- assert callable(stop_callback)
-
- self.cli = cli
- self.stop_callback = stop_callback
-
- def stop(self):
- self.stop_callback()
-
- def close(self):
- pass
-
- def run_in_executor(self, callback):
- self.cli.eventloop.run_in_executor(callback)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- self.cli.eventloop.call_from_executor(
- callback, _max_postpone_until=_max_postpone_until)
-
- def add_reader(self, fd, callback):
- self.cli.eventloop.add_reader(fd, callback)
-
- def remove_reader(self, fd):
- self.cli.eventloop.remove_reader(fd)
+
+
+class _StdoutProxy(object):
+ """
+ Proxy for stdout, as returned by
+ :class:`CommandLineInterface.stdout_proxy`.
+ """
+ def __init__(self, cli, raw=False):
+ assert isinstance(cli, CommandLineInterface)
+ assert isinstance(raw, bool)
+
+ self._lock = threading.RLock()
+ self._cli = cli
+ self._raw = raw
+ self._buffer = []
+
+ self.errors = sys.__stdout__.errors
+ self.encoding = sys.__stdout__.encoding
+
+ def _do(self, func):
+ if self._cli._is_running:
+ run_in_terminal = functools.partial(self._cli.run_in_terminal, func)
+ self._cli.eventloop.call_from_executor(run_in_terminal)
+ else:
+ func()
+
+ def _write(self, data):
+ """
+ Note: print()-statements cause to multiple write calls.
+ (write('line') and write('\n')). Of course we don't want to call
+ `run_in_terminal` for every individual call, because that's too
+ expensive, and as long as the newline hasn't been written, the
+ text itself is again overwritter by the rendering of the input
+ command line. Therefor, we have a little buffer which holds the
+ text until a newline is written to stdout.
+ """
+ if '\n' in data:
+ # When there is a newline in the data, write everything before the
+ # newline, including the newline itself.
+ before, after = data.rsplit('\n', 1)
+ to_write = self._buffer + [before, '\n']
+ self._buffer = [after]
+
+ def run():
+ for s in to_write:
+ if self._raw:
+ self._cli.output.write_raw(s)
+ else:
+ self._cli.output.write(s)
+ self._do(run)
+ else:
+ # Otherwise, cache in buffer.
+ self._buffer.append(data)
+
+ def write(self, data):
+ with self._lock:
+ self._write(data)
+
+ def _flush(self):
+ def run():
+ for s in self._buffer:
+ if self._raw:
+ self._cli.output.write_raw(s)
+ else:
+ self._cli.output.write(s)
+ self._buffer = []
+ self._cli.output.flush()
+ self._do(run)
+
+ def flush(self):
+ """
+ Flush buffered output.
+ """
+ with self._lock:
+ self._flush()
+
+
+class _SubApplicationEventLoop(EventLoop):
+ """
+ Eventloop used by sub applications.
+
+ A sub application is an `Application` that is "spawned" by a parent
+ application. The parent application is suspended temporarily and the sub
+ application is displayed instead.
+
+ It doesn't need it's own event loop. The `EventLoopCallbacks` from the
+ parent application are redirected to the sub application. So if the event
+ loop that is run by the parent application detects input, the callbacks
+ will make sure that it's forwarded to the sub application.
+
+ When the sub application has a return value set, it will terminate
+ by calling the `stop` method of this event loop. This is used to
+ transfer control back to the parent application.
+ """
+ def __init__(self, cli, stop_callback):
+ assert isinstance(cli, CommandLineInterface)
+ assert callable(stop_callback)
+
+ self.cli = cli
+ self.stop_callback = stop_callback
+
+ def stop(self):
+ self.stop_callback()
+
+ def close(self):
+ pass
+
+ def run_in_executor(self, callback):
+ self.cli.eventloop.run_in_executor(callback)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ self.cli.eventloop.call_from_executor(
+ callback, _max_postpone_until=_max_postpone_until)
+
+ def add_reader(self, fd, callback):
+ self.cli.eventloop.add_reader(fd, callback)
+
+ def remove_reader(self, fd):
+ self.cli.eventloop.remove_reader(fd)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py
index a8b3a591b21..baffc488252 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/__init__.py
@@ -1 +1 @@
-from __future__ import unicode_literals
+from __future__ import unicode_literals
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py
index 3593df43e5f..401135dec06 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/basic.py
@@ -1,123 +1,123 @@
-# pylint: disable=function-redefined
-from __future__ import unicode_literals
-
-from prompt_toolkit.enums import DEFAULT_BUFFER
+# pylint: disable=function-redefined
+from __future__ import unicode_literals
+
+from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import HasSelection, Condition, EmacsInsertMode, ViInsertMode
-from prompt_toolkit.keys import Keys
-from prompt_toolkit.layout.screen import Point
+from prompt_toolkit.keys import Keys
+from prompt_toolkit.layout.screen import Point
from prompt_toolkit.mouse_events import MouseEventType, MouseEvent
-from prompt_toolkit.renderer import HeightIsUnknownError
-from prompt_toolkit.utils import suspend_to_background_supported, is_windows
-
+from prompt_toolkit.renderer import HeightIsUnknownError
+from prompt_toolkit.utils import suspend_to_background_supported, is_windows
+
from .named_commands import get_by_name
from ..registry import Registry
-
-
-__all__ = (
- 'load_basic_bindings',
- 'load_abort_and_exit_bindings',
- 'load_basic_system_bindings',
- 'load_auto_suggestion_bindings',
-)
-
-def if_no_repeat(event):
- """ Callable that returns True when the previous event was delivered to
- another handler. """
- return not event.is_repeat
-
-
+
+
+__all__ = (
+ 'load_basic_bindings',
+ 'load_abort_and_exit_bindings',
+ 'load_basic_system_bindings',
+ 'load_auto_suggestion_bindings',
+)
+
+def if_no_repeat(event):
+ """ Callable that returns True when the previous event was delivered to
+ another handler. """
+ return not event.is_repeat
+
+
def load_basic_bindings():
registry = Registry()
insert_mode = ViInsertMode() | EmacsInsertMode()
handle = registry.add_binding
- has_selection = HasSelection()
-
- @handle(Keys.ControlA)
- @handle(Keys.ControlB)
- @handle(Keys.ControlC)
- @handle(Keys.ControlD)
- @handle(Keys.ControlE)
- @handle(Keys.ControlF)
- @handle(Keys.ControlG)
- @handle(Keys.ControlH)
- @handle(Keys.ControlI)
- @handle(Keys.ControlJ)
- @handle(Keys.ControlK)
- @handle(Keys.ControlL)
- @handle(Keys.ControlM)
- @handle(Keys.ControlN)
- @handle(Keys.ControlO)
- @handle(Keys.ControlP)
- @handle(Keys.ControlQ)
- @handle(Keys.ControlR)
- @handle(Keys.ControlS)
- @handle(Keys.ControlT)
- @handle(Keys.ControlU)
- @handle(Keys.ControlV)
- @handle(Keys.ControlW)
- @handle(Keys.ControlX)
- @handle(Keys.ControlY)
- @handle(Keys.ControlZ)
- @handle(Keys.F1)
- @handle(Keys.F2)
- @handle(Keys.F3)
- @handle(Keys.F4)
- @handle(Keys.F5)
- @handle(Keys.F6)
- @handle(Keys.F7)
- @handle(Keys.F8)
- @handle(Keys.F9)
- @handle(Keys.F10)
- @handle(Keys.F11)
- @handle(Keys.F12)
- @handle(Keys.F13)
- @handle(Keys.F14)
- @handle(Keys.F15)
- @handle(Keys.F16)
- @handle(Keys.F17)
- @handle(Keys.F18)
- @handle(Keys.F19)
- @handle(Keys.F20)
- @handle(Keys.ControlSpace)
- @handle(Keys.ControlBackslash)
- @handle(Keys.ControlSquareClose)
- @handle(Keys.ControlCircumflex)
- @handle(Keys.ControlUnderscore)
- @handle(Keys.Backspace)
- @handle(Keys.Up)
- @handle(Keys.Down)
- @handle(Keys.Right)
- @handle(Keys.Left)
+ has_selection = HasSelection()
+
+ @handle(Keys.ControlA)
+ @handle(Keys.ControlB)
+ @handle(Keys.ControlC)
+ @handle(Keys.ControlD)
+ @handle(Keys.ControlE)
+ @handle(Keys.ControlF)
+ @handle(Keys.ControlG)
+ @handle(Keys.ControlH)
+ @handle(Keys.ControlI)
+ @handle(Keys.ControlJ)
+ @handle(Keys.ControlK)
+ @handle(Keys.ControlL)
+ @handle(Keys.ControlM)
+ @handle(Keys.ControlN)
+ @handle(Keys.ControlO)
+ @handle(Keys.ControlP)
+ @handle(Keys.ControlQ)
+ @handle(Keys.ControlR)
+ @handle(Keys.ControlS)
+ @handle(Keys.ControlT)
+ @handle(Keys.ControlU)
+ @handle(Keys.ControlV)
+ @handle(Keys.ControlW)
+ @handle(Keys.ControlX)
+ @handle(Keys.ControlY)
+ @handle(Keys.ControlZ)
+ @handle(Keys.F1)
+ @handle(Keys.F2)
+ @handle(Keys.F3)
+ @handle(Keys.F4)
+ @handle(Keys.F5)
+ @handle(Keys.F6)
+ @handle(Keys.F7)
+ @handle(Keys.F8)
+ @handle(Keys.F9)
+ @handle(Keys.F10)
+ @handle(Keys.F11)
+ @handle(Keys.F12)
+ @handle(Keys.F13)
+ @handle(Keys.F14)
+ @handle(Keys.F15)
+ @handle(Keys.F16)
+ @handle(Keys.F17)
+ @handle(Keys.F18)
+ @handle(Keys.F19)
+ @handle(Keys.F20)
+ @handle(Keys.ControlSpace)
+ @handle(Keys.ControlBackslash)
+ @handle(Keys.ControlSquareClose)
+ @handle(Keys.ControlCircumflex)
+ @handle(Keys.ControlUnderscore)
+ @handle(Keys.Backspace)
+ @handle(Keys.Up)
+ @handle(Keys.Down)
+ @handle(Keys.Right)
+ @handle(Keys.Left)
@handle(Keys.ShiftUp)
@handle(Keys.ShiftDown)
@handle(Keys.ShiftRight)
@handle(Keys.ShiftLeft)
- @handle(Keys.Home)
- @handle(Keys.End)
- @handle(Keys.Delete)
- @handle(Keys.ShiftDelete)
+ @handle(Keys.Home)
+ @handle(Keys.End)
+ @handle(Keys.Delete)
+ @handle(Keys.ShiftDelete)
@handle(Keys.ControlDelete)
- @handle(Keys.PageUp)
- @handle(Keys.PageDown)
- @handle(Keys.BackTab)
- @handle(Keys.Tab)
- @handle(Keys.ControlLeft)
- @handle(Keys.ControlRight)
- @handle(Keys.ControlUp)
- @handle(Keys.ControlDown)
- @handle(Keys.Insert)
+ @handle(Keys.PageUp)
+ @handle(Keys.PageDown)
+ @handle(Keys.BackTab)
+ @handle(Keys.Tab)
+ @handle(Keys.ControlLeft)
+ @handle(Keys.ControlRight)
+ @handle(Keys.ControlUp)
+ @handle(Keys.ControlDown)
+ @handle(Keys.Insert)
@handle(Keys.Ignore)
- def _(event):
- """
- First, for any of these keys, Don't do anything by default. Also don't
- catch them in the 'Any' handler which will insert them as data.
-
- If people want to insert these characters as a literal, they can always
- do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
- mode.)
- """
- pass
-
+ def _(event):
+ """
+ First, for any of these keys, Don't do anything by default. Also don't
+ catch them in the 'Any' handler which will insert them as data.
+
+ If people want to insert these characters as a literal, they can always
+ do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
+ mode.)
+ """
+ pass
+
# Readline-style bindings.
handle(Keys.Home)(get_by_name('beginning-of-line'))
handle(Keys.End)(get_by_name('end-of-line'))
@@ -126,7 +126,7 @@ def load_basic_bindings():
handle(Keys.ControlUp)(get_by_name('previous-history'))
handle(Keys.ControlDown)(get_by_name('next-history'))
handle(Keys.ControlL)(get_by_name('clear-screen'))
-
+
handle(Keys.ControlK, filter=insert_mode)(get_by_name('kill-line'))
handle(Keys.ControlU, filter=insert_mode)(get_by_name('unix-line-discard'))
handle(Keys.ControlH, filter=insert_mode, save_before=if_no_repeat)(
@@ -143,76 +143,76 @@ def load_basic_bindings():
handle(Keys.ControlW, filter=insert_mode)(get_by_name('unix-word-rubout'))
handle(Keys.ControlI, filter=insert_mode)(get_by_name('menu-complete'))
handle(Keys.BackTab, filter=insert_mode)(get_by_name('menu-complete-backward'))
-
+
handle(Keys.PageUp, filter= ~has_selection)(get_by_name('previous-history'))
handle(Keys.PageDown, filter= ~has_selection)(get_by_name('next-history'))
- # CTRL keys.
-
+ # CTRL keys.
+
text_before_cursor = Condition(lambda cli: cli.current_buffer.text)
handle(Keys.ControlD, filter=text_before_cursor & insert_mode)(get_by_name('delete-char'))
-
+
is_multiline = Condition(lambda cli: cli.current_buffer.is_multiline())
is_returnable = Condition(lambda cli: cli.current_buffer.accept_action.is_returnable)
-
+
@handle(Keys.ControlJ, filter=is_multiline & insert_mode)
- def _(event):
+ def _(event):
" Newline (in case of multiline input. "
event.current_buffer.newline(copy_margin=not event.cli.in_paste_mode)
-
+
@handle(Keys.ControlJ, filter=~is_multiline & is_returnable)
- def _(event):
+ def _(event):
" Enter, accept input. "
buff = event.current_buffer
buff.accept_action.validate_and_handle(event.cli, buff)
-
+
# Delete the word before the cursor.
-
+
@handle(Keys.Up)
- def _(event):
- event.current_buffer.auto_up(count=event.arg)
-
+ def _(event):
+ event.current_buffer.auto_up(count=event.arg)
+
@handle(Keys.Down)
- def _(event):
- event.current_buffer.auto_down(count=event.arg)
-
- @handle(Keys.Delete, filter=has_selection)
- def _(event):
- data = event.current_buffer.cut_selection()
- event.cli.clipboard.set_data(data)
-
+ def _(event):
+ event.current_buffer.auto_down(count=event.arg)
+
+ @handle(Keys.Delete, filter=has_selection)
+ def _(event):
+ data = event.current_buffer.cut_selection()
+ event.cli.clipboard.set_data(data)
+
# Global bindings.
-
- @handle(Keys.ControlZ)
- def _(event):
- """
- By default, control-Z should literally insert Ctrl-Z.
- (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
- In a Python REPL for instance, it's possible to type
- Control-Z followed by enter to quit.)
-
- When the system bindings are loaded and suspend-to-background is
- supported, that will override this binding.
- """
- event.current_buffer.insert_text(event.data)
-
+
+ @handle(Keys.ControlZ)
+ def _(event):
+ """
+ By default, control-Z should literally insert Ctrl-Z.
+ (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
+ In a Python REPL for instance, it's possible to type
+ Control-Z followed by enter to quit.)
+
+ When the system bindings are loaded and suspend-to-background is
+ supported, that will override this binding.
+ """
+ event.current_buffer.insert_text(event.data)
+
@handle(Keys.CPRResponse, save_before=lambda e: False)
- def _(event):
- """
- Handle incoming Cursor-Position-Request response.
- """
- # The incoming data looks like u'\x1b[35;1R'
- # Parse row/col information.
- row, col = map(int, event.data[2:-1].split(';'))
-
- # Report absolute cursor position to the renderer.
- event.cli.renderer.report_absolute_cursor_row(row)
-
+ def _(event):
+ """
+ Handle incoming Cursor-Position-Request response.
+ """
+ # The incoming data looks like u'\x1b[35;1R'
+ # Parse row/col information.
+ row, col = map(int, event.data[2:-1].split(';'))
+
+ # Report absolute cursor position to the renderer.
+ event.cli.renderer.report_absolute_cursor_row(row)
+
@handle(Keys.BracketedPaste)
- def _(event):
- " Pasting from clipboard. "
+ def _(event):
+ " Pasting from clipboard. "
data = event.data
-
+
# Be sure to use \n as line ending.
# Some terminals (Like iTerm2) seem to paste \r\n line endings in a
# bracketed paste. See: https://github.com/ipython/ipython/issues/9737
@@ -239,169 +239,169 @@ def load_mouse_bindings():
"""
registry = Registry()
- @registry.add_binding(Keys.Vt100MouseEvent)
- def _(event):
- """
- Handling of incoming mouse event.
- """
- # Typical: "Esc[MaB*"
- # Urxvt: "Esc[96;14;13M"
- # Xterm SGR: "Esc[<64;85;12M"
-
- # Parse incoming packet.
- if event.data[2] == 'M':
- # Typical.
- mouse_event, x, y = map(ord, event.data[3:])
- mouse_event = {
+ @registry.add_binding(Keys.Vt100MouseEvent)
+ def _(event):
+ """
+ Handling of incoming mouse event.
+ """
+ # Typical: "Esc[MaB*"
+ # Urxvt: "Esc[96;14;13M"
+ # Xterm SGR: "Esc[<64;85;12M"
+
+ # Parse incoming packet.
+ if event.data[2] == 'M':
+ # Typical.
+ mouse_event, x, y = map(ord, event.data[3:])
+ mouse_event = {
32: MouseEventType.MOUSE_DOWN,
35: MouseEventType.MOUSE_UP,
96: MouseEventType.SCROLL_UP,
97: MouseEventType.SCROLL_DOWN,
- }.get(mouse_event)
+ }.get(mouse_event)
# Handle situations where `PosixStdinReader` used surrogateescapes.
if x >= 0xdc00: x-= 0xdc00
if y >= 0xdc00: y-= 0xdc00
- x -= 32
- y -= 32
- else:
- # Urxvt and Xterm SGR.
- # When the '<' is not present, we are not using the Xterm SGR mode,
- # but Urxvt instead.
- data = event.data[2:]
- if data[:1] == '<':
- sgr = True
- data = data[1:]
- else:
- sgr = False
-
- # Extract coordinates.
- mouse_event, x, y = map(int, data[:-1].split(';'))
- m = data[-1]
-
- # Parse event type.
- if sgr:
- mouse_event = {
+ x -= 32
+ y -= 32
+ else:
+ # Urxvt and Xterm SGR.
+ # When the '<' is not present, we are not using the Xterm SGR mode,
+ # but Urxvt instead.
+ data = event.data[2:]
+ if data[:1] == '<':
+ sgr = True
+ data = data[1:]
+ else:
+ sgr = False
+
+ # Extract coordinates.
+ mouse_event, x, y = map(int, data[:-1].split(';'))
+ m = data[-1]
+
+ # Parse event type.
+ if sgr:
+ mouse_event = {
(0, 'M'): MouseEventType.MOUSE_DOWN,
(0, 'm'): MouseEventType.MOUSE_UP,
(64, 'M'): MouseEventType.SCROLL_UP,
(65, 'M'): MouseEventType.SCROLL_DOWN,
- }.get((mouse_event, m))
- else:
- mouse_event = {
+ }.get((mouse_event, m))
+ else:
+ mouse_event = {
32: MouseEventType.MOUSE_DOWN,
35: MouseEventType.MOUSE_UP,
96: MouseEventType.SCROLL_UP,
97: MouseEventType.SCROLL_DOWN,
- }.get(mouse_event)
-
- x -= 1
- y -= 1
-
- # Only handle mouse events when we know the window height.
- if event.cli.renderer.height_is_known and mouse_event is not None:
- # Take region above the layout into account. The reported
- # coordinates are absolute to the visible part of the terminal.
- try:
- y -= event.cli.renderer.rows_above_layout
- except HeightIsUnknownError:
- return
-
- # Call the mouse handler from the renderer.
- handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
- handler(event.cli, MouseEvent(position=Point(x=x, y=y),
- event_type=mouse_event))
-
- @registry.add_binding(Keys.WindowsMouseEvent)
- def _(event):
- """
- Handling of mouse events for Windows.
- """
- assert is_windows() # This key binding should only exist for Windows.
-
- # Parse data.
- event_type, x, y = event.data.split(';')
- x = int(x)
- y = int(y)
-
- # Make coordinates absolute to the visible part of the terminal.
- screen_buffer_info = event.cli.renderer.output.get_win32_screen_buffer_info()
- rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.cli.renderer._cursor_pos.y
- y -= rows_above_cursor
-
- # Call the mouse event handler.
- handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
- handler(event.cli, MouseEvent(position=Point(x=x, y=y),
- event_type=event_type))
-
+ }.get(mouse_event)
+
+ x -= 1
+ y -= 1
+
+ # Only handle mouse events when we know the window height.
+ if event.cli.renderer.height_is_known and mouse_event is not None:
+ # Take region above the layout into account. The reported
+ # coordinates are absolute to the visible part of the terminal.
+ try:
+ y -= event.cli.renderer.rows_above_layout
+ except HeightIsUnknownError:
+ return
+
+ # Call the mouse handler from the renderer.
+ handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
+ handler(event.cli, MouseEvent(position=Point(x=x, y=y),
+ event_type=mouse_event))
+
+ @registry.add_binding(Keys.WindowsMouseEvent)
+ def _(event):
+ """
+ Handling of mouse events for Windows.
+ """
+ assert is_windows() # This key binding should only exist for Windows.
+
+ # Parse data.
+ event_type, x, y = event.data.split(';')
+ x = int(x)
+ y = int(y)
+
+ # Make coordinates absolute to the visible part of the terminal.
+ screen_buffer_info = event.cli.renderer.output.get_win32_screen_buffer_info()
+ rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.cli.renderer._cursor_pos.y
+ y -= rows_above_cursor
+
+ # Call the mouse event handler.
+ handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
+ handler(event.cli, MouseEvent(position=Point(x=x, y=y),
+ event_type=event_type))
+
return registry
-
+
def load_abort_and_exit_bindings():
- """
- Basic bindings for abort (Ctrl-C) and exit (Ctrl-D).
- """
+ """
+ Basic bindings for abort (Ctrl-C) and exit (Ctrl-D).
+ """
registry = Registry()
handle = registry.add_binding
-
- @handle(Keys.ControlC)
- def _(event):
- " Abort when Control-C has been pressed. "
- event.cli.abort()
-
- @Condition
- def ctrl_d_condition(cli):
- """ Ctrl-D binding is only active when the default buffer is selected
- and empty. """
- return (cli.current_buffer_name == DEFAULT_BUFFER and
- not cli.current_buffer.text)
-
+
+ @handle(Keys.ControlC)
+ def _(event):
+ " Abort when Control-C has been pressed. "
+ event.cli.abort()
+
+ @Condition
+ def ctrl_d_condition(cli):
+ """ Ctrl-D binding is only active when the default buffer is selected
+ and empty. """
+ return (cli.current_buffer_name == DEFAULT_BUFFER and
+ not cli.current_buffer.text)
+
handle(Keys.ControlD, filter=ctrl_d_condition)(get_by_name('end-of-file'))
-
+
return registry
-
+
def load_basic_system_bindings():
- """
- Basic system bindings (For both Emacs and Vi mode.)
- """
+ """
+ Basic system bindings (For both Emacs and Vi mode.)
+ """
registry = Registry()
-
- suspend_supported = Condition(
- lambda cli: suspend_to_background_supported())
-
+
+ suspend_supported = Condition(
+ lambda cli: suspend_to_background_supported())
+
@registry.add_binding(Keys.ControlZ, filter=suspend_supported)
- def _(event):
- """
- Suspend process to background.
- """
- event.cli.suspend_to_background()
-
+ def _(event):
+ """
+ Suspend process to background.
+ """
+ event.cli.suspend_to_background()
+
return registry
-
+
def load_auto_suggestion_bindings():
- """
- Key bindings for accepting auto suggestion text.
- """
+ """
+ Key bindings for accepting auto suggestion text.
+ """
registry = Registry()
handle = registry.add_binding
-
- suggestion_available = Condition(
- lambda cli:
- cli.current_buffer.suggestion is not None and
- cli.current_buffer.document.is_cursor_at_the_end)
-
- @handle(Keys.ControlF, filter=suggestion_available)
- @handle(Keys.ControlE, filter=suggestion_available)
- @handle(Keys.Right, filter=suggestion_available)
- def _(event):
- " Accept suggestion. "
- b = event.current_buffer
- suggestion = b.suggestion
-
- if suggestion:
- b.insert_text(suggestion.text)
+
+ suggestion_available = Condition(
+ lambda cli:
+ cli.current_buffer.suggestion is not None and
+ cli.current_buffer.document.is_cursor_at_the_end)
+
+ @handle(Keys.ControlF, filter=suggestion_available)
+ @handle(Keys.ControlE, filter=suggestion_available)
+ @handle(Keys.Right, filter=suggestion_available)
+ def _(event):
+ " Accept suggestion. "
+ b = event.current_buffer
+ suggestion = b.suggestion
+
+ if suggestion:
+ b.insert_text(suggestion.text)
return registry
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py
index 5a0c502a57b..bccdb04ff38 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/emacs.py
@@ -1,47 +1,47 @@
-# pylint: disable=function-redefined
-from __future__ import unicode_literals
-from prompt_toolkit.buffer import SelectionType, indent, unindent
-from prompt_toolkit.keys import Keys
-from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER
+# pylint: disable=function-redefined
+from __future__ import unicode_literals
+from prompt_toolkit.buffer import SelectionType, indent, unindent
+from prompt_toolkit.keys import Keys
+from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER
from prompt_toolkit.filters import Condition, EmacsMode, HasSelection, EmacsInsertMode, HasFocus, HasArg
from prompt_toolkit.completion import CompleteEvent
-
-from .scroll import scroll_page_up, scroll_page_down
+
+from .scroll import scroll_page_up, scroll_page_down
from .named_commands import get_by_name
from ..registry import Registry, ConditionalRegistry
-
-__all__ = (
- 'load_emacs_bindings',
- 'load_emacs_search_bindings',
- 'load_emacs_system_bindings',
- 'load_extra_emacs_page_navigation_bindings',
-)
-
-
+
+__all__ = (
+ 'load_emacs_bindings',
+ 'load_emacs_search_bindings',
+ 'load_emacs_system_bindings',
+ 'load_extra_emacs_page_navigation_bindings',
+)
+
+
def load_emacs_bindings():
- """
- Some e-macs extensions.
- """
- # Overview of Readline emacs commands:
- # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
+ """
+ Some e-macs extensions.
+ """
+ # Overview of Readline emacs commands:
+ # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
registry = ConditionalRegistry(Registry(), EmacsMode())
handle = registry.add_binding
-
+
insert_mode = EmacsInsertMode()
has_selection = HasSelection()
-
- @handle(Keys.Escape)
- def _(event):
- """
- By default, ignore escape key.
-
- (If we don't put this here, and Esc is followed by a key which sequence
- is not handled, we'll insert an Escape character in the input stream.
- Something we don't want and happens to easily in emacs mode.
- Further, people can always use ControlQ to do a quoted insert.)
- """
- pass
-
+
+ @handle(Keys.Escape)
+ def _(event):
+ """
+ By default, ignore escape key.
+
+ (If we don't put this here, and Esc is followed by a key which sequence
+ is not handled, we'll insert an Escape character in the input stream.
+ Something we don't want and happens to easily in emacs mode.
+ Further, people can always use ControlQ to do a quoted insert.)
+ """
+ pass
+
handle(Keys.ControlA)(get_by_name('beginning-of-line'))
handle(Keys.ControlB)(get_by_name('backward-char'))
handle(Keys.ControlDelete, filter=insert_mode)(get_by_name('kill-word'))
@@ -61,14 +61,14 @@ def load_emacs_bindings():
handle(Keys.Escape, Keys.ControlH, filter=insert_mode)(get_by_name('backward-kill-word'))
handle(Keys.Escape, Keys.Backspace, filter=insert_mode)(get_by_name('backward-kill-word'))
handle(Keys.Escape, '\\', filter=insert_mode)(get_by_name('delete-horizontal-space'))
-
+
handle(Keys.ControlUnderscore, save_before=(lambda e: False), filter=insert_mode)(
get_by_name('undo'))
-
+
handle(Keys.ControlX, Keys.ControlU, save_before=(lambda e: False), filter=insert_mode)(
get_by_name('undo'))
-
-
+
+
handle(Keys.Escape, '<', filter= ~has_selection)(get_by_name('beginning-of-history'))
handle(Keys.Escape, '>', filter= ~has_selection)(get_by_name('end-of-history'))
@@ -88,365 +88,365 @@ def load_emacs_bindings():
handle(Keys.ControlX, 'e')(get_by_name('call-last-kbd-macro'))
@handle(Keys.ControlN)
- def _(event):
+ def _(event):
" Next line. "
- event.current_buffer.auto_down()
-
+ event.current_buffer.auto_down()
+
@handle(Keys.ControlP)
- def _(event):
+ def _(event):
" Previous line. "
- event.current_buffer.auto_up(count=event.arg)
-
- def handle_digit(c):
- """
+ event.current_buffer.auto_up(count=event.arg)
+
+ def handle_digit(c):
+ """
Handle input of arguments.
The first number needs to be preceeded by escape.
- """
+ """
@handle(c, filter=HasArg())
- @handle(Keys.Escape, c)
- def _(event):
- event.append_to_arg_count(c)
-
- for c in '0123456789':
- handle_digit(c)
-
+ @handle(Keys.Escape, c)
+ def _(event):
+ event.append_to_arg_count(c)
+
+ for c in '0123456789':
+ handle_digit(c)
+
@handle(Keys.Escape, '-', filter=~HasArg())
- def _(event):
- """
- """
- if event._arg is None:
- event.append_to_arg_count('-')
-
+ def _(event):
+ """
+ """
+ if event._arg is None:
+ event.append_to_arg_count('-')
+
@handle('-', filter=Condition(lambda cli: cli.input_processor.arg == '-'))
- def _(event):
- """
+ def _(event):
+ """
When '-' is typed again, after exactly '-' has been given as an
argument, ignore this.
- """
+ """
event.cli.input_processor.arg = '-'
-
+
is_returnable = Condition(
lambda cli: cli.current_buffer.accept_action.is_returnable)
-
+
# Meta + Newline: always accept input.
handle(Keys.Escape, Keys.ControlJ, filter=insert_mode & is_returnable)(
get_by_name('accept-line'))
-
+
def character_search(buff, char, count):
if count < 0:
match = buff.document.find_backwards(char, in_current_line=True, count=-count)
else:
match = buff.document.find(char, in_current_line=True, count=count)
-
+
if match is not None:
buff.cursor_position += match
-
+
@handle(Keys.ControlSquareClose, Keys.Any)
- def _(event):
+ def _(event):
" When Ctl-] + a character is pressed. go to that character. "
# Also named 'character-search'
character_search(event.current_buffer, event.data, event.arg)
-
+
@handle(Keys.Escape, Keys.ControlSquareClose, Keys.Any)
- def _(event):
+ def _(event):
" Like Ctl-], but backwards. "
# Also named 'character-search-backward'
character_search(event.current_buffer, event.data, -event.arg)
-
+
@handle(Keys.Escape, 'a')
- def _(event):
+ def _(event):
" Previous sentence. "
# TODO:
-
+
@handle(Keys.Escape, 'e')
- def _(event):
+ def _(event):
" Move to end of sentence. "
- # TODO:
-
+ # TODO:
+
@handle(Keys.Escape, 't', filter=insert_mode)
- def _(event):
- """
- Swap the last two words before the cursor.
- """
- # TODO
-
+ def _(event):
+ """
+ Swap the last two words before the cursor.
+ """
+ # TODO
+
@handle(Keys.Escape, '*', filter=insert_mode)
- def _(event):
- """
+ def _(event):
+ """
`meta-*`: Insert all possible completions of the preceding text.
- """
+ """
buff = event.current_buffer
-
+
# List all completions.
complete_event = CompleteEvent(text_inserted=False, completion_requested=True)
completions = list(buff.completer.get_completions(buff.document, complete_event))
-
+
# Insert them.
text_to_insert = ' '.join(c.text for c in completions)
buff.insert_text(text_to_insert)
-
- @handle(Keys.ControlX, Keys.ControlX)
- def _(event):
- """
- Move cursor back and forth between the start and end of the current
- line.
- """
- buffer = event.current_buffer
-
+
+ @handle(Keys.ControlX, Keys.ControlX)
+ def _(event):
+ """
+ Move cursor back and forth between the start and end of the current
+ line.
+ """
+ buffer = event.current_buffer
+
if buffer.document.is_cursor_at_the_end_of_line:
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=False)
- else:
- buffer.cursor_position += buffer.document.get_end_of_line_position()
-
- @handle(Keys.ControlSpace)
- def _(event):
- """
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=False)
+ else:
+ buffer.cursor_position += buffer.document.get_end_of_line_position()
+
+ @handle(Keys.ControlSpace)
+ def _(event):
+ """
Start of the selection (if the current buffer is not empty).
- """
- # Take the current cursor position as the start of this selection.
+ """
+ # Take the current cursor position as the start of this selection.
buff = event.current_buffer
if buff.text:
buff.start_selection(selection_type=SelectionType.CHARACTERS)
-
- @handle(Keys.ControlG, filter= ~has_selection)
- def _(event):
- """
- Control + G: Cancel completion menu and validation state.
- """
- event.current_buffer.complete_state = None
- event.current_buffer.validation_error = None
-
- @handle(Keys.ControlG, filter=has_selection)
- def _(event):
- """
- Cancel selection.
- """
- event.current_buffer.exit_selection()
-
- @handle(Keys.ControlW, filter=has_selection)
- @handle(Keys.ControlX, 'r', 'k', filter=has_selection)
- def _(event):
- """
- Cut selected text.
- """
- data = event.current_buffer.cut_selection()
- event.cli.clipboard.set_data(data)
-
- @handle(Keys.Escape, 'w', filter=has_selection)
- def _(event):
- """
- Copy selected text.
- """
- data = event.current_buffer.copy_selection()
- event.cli.clipboard.set_data(data)
-
- @handle(Keys.Escape, Keys.Left)
- def _(event):
- """
- Cursor to start of previous word.
- """
- buffer = event.current_buffer
- buffer.cursor_position += buffer.document.find_previous_word_beginning(count=event.arg) or 0
-
- @handle(Keys.Escape, Keys.Right)
- def _(event):
- """
- Cursor to start of next word.
- """
- buffer = event.current_buffer
- buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
- buffer.document.get_end_of_document_position()
-
+
+ @handle(Keys.ControlG, filter= ~has_selection)
+ def _(event):
+ """
+ Control + G: Cancel completion menu and validation state.
+ """
+ event.current_buffer.complete_state = None
+ event.current_buffer.validation_error = None
+
+ @handle(Keys.ControlG, filter=has_selection)
+ def _(event):
+ """
+ Cancel selection.
+ """
+ event.current_buffer.exit_selection()
+
+ @handle(Keys.ControlW, filter=has_selection)
+ @handle(Keys.ControlX, 'r', 'k', filter=has_selection)
+ def _(event):
+ """
+ Cut selected text.
+ """
+ data = event.current_buffer.cut_selection()
+ event.cli.clipboard.set_data(data)
+
+ @handle(Keys.Escape, 'w', filter=has_selection)
+ def _(event):
+ """
+ Copy selected text.
+ """
+ data = event.current_buffer.copy_selection()
+ event.cli.clipboard.set_data(data)
+
+ @handle(Keys.Escape, Keys.Left)
+ def _(event):
+ """
+ Cursor to start of previous word.
+ """
+ buffer = event.current_buffer
+ buffer.cursor_position += buffer.document.find_previous_word_beginning(count=event.arg) or 0
+
+ @handle(Keys.Escape, Keys.Right)
+ def _(event):
+ """
+ Cursor to start of next word.
+ """
+ buffer = event.current_buffer
+ buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
+ buffer.document.get_end_of_document_position()
+
@handle(Keys.Escape, '/', filter=insert_mode)
- def _(event):
- """
- M-/: Complete.
- """
- b = event.current_buffer
- if b.complete_state:
- b.complete_next()
- else:
- event.cli.start_completion(select_first=True)
-
- @handle(Keys.ControlC, '>', filter=has_selection)
- def _(event):
- """
- Indent selected text.
- """
- buffer = event.current_buffer
-
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
-
- from_, to = buffer.document.selection_range()
- from_, _ = buffer.document.translate_index_to_position(from_)
- to, _ = buffer.document.translate_index_to_position(to)
-
- indent(buffer, from_, to + 1, count=event.arg)
-
- @handle(Keys.ControlC, '<', filter=has_selection)
- def _(event):
- """
- Unindent selected text.
- """
- buffer = event.current_buffer
-
- from_, to = buffer.document.selection_range()
- from_, _ = buffer.document.translate_index_to_position(from_)
- to, _ = buffer.document.translate_index_to_position(to)
-
- unindent(buffer, from_, to + 1, count=event.arg)
-
+ def _(event):
+ """
+ M-/: Complete.
+ """
+ b = event.current_buffer
+ if b.complete_state:
+ b.complete_next()
+ else:
+ event.cli.start_completion(select_first=True)
+
+ @handle(Keys.ControlC, '>', filter=has_selection)
+ def _(event):
+ """
+ Indent selected text.
+ """
+ buffer = event.current_buffer
+
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+
+ from_, to = buffer.document.selection_range()
+ from_, _ = buffer.document.translate_index_to_position(from_)
+ to, _ = buffer.document.translate_index_to_position(to)
+
+ indent(buffer, from_, to + 1, count=event.arg)
+
+ @handle(Keys.ControlC, '<', filter=has_selection)
+ def _(event):
+ """
+ Unindent selected text.
+ """
+ buffer = event.current_buffer
+
+ from_, to = buffer.document.selection_range()
+ from_, _ = buffer.document.translate_index_to_position(from_)
+ to, _ = buffer.document.translate_index_to_position(to)
+
+ unindent(buffer, from_, to + 1, count=event.arg)
+
return registry
-
+
def load_emacs_open_in_editor_bindings():
- """
- Pressing C-X C-E will open the buffer in an external editor.
- """
+ """
+ Pressing C-X C-E will open the buffer in an external editor.
+ """
registry = Registry()
-
+
registry.add_binding(Keys.ControlX, Keys.ControlE,
filter=EmacsMode() & ~HasSelection())(
get_by_name('edit-and-execute-command'))
-
+
return registry
-
+
def load_emacs_system_bindings():
registry = ConditionalRegistry(Registry(), EmacsMode())
handle = registry.add_binding
has_focus = HasFocus(SYSTEM_BUFFER)
-
- @handle(Keys.Escape, '!', filter= ~has_focus)
- def _(event):
- """
- M-'!' opens the system prompt.
- """
- event.cli.push_focus(SYSTEM_BUFFER)
-
- @handle(Keys.Escape, filter=has_focus)
- @handle(Keys.ControlG, filter=has_focus)
- @handle(Keys.ControlC, filter=has_focus)
- def _(event):
- """
- Cancel system prompt.
- """
- event.cli.buffers[SYSTEM_BUFFER].reset()
- event.cli.pop_focus()
-
- @handle(Keys.ControlJ, filter=has_focus)
- def _(event):
- """
- Run system command.
- """
- system_line = event.cli.buffers[SYSTEM_BUFFER]
- event.cli.run_system_command(system_line.text)
- system_line.reset(append_to_history=True)
-
- # Focus previous buffer again.
- event.cli.pop_focus()
-
+
+ @handle(Keys.Escape, '!', filter= ~has_focus)
+ def _(event):
+ """
+ M-'!' opens the system prompt.
+ """
+ event.cli.push_focus(SYSTEM_BUFFER)
+
+ @handle(Keys.Escape, filter=has_focus)
+ @handle(Keys.ControlG, filter=has_focus)
+ @handle(Keys.ControlC, filter=has_focus)
+ def _(event):
+ """
+ Cancel system prompt.
+ """
+ event.cli.buffers[SYSTEM_BUFFER].reset()
+ event.cli.pop_focus()
+
+ @handle(Keys.ControlJ, filter=has_focus)
+ def _(event):
+ """
+ Run system command.
+ """
+ system_line = event.cli.buffers[SYSTEM_BUFFER]
+ event.cli.run_system_command(system_line.text)
+ system_line.reset(append_to_history=True)
+
+ # Focus previous buffer again.
+ event.cli.pop_focus()
+
return registry
-
-
+
+
def load_emacs_search_bindings(get_search_state=None):
registry = ConditionalRegistry(Registry(), EmacsMode())
handle = registry.add_binding
has_focus = HasFocus(SEARCH_BUFFER)
- assert get_search_state is None or callable(get_search_state)
-
- if not get_search_state:
- def get_search_state(cli): return cli.search_state
-
- @handle(Keys.ControlG, filter=has_focus)
- @handle(Keys.ControlC, filter=has_focus)
- # NOTE: the reason for not also binding Escape to this one, is that we want
- # Alt+Enter to accept input directly in incremental search mode.
- def _(event):
- """
- Abort an incremental search and restore the original line.
- """
- search_buffer = event.cli.buffers[SEARCH_BUFFER]
-
- search_buffer.reset()
- event.cli.pop_focus()
-
- @handle(Keys.ControlJ, filter=has_focus)
+ assert get_search_state is None or callable(get_search_state)
+
+ if not get_search_state:
+ def get_search_state(cli): return cli.search_state
+
+ @handle(Keys.ControlG, filter=has_focus)
+ @handle(Keys.ControlC, filter=has_focus)
+ # NOTE: the reason for not also binding Escape to this one, is that we want
+ # Alt+Enter to accept input directly in incremental search mode.
+ def _(event):
+ """
+ Abort an incremental search and restore the original line.
+ """
+ search_buffer = event.cli.buffers[SEARCH_BUFFER]
+
+ search_buffer.reset()
+ event.cli.pop_focus()
+
+ @handle(Keys.ControlJ, filter=has_focus)
@handle(Keys.Escape, filter=has_focus, eager=True)
- def _(event):
- """
- When enter pressed in isearch, quit isearch mode. (Multiline
- isearch would be too complicated.)
- """
- input_buffer = event.cli.buffers.previous(event.cli)
- search_buffer = event.cli.buffers[SEARCH_BUFFER]
-
- # Update search state.
- if search_buffer.text:
- get_search_state(event.cli).text = search_buffer.text
-
- # Apply search.
- input_buffer.apply_search(get_search_state(event.cli), include_current_position=True)
-
- # Add query to history of search line.
- search_buffer.append_to_history()
- search_buffer.reset()
-
- # Focus previous document again.
- event.cli.pop_focus()
-
- @handle(Keys.ControlR, filter= ~has_focus)
- def _(event):
- get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD
- event.cli.push_focus(SEARCH_BUFFER)
-
- @handle(Keys.ControlS, filter= ~has_focus)
- def _(event):
- get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD
- event.cli.push_focus(SEARCH_BUFFER)
-
+ def _(event):
+ """
+ When enter pressed in isearch, quit isearch mode. (Multiline
+ isearch would be too complicated.)
+ """
+ input_buffer = event.cli.buffers.previous(event.cli)
+ search_buffer = event.cli.buffers[SEARCH_BUFFER]
+
+ # Update search state.
+ if search_buffer.text:
+ get_search_state(event.cli).text = search_buffer.text
+
+ # Apply search.
+ input_buffer.apply_search(get_search_state(event.cli), include_current_position=True)
+
+ # Add query to history of search line.
+ search_buffer.append_to_history()
+ search_buffer.reset()
+
+ # Focus previous document again.
+ event.cli.pop_focus()
+
+ @handle(Keys.ControlR, filter= ~has_focus)
+ def _(event):
+ get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD
+ event.cli.push_focus(SEARCH_BUFFER)
+
+ @handle(Keys.ControlS, filter= ~has_focus)
+ def _(event):
+ get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD
+ event.cli.push_focus(SEARCH_BUFFER)
+
def incremental_search(cli, direction, count=1):
" Apply search, but keep search buffer focussed. "
- # Update search_state.
+ # Update search_state.
search_state = get_search_state(cli)
direction_changed = search_state.direction != direction
-
+
search_state.text = cli.buffers[SEARCH_BUFFER].text
search_state.direction = direction
-
- # Apply search to current buffer.
- if not direction_changed:
+
+ # Apply search to current buffer.
+ if not direction_changed:
input_buffer = cli.buffers.previous(cli)
- input_buffer.apply_search(search_state,
+ input_buffer.apply_search(search_state,
include_current_position=False, count=count)
-
+
@handle(Keys.ControlR, filter=has_focus)
@handle(Keys.Up, filter=has_focus)
def _(event):
incremental_search(event.cli, IncrementalSearchDirection.BACKWARD, count=event.arg)
- @handle(Keys.ControlS, filter=has_focus)
- @handle(Keys.Down, filter=has_focus)
- def _(event):
+ @handle(Keys.ControlS, filter=has_focus)
+ @handle(Keys.Down, filter=has_focus)
+ def _(event):
incremental_search(event.cli, IncrementalSearchDirection.FORWARD, count=event.arg)
-
+
return registry
-
+
def load_extra_emacs_page_navigation_bindings():
- """
- Key bindings, for scrolling up and down through pages.
- This are separate bindings, because GNU readline doesn't have them.
- """
+ """
+ Key bindings, for scrolling up and down through pages.
+ This are separate bindings, because GNU readline doesn't have them.
+ """
registry = ConditionalRegistry(Registry(), EmacsMode())
handle = registry.add_binding
-
- handle(Keys.ControlV)(scroll_page_down)
- handle(Keys.PageDown)(scroll_page_down)
- handle(Keys.Escape, 'v')(scroll_page_up)
- handle(Keys.PageUp)(scroll_page_up)
+
+ handle(Keys.ControlV)(scroll_page_down)
+ handle(Keys.PageDown)(scroll_page_down)
+ handle(Keys.Escape, 'v')(scroll_page_up)
+ handle(Keys.PageUp)(scroll_page_up)
return registry
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py
index 169517942cf..2cc58129ffc 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/scroll.py
@@ -1,139 +1,139 @@
-"""
-Key bindings, for scrolling up and down through pages.
-
-This are separate bindings, because GNU readline doesn't have them, but
-they are very useful for navigating through long multiline buffers, like in
-Vi, Emacs, etc...
-"""
-from __future__ import unicode_literals
-
-from prompt_toolkit.layout.utils import find_window_for_buffer_name
+"""
+Key bindings, for scrolling up and down through pages.
+
+This are separate bindings, because GNU readline doesn't have them, but
+they are very useful for navigating through long multiline buffers, like in
+Vi, Emacs, etc...
+"""
+from __future__ import unicode_literals
+
+from prompt_toolkit.layout.utils import find_window_for_buffer_name
from six.moves import range
-
-__all__ = (
- 'scroll_forward',
- 'scroll_backward',
- 'scroll_half_page_up',
- 'scroll_half_page_down',
- 'scroll_one_line_up',
- 'scroll_one_line_down',
-)
-
-
-def _current_window_for_event(event):
- """
- Return the `Window` for the currently focussed Buffer.
- """
- return find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
-
-
-def scroll_forward(event, half=False):
- """
- Scroll window down.
- """
- w = _current_window_for_event(event)
- b = event.cli.current_buffer
-
- if w and w.render_info:
+
+__all__ = (
+ 'scroll_forward',
+ 'scroll_backward',
+ 'scroll_half_page_up',
+ 'scroll_half_page_down',
+ 'scroll_one_line_up',
+ 'scroll_one_line_down',
+)
+
+
+def _current_window_for_event(event):
+ """
+ Return the `Window` for the currently focussed Buffer.
+ """
+ return find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+
+
+def scroll_forward(event, half=False):
+ """
+ Scroll window down.
+ """
+ w = _current_window_for_event(event)
+ b = event.cli.current_buffer
+
+ if w and w.render_info:
info = w.render_info
ui_content = info.ui_content
# Height to scroll.
scroll_height = info.window_height
- if half:
+ if half:
scroll_height //= 2
-
+
# Calculate how many lines is equivalent to that vertical space.
y = b.document.cursor_position_row + 1
height = 0
while y < ui_content.line_count:
line_height = info.get_height_for_line(y)
-
+
if height + line_height < scroll_height:
height += line_height
y += 1
else:
break
-
+
b.cursor_position = b.document.translate_row_col_to_index(y, 0)
-def scroll_backward(event, half=False):
- """
- Scroll window up.
- """
- w = _current_window_for_event(event)
- b = event.cli.current_buffer
-
- if w and w.render_info:
+def scroll_backward(event, half=False):
+ """
+ Scroll window up.
+ """
+ w = _current_window_for_event(event)
+ b = event.cli.current_buffer
+
+ if w and w.render_info:
info = w.render_info
# Height to scroll.
scroll_height = info.window_height
- if half:
+ if half:
scroll_height //= 2
-
+
# Calculate how many lines is equivalent to that vertical space.
y = max(0, b.document.cursor_position_row - 1)
height = 0
while y > 0:
line_height = info.get_height_for_line(y)
-
+
if height + line_height < scroll_height:
height += line_height
y -= 1
else:
break
-
+
b.cursor_position = b.document.translate_row_col_to_index(y, 0)
-def scroll_half_page_down(event):
- """
- Same as ControlF, but only scroll half a page.
- """
- scroll_forward(event, half=True)
-
-
-def scroll_half_page_up(event):
- """
- Same as ControlB, but only scroll half a page.
- """
- scroll_backward(event, half=True)
-
-
-def scroll_one_line_down(event):
- """
- scroll_offset += 1
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.cli.current_buffer
-
- if w:
- # When the cursor is at the top, move to the next line. (Otherwise, only scroll.)
- if w.render_info:
- info = w.render_info
-
- if w.vertical_scroll < info.content_height - info.window_height:
- if info.cursor_position.y <= info.configured_scroll_offsets.top:
- b.cursor_position += b.document.get_cursor_down_position()
-
- w.vertical_scroll += 1
-
-
-def scroll_one_line_up(event):
- """
- scroll_offset -= 1
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.cli.current_buffer
-
- if w:
- # When the cursor is at the bottom, move to the previous line. (Otherwise, only scroll.)
- if w.render_info:
- info = w.render_info
-
- if w.vertical_scroll > 0:
+def scroll_half_page_down(event):
+ """
+ Same as ControlF, but only scroll half a page.
+ """
+ scroll_forward(event, half=True)
+
+
+def scroll_half_page_up(event):
+ """
+ Same as ControlB, but only scroll half a page.
+ """
+ scroll_backward(event, half=True)
+
+
+def scroll_one_line_down(event):
+ """
+ scroll_offset += 1
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.cli.current_buffer
+
+ if w:
+ # When the cursor is at the top, move to the next line. (Otherwise, only scroll.)
+ if w.render_info:
+ info = w.render_info
+
+ if w.vertical_scroll < info.content_height - info.window_height:
+ if info.cursor_position.y <= info.configured_scroll_offsets.top:
+ b.cursor_position += b.document.get_cursor_down_position()
+
+ w.vertical_scroll += 1
+
+
+def scroll_one_line_up(event):
+ """
+ scroll_offset -= 1
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.cli.current_buffer
+
+ if w:
+ # When the cursor is at the bottom, move to the previous line. (Otherwise, only scroll.)
+ if w.render_info:
+ info = w.render_info
+
+ if w.vertical_scroll > 0:
first_line_height = info.get_height_for_line(info.first_visible_line())
cursor_up = info.cursor_position.y - (info.window_height - 1 - first_line_height -
@@ -142,44 +142,44 @@ def scroll_one_line_up(event):
# Move cursor up, as many steps as the height of the first line.
# TODO: not entirely correct yet, in case of line wrapping and many long lines.
for _ in range(max(0, cursor_up)):
- b.cursor_position += b.document.get_cursor_up_position()
-
- # Scroll window
- w.vertical_scroll -= 1
-
-
-def scroll_page_down(event):
- """
- Scroll page down. (Prefer the cursor at the top of the page, after scrolling.)
- """
- w = _current_window_for_event(event)
- b = event.cli.current_buffer
-
- if w and w.render_info:
- # Scroll down one page.
+ b.cursor_position += b.document.get_cursor_up_position()
+
+ # Scroll window
+ w.vertical_scroll -= 1
+
+
+def scroll_page_down(event):
+ """
+ Scroll page down. (Prefer the cursor at the top of the page, after scrolling.)
+ """
+ w = _current_window_for_event(event)
+ b = event.cli.current_buffer
+
+ if w and w.render_info:
+ # Scroll down one page.
line_index = max(w.render_info.last_visible_line(), w.vertical_scroll + 1)
w.vertical_scroll = line_index
-
+
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0)
- b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True)
-
-
-def scroll_page_up(event):
- """
- Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.)
- """
- w = _current_window_for_event(event)
- b = event.cli.current_buffer
-
- if w and w.render_info:
+ b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True)
+
+
+def scroll_page_up(event):
+ """
+ Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.)
+ """
+ w = _current_window_for_event(event)
+ b = event.cli.current_buffer
+
+ if w and w.render_info:
# Put cursor at the first visible line. (But make sure that the cursor
# moves at least one line up.)
line_index = max(0, min(w.render_info.first_visible_line(),
b.document.cursor_position_row - 1))
-
+
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0)
b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True)
-
+
# Set the scroll offset. We can safely set it to zero; the Window will
# make sure that it scrolls at least until the cursor becomes visible.
w.vertical_scroll = 0
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py
index 226ae8a5c55..caf08c5c1bd 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/utils.py
@@ -1,25 +1,25 @@
-from __future__ import unicode_literals
-from prompt_toolkit.filters import CLIFilter, Always
-
-__all__ = (
- 'create_handle_decorator',
-)
-
-def create_handle_decorator(registry, filter=Always()):
- """
+from __future__ import unicode_literals
+from prompt_toolkit.filters import CLIFilter, Always
+
+__all__ = (
+ 'create_handle_decorator',
+)
+
+def create_handle_decorator(registry, filter=Always()):
+ """
Create a key handle decorator, which is compatible with `Registry.handle`,
but will chain the given filter to every key binding.
-
+
:param filter: `CLIFilter`
- """
- assert isinstance(filter, CLIFilter)
-
- def handle(*keys, **kw):
- # Chain the given filter to the filter of this specific binding.
- if 'filter' in kw:
- kw['filter'] = kw['filter'] & filter
- else:
- kw['filter'] = filter
-
+ """
+ assert isinstance(filter, CLIFilter)
+
+ def handle(*keys, **kw):
+ # Chain the given filter to the filter of this specific binding.
+ if 'filter' in kw:
+ kw['filter'] = kw['filter'] & filter
+ else:
+ kw['filter'] = filter
+
return registry.add_binding(*keys, **kw)
- return handle
+ return handle
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py
index a436edf3a7a..72568ee273d 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/bindings/vi.py
@@ -1,26 +1,26 @@
-# pylint: disable=function-redefined
-from __future__ import unicode_literals
+# pylint: disable=function-redefined
+from __future__ import unicode_literals
from prompt_toolkit.buffer import ClipboardData, indent, unindent, reshape_text
-from prompt_toolkit.document import Document
-from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER
+from prompt_toolkit.document import Document
+from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER, SYSTEM_BUFFER
from prompt_toolkit.filters import Filter, Condition, HasArg, Always, IsReadOnly
from prompt_toolkit.filters.cli import ViNavigationMode, ViInsertMode, ViInsertMultipleMode, ViReplaceMode, ViSelectionMode, ViWaitingForTextObjectMode, ViDigraphMode, ViMode
from prompt_toolkit.key_binding.digraphs import DIGRAPHS
-from prompt_toolkit.key_binding.vi_state import CharacterFind, InputMode
-from prompt_toolkit.keys import Keys
-from prompt_toolkit.layout.utils import find_window_for_buffer_name
+from prompt_toolkit.key_binding.vi_state import CharacterFind, InputMode
+from prompt_toolkit.keys import Keys
+from prompt_toolkit.layout.utils import find_window_for_buffer_name
from prompt_toolkit.selection import SelectionType, SelectionState, PasteMode
-
-from .scroll import scroll_forward, scroll_backward, scroll_half_page_up, scroll_half_page_down, scroll_one_line_up, scroll_one_line_down, scroll_page_up, scroll_page_down
+
+from .scroll import scroll_forward, scroll_backward, scroll_half_page_up, scroll_half_page_down, scroll_one_line_up, scroll_one_line_down, scroll_page_up, scroll_page_down
from .named_commands import get_by_name
from ..registry import Registry, ConditionalRegistry, BaseRegistry
-
-import prompt_toolkit.filters as filters
+
+import prompt_toolkit.filters as filters
from six.moves import range
-import codecs
+import codecs
import six
import string
-
+
try:
from itertools import accumulate
except ImportError: # < Python 3.2
@@ -31,38 +31,38 @@ except ImportError: # < Python 3.2
total += item
yield total
-__all__ = (
- 'load_vi_bindings',
- 'load_vi_search_bindings',
- 'load_vi_system_bindings',
- 'load_extra_vi_page_navigation_bindings',
-)
-
+__all__ = (
+ 'load_vi_bindings',
+ 'load_vi_search_bindings',
+ 'load_vi_system_bindings',
+ 'load_extra_vi_page_navigation_bindings',
+)
+
if six.PY2:
ascii_lowercase = string.ascii_lowercase.decode('ascii')
else:
ascii_lowercase = string.ascii_lowercase
-
+
vi_register_names = ascii_lowercase + '0123456789'
-
-
+
+
class TextObjectType(object):
EXCLUSIVE = 'EXCLUSIVE'
INCLUSIVE = 'INCLUSIVE'
LINEWISE = 'LINEWISE'
BLOCK = 'BLOCK'
-
-
+
+
class TextObject(object):
- """
+ """
Return struct for functions wrapped in ``text_object``.
- Both `start` and `end` are relative to the current cursor position.
- """
+ Both `start` and `end` are relative to the current cursor position.
+ """
def __init__(self, start, end=0, type=TextObjectType.EXCLUSIVE):
- self.start = start
- self.end = end
+ self.start = start
+ self.end = end
self.type = type
-
+
@property
def selection_type(self):
if self.type == TextObjectType.LINEWISE:
@@ -72,15 +72,15 @@ class TextObject(object):
else:
return SelectionType.CHARACTERS
- def sorted(self):
- """
- Return a (start, end) tuple where start <= end.
- """
- if self.start < self.end:
- return self.start, self.end
- else:
- return self.end, self.start
-
+ def sorted(self):
+ """
+ Return a (start, end) tuple where start <= end.
+ """
+ if self.start < self.end:
+ return self.start, self.end
+ else:
+ return self.end, self.start
+
def operator_range(self, document):
"""
Return a (start, end) tuple with start <= end that indicates the range
@@ -89,7 +89,7 @@ class TextObject(object):
"""
start, end = self.sorted()
doc = document
-
+
if (self.type == TextObjectType.EXCLUSIVE and
doc.translate_index_to_position(end + doc.cursor_position)[1] == 0):
# If the motion is exclusive and the end of motion is on the first
@@ -138,7 +138,7 @@ class TextObject(object):
def create_text_object_decorator(registry):
- """
+ """
Create a decorator that can be used to register Vi text object implementations.
"""
assert isinstance(registry, BaseRegistry)
@@ -299,30 +299,30 @@ def create_operator_decorator(registry):
def load_vi_bindings(get_search_state=None):
"""
- Vi extensions.
-
- # Overview of Readline Vi commands:
- # http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf
-
+ Vi extensions.
+
+ # Overview of Readline Vi commands:
+ # http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf
+
:param get_search_state: None or a callable that takes a
CommandLineInterface and returns a SearchState.
- """
- # Note: Some key bindings have the "~IsReadOnly()" filter added. This
- # prevents the handler to be executed when the focus is on a
- # read-only buffer.
- # This is however only required for those that change the ViState to
- # INSERT mode. The `Buffer` class itself throws the
- # `EditReadOnlyBuffer` exception for any text operations which is
- # handled correctly. There is no need to add "~IsReadOnly" to all key
- # bindings that do text manipulation.
-
+ """
+ # Note: Some key bindings have the "~IsReadOnly()" filter added. This
+ # prevents the handler to be executed when the focus is on a
+ # read-only buffer.
+ # This is however only required for those that change the ViState to
+ # INSERT mode. The `Buffer` class itself throws the
+ # `EditReadOnlyBuffer` exception for any text operations which is
+ # handled correctly. There is no need to add "~IsReadOnly" to all key
+ # bindings that do text manipulation.
+
registry = ConditionalRegistry(Registry(), ViMode())
handle = registry.add_binding
-
- # Default get_search_state.
- if get_search_state is None:
- def get_search_state(cli): return cli.search_state
-
+
+ # Default get_search_state.
+ if get_search_state is None:
+ def get_search_state(cli): return cli.search_state
+
# (Note: Always take the navigation bindings in read-only mode, even when
# ViState says different.)
navigation_mode = ViNavigationMode()
@@ -332,63 +332,63 @@ def load_vi_bindings(get_search_state=None):
selection_mode = ViSelectionMode()
operator_given = ViWaitingForTextObjectMode()
digraph_mode = ViDigraphMode()
-
- vi_transform_functions = [
- # Rot 13 transformation
+
+ vi_transform_functions = [
+ # Rot 13 transformation
(('g', '?'), Always(), lambda string: codecs.encode(string, 'rot_13')),
-
- # To lowercase
+
+ # To lowercase
(('g', 'u'), Always(), lambda string: string.lower()),
-
- # To uppercase.
+
+ # To uppercase.
(('g', 'U'), Always(), lambda string: string.upper()),
-
- # Swap case.
+
+ # Swap case.
(('g', '~'), Always(), lambda string: string.swapcase()),
(('~', ), Condition(lambda cli: cli.vi_state.tilde_operator), lambda string: string.swapcase()),
- ]
-
+ ]
+
# Insert a character literally (quoted insert).
handle(Keys.ControlV, filter=insert_mode)(get_by_name('quoted-insert'))
- @handle(Keys.Escape)
- def _(event):
- """
- Escape goes to vi navigation mode.
- """
- buffer = event.current_buffer
+ @handle(Keys.Escape)
+ def _(event):
+ """
+ Escape goes to vi navigation mode.
+ """
+ buffer = event.current_buffer
vi_state = event.cli.vi_state
-
- if vi_state.input_mode in (InputMode.INSERT, InputMode.REPLACE):
- buffer.cursor_position += buffer.document.get_cursor_left_position()
-
+
+ if vi_state.input_mode in (InputMode.INSERT, InputMode.REPLACE):
+ buffer.cursor_position += buffer.document.get_cursor_left_position()
+
vi_state.reset(InputMode.NAVIGATION)
-
- if bool(buffer.selection_state):
- buffer.exit_selection()
-
- @handle('k', filter=selection_mode)
- def _(event):
- """
- Arrow up in selection mode.
- """
- event.current_buffer.cursor_up(count=event.arg)
-
- @handle('j', filter=selection_mode)
- def _(event):
- """
- Arrow down in selection mode.
- """
- event.current_buffer.cursor_down(count=event.arg)
-
- @handle(Keys.Up, filter=navigation_mode)
- @handle(Keys.ControlP, filter=navigation_mode)
- def _(event):
- """
- Arrow up and ControlP in navigation mode go up.
- """
+
+ if bool(buffer.selection_state):
+ buffer.exit_selection()
+
+ @handle('k', filter=selection_mode)
+ def _(event):
+ """
+ Arrow up in selection mode.
+ """
+ event.current_buffer.cursor_up(count=event.arg)
+
+ @handle('j', filter=selection_mode)
+ def _(event):
+ """
+ Arrow down in selection mode.
+ """
+ event.current_buffer.cursor_down(count=event.arg)
+
+ @handle(Keys.Up, filter=navigation_mode)
+ @handle(Keys.ControlP, filter=navigation_mode)
+ def _(event):
+ """
+ Arrow up and ControlP in navigation mode go up.
+ """
event.current_buffer.auto_up(count=event.arg)
-
+
@handle('k', filter=navigation_mode)
def _(event):
"""
@@ -398,14 +398,14 @@ def load_vi_bindings(get_search_state=None):
event.current_buffer.auto_up(
count=event.arg, go_to_start_of_line_if_history_changes=True)
- @handle(Keys.Down, filter=navigation_mode)
- @handle(Keys.ControlN, filter=navigation_mode)
- def _(event):
- """
- Arrow down and Control-N in navigation mode.
- """
+ @handle(Keys.Down, filter=navigation_mode)
+ @handle(Keys.ControlN, filter=navigation_mode)
+ def _(event):
+ """
+ Arrow down and Control-N in navigation mode.
+ """
event.current_buffer.auto_down(count=event.arg)
-
+
@handle('j', filter=navigation_mode)
def _(event):
"""
@@ -415,143 +415,143 @@ def load_vi_bindings(get_search_state=None):
count=event.arg, go_to_start_of_line_if_history_changes=True)
@handle(Keys.ControlH, filter=navigation_mode)
- @handle(Keys.Backspace, filter=navigation_mode)
- def _(event):
- """
- In navigation-mode, move cursor.
- """
- event.current_buffer.cursor_position += \
- event.current_buffer.document.get_cursor_left_position(count=event.arg)
-
- @handle(Keys.ControlN, filter=insert_mode)
- def _(event):
- b = event.current_buffer
-
- if b.complete_state:
- b.complete_next()
- else:
- event.cli.start_completion(select_first=True)
-
- @handle(Keys.ControlP, filter=insert_mode)
- def _(event):
- """
- Control-P: To previous completion.
- """
- b = event.current_buffer
-
- if b.complete_state:
- b.complete_previous()
- else:
- event.cli.start_completion(select_last=True)
-
- @handle(Keys.ControlY, filter=insert_mode)
- def _(event):
- """
- Accept current completion.
- """
- event.current_buffer.complete_state = None
-
- @handle(Keys.ControlE, filter=insert_mode)
- def _(event):
- """
- Cancel completion. Go back to originally typed text.
- """
- event.current_buffer.cancel_completion()
-
+ @handle(Keys.Backspace, filter=navigation_mode)
+ def _(event):
+ """
+ In navigation-mode, move cursor.
+ """
+ event.current_buffer.cursor_position += \
+ event.current_buffer.document.get_cursor_left_position(count=event.arg)
+
+ @handle(Keys.ControlN, filter=insert_mode)
+ def _(event):
+ b = event.current_buffer
+
+ if b.complete_state:
+ b.complete_next()
+ else:
+ event.cli.start_completion(select_first=True)
+
+ @handle(Keys.ControlP, filter=insert_mode)
+ def _(event):
+ """
+ Control-P: To previous completion.
+ """
+ b = event.current_buffer
+
+ if b.complete_state:
+ b.complete_previous()
+ else:
+ event.cli.start_completion(select_last=True)
+
+ @handle(Keys.ControlY, filter=insert_mode)
+ def _(event):
+ """
+ Accept current completion.
+ """
+ event.current_buffer.complete_state = None
+
+ @handle(Keys.ControlE, filter=insert_mode)
+ def _(event):
+ """
+ Cancel completion. Go back to originally typed text.
+ """
+ event.current_buffer.cancel_completion()
+
@handle(Keys.ControlJ, filter=navigation_mode) # XXX: only if the selected buffer has a return handler.
- def _(event):
- """
- In navigation mode, pressing enter will always return the input.
- """
- b = event.current_buffer
-
- if b.accept_action.is_returnable:
- b.accept_action.validate_and_handle(event.cli, b)
-
- # ** In navigation mode **
-
- # List of navigation commands: http://hea-www.harvard.edu/~fine/Tech/vi.html
-
- @handle(Keys.Insert, filter=navigation_mode)
- def _(event):
- " Presing the Insert key. "
+ def _(event):
+ """
+ In navigation mode, pressing enter will always return the input.
+ """
+ b = event.current_buffer
+
+ if b.accept_action.is_returnable:
+ b.accept_action.validate_and_handle(event.cli, b)
+
+ # ** In navigation mode **
+
+ # List of navigation commands: http://hea-www.harvard.edu/~fine/Tech/vi.html
+
+ @handle(Keys.Insert, filter=navigation_mode)
+ def _(event):
+ " Presing the Insert key. "
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('a', filter=navigation_mode & ~IsReadOnly())
- # ~IsReadOnly, because we want to stay in navigation mode for
- # read-only buffers.
- def _(event):
- event.current_buffer.cursor_position += event.current_buffer.document.get_cursor_right_position()
+
+ @handle('a', filter=navigation_mode & ~IsReadOnly())
+ # ~IsReadOnly, because we want to stay in navigation mode for
+ # read-only buffers.
+ def _(event):
+ event.current_buffer.cursor_position += event.current_buffer.document.get_cursor_right_position()
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('A', filter=navigation_mode & ~IsReadOnly())
- def _(event):
- event.current_buffer.cursor_position += event.current_buffer.document.get_end_of_line_position()
+
+ @handle('A', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
+ event.current_buffer.cursor_position += event.current_buffer.document.get_end_of_line_position()
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('C', filter=navigation_mode & ~IsReadOnly())
- def _(event):
- """
- # Change to end of line.
- # Same as 'c$' (which is implemented elsewhere.)
- """
- buffer = event.current_buffer
-
- deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
- event.cli.clipboard.set_text(deleted)
+
+ @handle('C', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
+ """
+ # Change to end of line.
+ # Same as 'c$' (which is implemented elsewhere.)
+ """
+ buffer = event.current_buffer
+
+ deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
+ event.cli.clipboard.set_text(deleted)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('c', 'c', filter=navigation_mode & ~IsReadOnly())
- @handle('S', filter=navigation_mode & ~IsReadOnly())
- def _(event): # TODO: implement 'arg'
- """
- Change current line
- """
- buffer = event.current_buffer
-
- # We copy the whole line.
- data = ClipboardData(buffer.document.current_line, SelectionType.LINES)
- event.cli.clipboard.set_data(data)
-
- # But we delete after the whitespace
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
- buffer.delete(count=buffer.document.get_end_of_line_position())
+
+ @handle('c', 'c', filter=navigation_mode & ~IsReadOnly())
+ @handle('S', filter=navigation_mode & ~IsReadOnly())
+ def _(event): # TODO: implement 'arg'
+ """
+ Change current line
+ """
+ buffer = event.current_buffer
+
+ # We copy the whole line.
+ data = ClipboardData(buffer.document.current_line, SelectionType.LINES)
+ event.cli.clipboard.set_data(data)
+
+ # But we delete after the whitespace
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+ buffer.delete(count=buffer.document.get_end_of_line_position())
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('D', filter=navigation_mode)
- def _(event):
- buffer = event.current_buffer
- deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
- event.cli.clipboard.set_text(deleted)
-
- @handle('d', 'd', filter=navigation_mode)
- def _(event):
- """
- Delete line. (Or the following 'n' lines.)
- """
- buffer = event.current_buffer
-
- # Split string in before/deleted/after text.
- lines = buffer.document.lines
-
- before = '\n'.join(lines[:buffer.document.cursor_position_row])
+
+ @handle('D', filter=navigation_mode)
+ def _(event):
+ buffer = event.current_buffer
+ deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
+ event.cli.clipboard.set_text(deleted)
+
+ @handle('d', 'd', filter=navigation_mode)
+ def _(event):
+ """
+ Delete line. (Or the following 'n' lines.)
+ """
+ buffer = event.current_buffer
+
+ # Split string in before/deleted/after text.
+ lines = buffer.document.lines
+
+ before = '\n'.join(lines[:buffer.document.cursor_position_row])
deleted = '\n'.join(lines[buffer.document.cursor_position_row:
buffer.document.cursor_position_row + event.arg])
- after = '\n'.join(lines[buffer.document.cursor_position_row + event.arg:])
-
- # Set new text.
- if before and after:
- before = before + '\n'
-
- # Set text and cursor position.
- buffer.document = Document(
- text=before + after,
- # Cursor At the start of the first 'after' line, after the leading whitespace.
- cursor_position = len(before) + len(after) - len(after.lstrip(' ')))
-
- # Set clipboard data
- event.cli.clipboard.set_data(ClipboardData(deleted, SelectionType.LINES))
-
+ after = '\n'.join(lines[buffer.document.cursor_position_row + event.arg:])
+
+ # Set new text.
+ if before and after:
+ before = before + '\n'
+
+ # Set text and cursor position.
+ buffer.document = Document(
+ text=before + after,
+ # Cursor At the start of the first 'after' line, after the leading whitespace.
+ cursor_position = len(before) + len(after) - len(after.lstrip(' ')))
+
+ # Set clipboard data
+ event.cli.clipboard.set_data(ClipboardData(deleted, SelectionType.LINES))
+
@handle('x', filter=selection_mode)
def _(event):
"""
@@ -561,16 +561,16 @@ def load_vi_bindings(get_search_state=None):
clipboard_data = event.current_buffer.cut_selection()
event.cli.clipboard.set_data(clipboard_data)
- @handle('i', filter=navigation_mode & ~IsReadOnly())
- def _(event):
+ @handle('i', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('I', filter=navigation_mode & ~IsReadOnly())
- def _(event):
+
+ @handle('I', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
event.cli.vi_state.input_mode = InputMode.INSERT
event.current_buffer.cursor_position += \
event.current_buffer.document.get_start_of_line_position(after_whitespace=True)
-
+
@Condition
def in_block_selection(cli):
buff = cli.current_buffer
@@ -603,17 +603,17 @@ def load_vi_bindings(get_search_state=None):
buff.exit_selection()
@handle('A', filter=in_block_selection & ~IsReadOnly())
- def _(event):
+ def _(event):
go_to_block_selection(event, after=True)
@handle('J', filter=navigation_mode & ~IsReadOnly())
def _(event):
" Join lines. "
- for i in range(event.arg):
- event.current_buffer.join_next_line()
-
+ for i in range(event.arg):
+ event.current_buffer.join_next_line()
+
@handle('g', 'J', filter=navigation_mode & ~IsReadOnly())
- def _(event):
+ def _(event):
" Join lines without space. "
for i in range(event.arg):
event.current_buffer.join_next_line(separator='')
@@ -621,33 +621,33 @@ def load_vi_bindings(get_search_state=None):
@handle('J', filter=selection_mode & ~IsReadOnly())
def _(event):
" Join selected lines. "
- event.current_buffer.join_selected_lines()
-
+ event.current_buffer.join_selected_lines()
+
@handle('g', 'J', filter=selection_mode & ~IsReadOnly())
def _(event):
" Join selected lines without space. "
event.current_buffer.join_selected_lines(separator='')
-
- @handle('p', filter=navigation_mode)
- def _(event):
- """
- Paste after
- """
- event.current_buffer.paste_clipboard_data(
- event.cli.clipboard.get_data(),
+
+ @handle('p', filter=navigation_mode)
+ def _(event):
+ """
+ Paste after
+ """
+ event.current_buffer.paste_clipboard_data(
+ event.cli.clipboard.get_data(),
count=event.arg,
paste_mode=PasteMode.VI_AFTER)
-
- @handle('P', filter=navigation_mode)
- def _(event):
- """
- Paste before
- """
- event.current_buffer.paste_clipboard_data(
- event.cli.clipboard.get_data(),
+
+ @handle('P', filter=navigation_mode)
+ def _(event):
+ """
+ Paste before
+ """
+ event.current_buffer.paste_clipboard_data(
+ event.cli.clipboard.get_data(),
count=event.arg,
paste_mode=PasteMode.VI_BEFORE)
-
+
@handle('"', Keys.Any, 'p', filter=navigation_mode)
def _(event):
" Paste from named register. "
@@ -668,190 +668,190 @@ def load_vi_bindings(get_search_state=None):
event.current_buffer.paste_clipboard_data(
data, count=event.arg, paste_mode=PasteMode.VI_BEFORE)
- @handle('r', Keys.Any, filter=navigation_mode)
- def _(event):
- """
- Replace single character under cursor
- """
- event.current_buffer.insert_text(event.data * event.arg, overwrite=True)
- event.current_buffer.cursor_position -= 1
-
- @handle('R', filter=navigation_mode)
- def _(event):
- """
- Go to 'replace'-mode.
- """
+ @handle('r', Keys.Any, filter=navigation_mode)
+ def _(event):
+ """
+ Replace single character under cursor
+ """
+ event.current_buffer.insert_text(event.data * event.arg, overwrite=True)
+ event.current_buffer.cursor_position -= 1
+
+ @handle('R', filter=navigation_mode)
+ def _(event):
+ """
+ Go to 'replace'-mode.
+ """
event.cli.vi_state.input_mode = InputMode.REPLACE
-
- @handle('s', filter=navigation_mode & ~IsReadOnly())
- def _(event):
- """
- Substitute with new text
- (Delete character(s) and go to insert mode.)
- """
- text = event.current_buffer.delete(count=event.arg)
- event.cli.clipboard.set_text(text)
+
+ @handle('s', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
+ """
+ Substitute with new text
+ (Delete character(s) and go to insert mode.)
+ """
+ text = event.current_buffer.delete(count=event.arg)
+ event.cli.clipboard.set_text(text)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('u', filter=navigation_mode, save_before=(lambda e: False))
- def _(event):
- for i in range(event.arg):
- event.current_buffer.undo()
-
- @handle('V', filter=navigation_mode)
- def _(event):
- """
- Start lines selection.
- """
- event.current_buffer.start_selection(selection_type=SelectionType.LINES)
-
- @handle(Keys.ControlV, filter=navigation_mode)
- def _(event):
- " Enter block selection mode. "
- event.current_buffer.start_selection(selection_type=SelectionType.BLOCK)
-
- @handle('V', filter=selection_mode)
- def _(event):
- """
- Exit line selection mode, or go from non line selection mode to line
- selection mode.
- """
- selection_state = event.current_buffer.selection_state
-
- if selection_state.type != SelectionType.LINES:
- selection_state.type = SelectionType.LINES
- else:
- event.current_buffer.exit_selection()
-
+
+ @handle('u', filter=navigation_mode, save_before=(lambda e: False))
+ def _(event):
+ for i in range(event.arg):
+ event.current_buffer.undo()
+
+ @handle('V', filter=navigation_mode)
+ def _(event):
+ """
+ Start lines selection.
+ """
+ event.current_buffer.start_selection(selection_type=SelectionType.LINES)
+
+ @handle(Keys.ControlV, filter=navigation_mode)
+ def _(event):
+ " Enter block selection mode. "
+ event.current_buffer.start_selection(selection_type=SelectionType.BLOCK)
+
+ @handle('V', filter=selection_mode)
+ def _(event):
+ """
+ Exit line selection mode, or go from non line selection mode to line
+ selection mode.
+ """
+ selection_state = event.current_buffer.selection_state
+
+ if selection_state.type != SelectionType.LINES:
+ selection_state.type = SelectionType.LINES
+ else:
+ event.current_buffer.exit_selection()
+
@handle('v', filter=navigation_mode)
- def _(event):
- " Enter character selection mode. "
- event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS)
-
- @handle('v', filter=selection_mode)
- def _(event):
- """
- Exit character selection mode, or go from non-character-selection mode
- to character selection mode.
- """
- selection_state = event.current_buffer.selection_state
-
- if selection_state.type != SelectionType.CHARACTERS:
- selection_state.type = SelectionType.CHARACTERS
- else:
- event.current_buffer.exit_selection()
-
- @handle(Keys.ControlV, filter=selection_mode)
- def _(event):
- """
- Exit block selection mode, or go from non block selection mode to block
- selection mode.
- """
- selection_state = event.current_buffer.selection_state
-
- if selection_state.type != SelectionType.BLOCK:
- selection_state.type = SelectionType.BLOCK
- else:
- event.current_buffer.exit_selection()
-
-
- @handle('a', 'w', filter=selection_mode)
- @handle('a', 'W', filter=selection_mode)
- def _(event):
- """
- Switch from visual linewise mode to visual characterwise mode.
- """
- buffer = event.current_buffer
-
- if buffer.selection_state and buffer.selection_state.type == SelectionType.LINES:
- buffer.selection_state.type = SelectionType.CHARACTERS
-
- @handle('x', filter=navigation_mode)
- def _(event):
- """
- Delete character.
- """
- text = event.current_buffer.delete(count=event.arg)
- event.cli.clipboard.set_text(text)
-
- @handle('X', filter=navigation_mode)
- def _(event):
- text = event.current_buffer.delete_before_cursor()
- event.cli.clipboard.set_text(text)
-
- @handle('y', 'y', filter=navigation_mode)
- @handle('Y', filter=navigation_mode)
- def _(event):
- """
- Yank the whole line.
- """
- text = '\n'.join(event.current_buffer.document.lines_from_current[:event.arg])
- event.cli.clipboard.set_data(ClipboardData(text, SelectionType.LINES))
-
- @handle('+', filter=navigation_mode)
- def _(event):
- """
- Move to first non whitespace of next line
- """
- buffer = event.current_buffer
- buffer.cursor_position += buffer.document.get_cursor_down_position(count=event.arg)
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
-
- @handle('-', filter=navigation_mode)
- def _(event):
- """
- Move to first non whitespace of previous line
- """
- buffer = event.current_buffer
- buffer.cursor_position += buffer.document.get_cursor_up_position(count=event.arg)
- buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
-
- @handle('>', '>', filter=navigation_mode)
- def _(event):
- """
- Indent lines.
- """
- buffer = event.current_buffer
- current_row = buffer.document.cursor_position_row
- indent(buffer, current_row, current_row + event.arg)
-
- @handle('<', '<', filter=navigation_mode)
- def _(event):
- """
- Unindent lines.
- """
- current_row = event.current_buffer.document.cursor_position_row
- unindent(event.current_buffer, current_row, current_row + event.arg)
-
- @handle('O', filter=navigation_mode & ~IsReadOnly())
- def _(event):
- """
- Open line above and enter insertion mode
- """
- event.current_buffer.insert_line_above(
- copy_margin=not event.cli.in_paste_mode)
+ def _(event):
+ " Enter character selection mode. "
+ event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS)
+
+ @handle('v', filter=selection_mode)
+ def _(event):
+ """
+ Exit character selection mode, or go from non-character-selection mode
+ to character selection mode.
+ """
+ selection_state = event.current_buffer.selection_state
+
+ if selection_state.type != SelectionType.CHARACTERS:
+ selection_state.type = SelectionType.CHARACTERS
+ else:
+ event.current_buffer.exit_selection()
+
+ @handle(Keys.ControlV, filter=selection_mode)
+ def _(event):
+ """
+ Exit block selection mode, or go from non block selection mode to block
+ selection mode.
+ """
+ selection_state = event.current_buffer.selection_state
+
+ if selection_state.type != SelectionType.BLOCK:
+ selection_state.type = SelectionType.BLOCK
+ else:
+ event.current_buffer.exit_selection()
+
+
+ @handle('a', 'w', filter=selection_mode)
+ @handle('a', 'W', filter=selection_mode)
+ def _(event):
+ """
+ Switch from visual linewise mode to visual characterwise mode.
+ """
+ buffer = event.current_buffer
+
+ if buffer.selection_state and buffer.selection_state.type == SelectionType.LINES:
+ buffer.selection_state.type = SelectionType.CHARACTERS
+
+ @handle('x', filter=navigation_mode)
+ def _(event):
+ """
+ Delete character.
+ """
+ text = event.current_buffer.delete(count=event.arg)
+ event.cli.clipboard.set_text(text)
+
+ @handle('X', filter=navigation_mode)
+ def _(event):
+ text = event.current_buffer.delete_before_cursor()
+ event.cli.clipboard.set_text(text)
+
+ @handle('y', 'y', filter=navigation_mode)
+ @handle('Y', filter=navigation_mode)
+ def _(event):
+ """
+ Yank the whole line.
+ """
+ text = '\n'.join(event.current_buffer.document.lines_from_current[:event.arg])
+ event.cli.clipboard.set_data(ClipboardData(text, SelectionType.LINES))
+
+ @handle('+', filter=navigation_mode)
+ def _(event):
+ """
+ Move to first non whitespace of next line
+ """
+ buffer = event.current_buffer
+ buffer.cursor_position += buffer.document.get_cursor_down_position(count=event.arg)
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+
+ @handle('-', filter=navigation_mode)
+ def _(event):
+ """
+ Move to first non whitespace of previous line
+ """
+ buffer = event.current_buffer
+ buffer.cursor_position += buffer.document.get_cursor_up_position(count=event.arg)
+ buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
+
+ @handle('>', '>', filter=navigation_mode)
+ def _(event):
+ """
+ Indent lines.
+ """
+ buffer = event.current_buffer
+ current_row = buffer.document.cursor_position_row
+ indent(buffer, current_row, current_row + event.arg)
+
+ @handle('<', '<', filter=navigation_mode)
+ def _(event):
+ """
+ Unindent lines.
+ """
+ current_row = event.current_buffer.document.cursor_position_row
+ unindent(event.current_buffer, current_row, current_row + event.arg)
+
+ @handle('O', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
+ """
+ Open line above and enter insertion mode
+ """
+ event.current_buffer.insert_line_above(
+ copy_margin=not event.cli.in_paste_mode)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('o', filter=navigation_mode & ~IsReadOnly())
- def _(event):
- """
- Open line below and enter insertion mode
- """
- event.current_buffer.insert_line_below(
- copy_margin=not event.cli.in_paste_mode)
+
+ @handle('o', filter=navigation_mode & ~IsReadOnly())
+ def _(event):
+ """
+ Open line below and enter insertion mode
+ """
+ event.current_buffer.insert_line_below(
+ copy_margin=not event.cli.in_paste_mode)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle('~', filter=navigation_mode)
- def _(event):
- """
- Reverse case of current character and move cursor forward.
- """
- buffer = event.current_buffer
- c = buffer.document.current_char
-
- if c is not None and c != '\n':
+
+ @handle('~', filter=navigation_mode)
+ def _(event):
+ """
+ Reverse case of current character and move cursor forward.
+ """
+ buffer = event.current_buffer
+ c = buffer.document.current_char
+
+ if c is not None and c != '\n':
buffer.insert_text(c.swapcase(), overwrite=True)
-
+
@handle('g', 'u', 'u', filter=navigation_mode & ~IsReadOnly())
def _(event):
" Lowercase current line. "
@@ -870,64 +870,64 @@ def load_vi_bindings(get_search_state=None):
buff = event.current_buffer
buff.transform_current_line(lambda s: s.swapcase())
- @handle('#', filter=navigation_mode)
- def _(event):
- """
- Go to previous occurence of this word.
- """
- b = event.cli.current_buffer
-
- search_state = get_search_state(event.cli)
- search_state.text = b.document.get_word_under_cursor()
- search_state.direction = IncrementalSearchDirection.BACKWARD
-
- b.apply_search(search_state, count=event.arg,
- include_current_position=False)
-
- @handle('*', filter=navigation_mode)
- def _(event):
- """
- Go to next occurence of this word.
- """
- b = event.cli.current_buffer
-
- search_state = get_search_state(event.cli)
- search_state.text = b.document.get_word_under_cursor()
- search_state.direction = IncrementalSearchDirection.FORWARD
-
- b.apply_search(search_state, count=event.arg,
- include_current_position=False)
-
- @handle('(', filter=navigation_mode)
- def _(event):
- # TODO: go to begin of sentence.
+ @handle('#', filter=navigation_mode)
+ def _(event):
+ """
+ Go to previous occurence of this word.
+ """
+ b = event.cli.current_buffer
+
+ search_state = get_search_state(event.cli)
+ search_state.text = b.document.get_word_under_cursor()
+ search_state.direction = IncrementalSearchDirection.BACKWARD
+
+ b.apply_search(search_state, count=event.arg,
+ include_current_position=False)
+
+ @handle('*', filter=navigation_mode)
+ def _(event):
+ """
+ Go to next occurence of this word.
+ """
+ b = event.cli.current_buffer
+
+ search_state = get_search_state(event.cli)
+ search_state.text = b.document.get_word_under_cursor()
+ search_state.direction = IncrementalSearchDirection.FORWARD
+
+ b.apply_search(search_state, count=event.arg,
+ include_current_position=False)
+
+ @handle('(', filter=navigation_mode)
+ def _(event):
+ # TODO: go to begin of sentence.
# XXX: should become text_object.
- pass
-
- @handle(')', filter=navigation_mode)
- def _(event):
- # TODO: go to end of sentence.
+ pass
+
+ @handle(')', filter=navigation_mode)
+ def _(event):
+ # TODO: go to end of sentence.
# XXX: should become text_object.
- pass
-
+ pass
+
operator = create_operator_decorator(registry)
text_object = create_text_object_decorator(registry)
-
+
@text_object(Keys.Any, filter=operator_given)
def _(event):
"""
Unknown key binding while waiting for a text object.
"""
event.cli.output.bell()
-
+
#
# *** Operators ***
#
-
+
def create_delete_and_change_operators(delete_only, with_register=False):
"""
Delete and change operators.
-
+
:param delete_only: Create an operator that deletes, but doesn't go to insert mode.
:param with_register: Copy the deleted text to this named register instead of the clipboard.
"""
@@ -935,16 +935,16 @@ def load_vi_bindings(get_search_state=None):
handler_keys = ('"', Keys.Any, 'cd'[delete_only])
else:
handler_keys = 'cd'[delete_only]
-
+
@operator(*handler_keys, filter=~IsReadOnly())
def delete_or_change_operator(event, text_object):
clipboard_data = None
buff = event.current_buffer
-
+
if text_object:
new_document, clipboard_data = text_object.cut(buff)
buff.document = new_document
-
+
# Set deleted/changed text to clipboard or named register.
if clipboard_data and clipboard_data.text:
if with_register:
@@ -953,11 +953,11 @@ def load_vi_bindings(get_search_state=None):
event.cli.vi_state.named_registers[reg_name] = clipboard_data
else:
event.cli.clipboard.set_data(clipboard_data)
-
+
# Only go back to insert mode in case of 'change'.
if not delete_only:
event.cli.vi_state.input_mode = InputMode.INSERT
-
+
create_delete_and_change_operators(False, False)
create_delete_and_change_operators(False, True)
create_delete_and_change_operators(True, False)
@@ -1034,68 +1034,68 @@ def load_vi_bindings(get_search_state=None):
#
@text_object('b')
- def _(event):
- """ Move one word or token left. """
+ def _(event):
+ """ Move one word or token left. """
return TextObject(event.current_buffer.document.find_start_of_previous_word(count=event.arg) or 0)
-
+
@text_object('B')
- def _(event):
- """ Move one non-blank word left """
+ def _(event):
+ """ Move one non-blank word left """
return TextObject(event.current_buffer.document.find_start_of_previous_word(count=event.arg, WORD=True) or 0)
-
+
@text_object('$')
- def key_dollar(event):
- """ 'c$', 'd$' and '$': Delete/change/move until end of line. """
+ def key_dollar(event):
+ """ 'c$', 'd$' and '$': Delete/change/move until end of line. """
return TextObject(event.current_buffer.document.get_end_of_line_position())
-
+
@text_object('w')
- def _(event):
- """ 'word' forward. 'cw', 'dw', 'w': Delete/change/move one word. """
+ def _(event):
+ """ 'word' forward. 'cw', 'dw', 'w': Delete/change/move one word. """
return TextObject(event.current_buffer.document.find_next_word_beginning(count=event.arg) or
- event.current_buffer.document.get_end_of_document_position())
-
+ event.current_buffer.document.get_end_of_document_position())
+
@text_object('W')
- def _(event):
- """ 'WORD' forward. 'cW', 'dW', 'W': Delete/change/move one WORD. """
+ def _(event):
+ """ 'WORD' forward. 'cW', 'dW', 'W': Delete/change/move one WORD. """
return TextObject(event.current_buffer.document.find_next_word_beginning(count=event.arg, WORD=True) or
- event.current_buffer.document.get_end_of_document_position())
-
+ event.current_buffer.document.get_end_of_document_position())
+
@text_object('e')
- def _(event):
- """ End of 'word': 'ce', 'de', 'e' """
- end = event.current_buffer.document.find_next_word_ending(count=event.arg)
+ def _(event):
+ """ End of 'word': 'ce', 'de', 'e' """
+ end = event.current_buffer.document.find_next_word_ending(count=event.arg)
return TextObject(end - 1 if end else 0, type=TextObjectType.INCLUSIVE)
-
+
@text_object('E')
- def _(event):
- """ End of 'WORD': 'cE', 'dE', 'E' """
- end = event.current_buffer.document.find_next_word_ending(count=event.arg, WORD=True)
+ def _(event):
+ """ End of 'WORD': 'cE', 'dE', 'E' """
+ end = event.current_buffer.document.find_next_word_ending(count=event.arg, WORD=True)
return TextObject(end - 1 if end else 0, type=TextObjectType.INCLUSIVE)
-
+
@text_object('i', 'w', no_move_handler=True)
- def _(event):
- """ Inner 'word': ciw and diw """
- start, end = event.current_buffer.document.find_boundaries_of_current_word()
+ def _(event):
+ """ Inner 'word': ciw and diw """
+ start, end = event.current_buffer.document.find_boundaries_of_current_word()
return TextObject(start, end)
-
+
@text_object('a', 'w', no_move_handler=True)
- def _(event):
- """ A 'word': caw and daw """
- start, end = event.current_buffer.document.find_boundaries_of_current_word(include_trailing_whitespace=True)
+ def _(event):
+ """ A 'word': caw and daw """
+ start, end = event.current_buffer.document.find_boundaries_of_current_word(include_trailing_whitespace=True)
return TextObject(start, end)
-
+
@text_object('i', 'W', no_move_handler=True)
- def _(event):
- """ Inner 'WORD': ciW and diW """
- start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True)
+ def _(event):
+ """ Inner 'WORD': ciW and diW """
+ start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True)
return TextObject(start, end)
-
+
@text_object('a', 'W', no_move_handler=True)
- def _(event):
- """ A 'WORD': caw and daw """
- start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True, include_trailing_whitespace=True)
+ def _(event):
+ """ A 'WORD': caw and daw """
+ start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True, include_trailing_whitespace=True)
return TextObject(start, end)
-
+
@text_object('a', 'p', no_move_handler=True)
def _(event):
"""
@@ -1106,24 +1106,24 @@ def load_vi_bindings(get_search_state=None):
return TextObject(start, end)
@text_object('^')
- def key_circumflex(event):
- """ 'c^', 'd^' and '^': Soft start of line, after whitespace. """
+ def key_circumflex(event):
+ """ 'c^', 'd^' and '^': Soft start of line, after whitespace. """
return TextObject(event.current_buffer.document.get_start_of_line_position(after_whitespace=True))
-
+
@text_object('0')
- def key_zero(event):
- """
- 'c0', 'd0': Hard start of line, before whitespace.
- (The move '0' key is implemented elsewhere, because a '0' could also change the `arg`.)
- """
+ def key_zero(event):
+ """
+ 'c0', 'd0': Hard start of line, before whitespace.
+ (The move '0' key is implemented elsewhere, because a '0' could also change the `arg`.)
+ """
return TextObject(event.current_buffer.document.get_start_of_line_position(after_whitespace=False))
-
+
def create_ci_ca_handles(ci_start, ci_end, inner, key=None):
- # TODO: 'dat', 'dit', (tags (like xml)
- """
- Delete/Change string between this start and stop character. But keep these characters.
- This implements all the ci", ci<, ci{, ci(, di", di<, ca", ca<, ... combinations.
- """
+ # TODO: 'dat', 'dit', (tags (like xml)
+ """
+ Delete/Change string between this start and stop character. But keep these characters.
+ This implements all the ci", ci<, ci{, ci(, di", di<, ca", ca<, ... combinations.
+ """
def handler(event):
if ci_start == ci_end:
# Quotes
@@ -1133,53 +1133,53 @@ def load_vi_bindings(get_search_state=None):
# Brackets
start = event.current_buffer.document.find_enclosing_bracket_left(ci_start, ci_end)
end = event.current_buffer.document.find_enclosing_bracket_right(ci_start, ci_end)
-
- if start is not None and end is not None:
- offset = 0 if inner else 1
+
+ if start is not None and end is not None:
+ offset = 0 if inner else 1
return TextObject(start + 1 - offset, end + offset)
- else:
- # Nothing found.
+ else:
+ # Nothing found.
return TextObject(0)
-
+
if key is None:
text_object('ai'[inner], ci_start, no_move_handler=True)(handler)
text_object('ai'[inner], ci_end, no_move_handler=True)(handler)
else:
text_object('ai'[inner], key, no_move_handler=True)(handler)
- for inner in (False, True):
- for ci_start, ci_end in [('"', '"'), ("'", "'"), ("`", "`"),
- ('[', ']'), ('<', '>'), ('{', '}'), ('(', ')')]:
- create_ci_ca_handles(ci_start, ci_end, inner)
-
+ for inner in (False, True):
+ for ci_start, ci_end in [('"', '"'), ("'", "'"), ("`", "`"),
+ ('[', ']'), ('<', '>'), ('{', '}'), ('(', ')')]:
+ create_ci_ca_handles(ci_start, ci_end, inner)
+
create_ci_ca_handles('(', ')', inner, 'b') # 'dab', 'dib'
create_ci_ca_handles('{', '}', inner, 'B') # 'daB', 'diB'
@text_object('{')
- def _(event):
- """
- Move to previous blank-line separated section.
- Implements '{', 'c{', 'd{', 'y{'
- """
+ def _(event):
+ """
+ Move to previous blank-line separated section.
+ Implements '{', 'c{', 'd{', 'y{'
+ """
index = event.current_buffer.document.start_of_paragraph(
count=event.arg, before=True)
return TextObject(index)
-
+
@text_object('}')
- def _(event):
- """
- Move to next blank-line separated section.
- Implements '}', 'c}', 'd}', 'y}'
- """
+ def _(event):
+ """
+ Move to next blank-line separated section.
+ Implements '}', 'c}', 'd}', 'y}'
+ """
index = event.current_buffer.document.end_of_paragraph(count=event.arg, after=True)
return TextObject(index)
-
+
@text_object('f', Keys.Any)
- def _(event):
- """
- Go to next occurance of character. Typing 'fx' will move the
- cursor to the next occurance of character. 'x'.
- """
+ def _(event):
+ """
+ Go to next occurance of character. Typing 'fx' will move the
+ cursor to the next occurance of character. 'x'.
+ """
event.cli.vi_state.last_character_find = CharacterFind(event.data, False)
match = event.current_buffer.document.find(
event.data, in_current_line=True, count=event.arg)
@@ -1187,22 +1187,22 @@ def load_vi_bindings(get_search_state=None):
return TextObject(match, type=TextObjectType.INCLUSIVE)
else:
return TextObject(0)
-
+
@text_object('F', Keys.Any)
- def _(event):
- """
- Go to previous occurance of character. Typing 'Fx' will move the
- cursor to the previous occurance of character. 'x'.
- """
+ def _(event):
+ """
+ Go to previous occurance of character. Typing 'Fx' will move the
+ cursor to the previous occurance of character. 'x'.
+ """
event.cli.vi_state.last_character_find = CharacterFind(event.data, True)
return TextObject(event.current_buffer.document.find_backwards(
event.data, in_current_line=True, count=event.arg) or 0)
-
+
@text_object('t', Keys.Any)
- def _(event):
- """
- Move right to the next occurance of c, then one char backward.
- """
+ def _(event):
+ """
+ Move right to the next occurance of c, then one char backward.
+ """
event.cli.vi_state.last_character_find = CharacterFind(event.data, False)
match = event.current_buffer.document.find(
event.data, in_current_line=True, count=event.arg)
@@ -1210,138 +1210,138 @@ def load_vi_bindings(get_search_state=None):
return TextObject(match - 1, type=TextObjectType.INCLUSIVE)
else:
return TextObject(0)
-
+
@text_object('T', Keys.Any)
- def _(event):
- """
- Move left to the previous occurance of c, then one char forward.
- """
+ def _(event):
+ """
+ Move left to the previous occurance of c, then one char forward.
+ """
event.cli.vi_state.last_character_find = CharacterFind(event.data, True)
match = event.current_buffer.document.find_backwards(
event.data, in_current_line=True, count=event.arg)
return TextObject(match + 1 if match else 0)
-
- def repeat(reverse):
- """
- Create ',' and ';' commands.
- """
+
+ def repeat(reverse):
+ """
+ Create ',' and ';' commands.
+ """
@text_object(',' if reverse else ';')
- def _(event):
- # Repeat the last 'f'/'F'/'t'/'T' command.
- pos = 0
+ def _(event):
+ # Repeat the last 'f'/'F'/'t'/'T' command.
+ pos = 0
vi_state = event.cli.vi_state
-
+
type = TextObjectType.EXCLUSIVE
- if vi_state.last_character_find:
- char = vi_state.last_character_find.character
- backwards = vi_state.last_character_find.backwards
-
- if reverse:
- backwards = not backwards
-
- if backwards:
- pos = event.current_buffer.document.find_backwards(char, in_current_line=True, count=event.arg)
- else:
- pos = event.current_buffer.document.find(char, in_current_line=True, count=event.arg)
+ if vi_state.last_character_find:
+ char = vi_state.last_character_find.character
+ backwards = vi_state.last_character_find.backwards
+
+ if reverse:
+ backwards = not backwards
+
+ if backwards:
+ pos = event.current_buffer.document.find_backwards(char, in_current_line=True, count=event.arg)
+ else:
+ pos = event.current_buffer.document.find(char, in_current_line=True, count=event.arg)
type = TextObjectType.INCLUSIVE
if pos:
return TextObject(pos, type=type)
else:
return TextObject(0)
- repeat(True)
- repeat(False)
-
+ repeat(True)
+ repeat(False)
+
@text_object('h')
@text_object(Keys.Left)
- def _(event):
- """ Implements 'ch', 'dh', 'h': Cursor left. """
+ def _(event):
+ """ Implements 'ch', 'dh', 'h': Cursor left. """
return TextObject(event.current_buffer.document.get_cursor_left_position(count=event.arg))
-
+
@text_object('j', no_move_handler=True, no_selection_handler=True)
# Note: We also need `no_selection_handler`, because we in
# selection mode, we prefer the other 'j' binding that keeps
# `buffer.preferred_column`.
- def _(event):
- """ Implements 'cj', 'dj', 'j', ... Cursor up. """
+ def _(event):
+ """ Implements 'cj', 'dj', 'j', ... Cursor up. """
return TextObject(event.current_buffer.document.get_cursor_down_position(count=event.arg),
type=TextObjectType.LINEWISE)
-
+
@text_object('k', no_move_handler=True, no_selection_handler=True)
- def _(event):
- """ Implements 'ck', 'dk', 'k', ... Cursor up. """
+ def _(event):
+ """ Implements 'ck', 'dk', 'k', ... Cursor up. """
return TextObject(event.current_buffer.document.get_cursor_up_position(count=event.arg),
type=TextObjectType.LINEWISE)
-
+
@text_object('l')
@text_object(' ')
@text_object(Keys.Right)
- def _(event):
- """ Implements 'cl', 'dl', 'l', 'c ', 'd ', ' '. Cursor right. """
+ def _(event):
+ """ Implements 'cl', 'dl', 'l', 'c ', 'd ', ' '. Cursor right. """
return TextObject(event.current_buffer.document.get_cursor_right_position(count=event.arg))
-
+
@text_object('H')
- def _(event):
- """
- Moves to the start of the visible region. (Below the scroll offset.)
- Implements 'cH', 'dH', 'H'.
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.current_buffer
-
+ def _(event):
+ """
+ Moves to the start of the visible region. (Below the scroll offset.)
+ Implements 'cH', 'dH', 'H'.
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.current_buffer
+
if w and w.render_info:
- # When we find a Window that has BufferControl showing this window,
- # move to the start of the visible area.
- pos = (b.document.translate_row_col_to_index(
- w.render_info.first_visible_line(after_scroll_offset=True), 0) -
- b.cursor_position)
-
- else:
- # Otherwise, move to the start of the input.
- pos = -len(b.document.text_before_cursor)
+ # When we find a Window that has BufferControl showing this window,
+ # move to the start of the visible area.
+ pos = (b.document.translate_row_col_to_index(
+ w.render_info.first_visible_line(after_scroll_offset=True), 0) -
+ b.cursor_position)
+
+ else:
+ # Otherwise, move to the start of the input.
+ pos = -len(b.document.text_before_cursor)
return TextObject(pos, type=TextObjectType.LINEWISE)
-
+
@text_object('M')
- def _(event):
- """
- Moves cursor to the vertical center of the visible region.
- Implements 'cM', 'dM', 'M'.
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.current_buffer
-
+ def _(event):
+ """
+ Moves cursor to the vertical center of the visible region.
+ Implements 'cM', 'dM', 'M'.
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.current_buffer
+
if w and w.render_info:
- # When we find a Window that has BufferControl showing this window,
- # move to the center of the visible area.
- pos = (b.document.translate_row_col_to_index(
- w.render_info.center_visible_line(), 0) -
- b.cursor_position)
-
- else:
- # Otherwise, move to the start of the input.
- pos = -len(b.document.text_before_cursor)
+ # When we find a Window that has BufferControl showing this window,
+ # move to the center of the visible area.
+ pos = (b.document.translate_row_col_to_index(
+ w.render_info.center_visible_line(), 0) -
+ b.cursor_position)
+
+ else:
+ # Otherwise, move to the start of the input.
+ pos = -len(b.document.text_before_cursor)
return TextObject(pos, type=TextObjectType.LINEWISE)
-
+
@text_object('L')
- def _(event):
- """
- Moves to the end of the visible region. (Above the scroll offset.)
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.current_buffer
-
+ def _(event):
+ """
+ Moves to the end of the visible region. (Above the scroll offset.)
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.current_buffer
+
if w and w.render_info:
- # When we find a Window that has BufferControl showing this window,
- # move to the end of the visible area.
- pos = (b.document.translate_row_col_to_index(
- w.render_info.last_visible_line(before_scroll_offset=True), 0) -
- b.cursor_position)
-
- else:
- # Otherwise, move to the end of the input.
- pos = len(b.document.text_after_cursor)
+ # When we find a Window that has BufferControl showing this window,
+ # move to the end of the visible area.
+ pos = (b.document.translate_row_col_to_index(
+ w.render_info.last_visible_line(before_scroll_offset=True), 0) -
+ b.cursor_position)
+
+ else:
+ # Otherwise, move to the end of the input.
+ pos = len(b.document.text_after_cursor)
return TextObject(pos, type=TextObjectType.LINEWISE)
-
+
@text_object('n', no_move_handler=True)
def _(event):
" Search next. "
@@ -1374,50 +1374,50 @@ def load_vi_bindings(get_search_state=None):
~get_search_state(event.cli), include_current_position=False,
count=event.arg)
- @handle('z', '+', filter=navigation_mode|selection_mode)
- @handle('z', 't', filter=navigation_mode|selection_mode)
- @handle('z', Keys.ControlJ, filter=navigation_mode|selection_mode)
- def _(event):
- """
- Scrolls the window to makes the current line the first line in the visible region.
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.cli.current_buffer
+ @handle('z', '+', filter=navigation_mode|selection_mode)
+ @handle('z', 't', filter=navigation_mode|selection_mode)
+ @handle('z', Keys.ControlJ, filter=navigation_mode|selection_mode)
+ def _(event):
+ """
+ Scrolls the window to makes the current line the first line in the visible region.
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.cli.current_buffer
w.vertical_scroll = b.document.cursor_position_row
-
- @handle('z', '-', filter=navigation_mode|selection_mode)
- @handle('z', 'b', filter=navigation_mode|selection_mode)
- def _(event):
- """
- Scrolls the window to makes the current line the last line in the visible region.
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
-
+
+ @handle('z', '-', filter=navigation_mode|selection_mode)
+ @handle('z', 'b', filter=navigation_mode|selection_mode)
+ def _(event):
+ """
+ Scrolls the window to makes the current line the last line in the visible region.
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+
# We can safely set the scroll offset to zero; the Window will meke
# sure that it scrolls at least enough to make the cursor visible
# again.
w.vertical_scroll = 0
-
- @handle('z', 'z', filter=navigation_mode|selection_mode)
- def _(event):
- """
- Center Window vertically around cursor.
- """
- w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
- b = event.cli.current_buffer
-
- if w and w.render_info:
+
+ @handle('z', 'z', filter=navigation_mode|selection_mode)
+ def _(event):
+ """
+ Center Window vertically around cursor.
+ """
+ w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
+ b = event.cli.current_buffer
+
+ if w and w.render_info:
info = w.render_info
- # Calculate the offset that we need in order to position the row
- # containing the cursor in the center.
+ # Calculate the offset that we need in order to position the row
+ # containing the cursor in the center.
scroll_height = info.window_height // 2
-
+
y = max(0, b.document.cursor_position_row - 1)
height = 0
while y > 0:
line_height = info.get_height_for_line(y)
-
+
if height + line_height < scroll_height:
height += line_height
y -= 1
@@ -1427,81 +1427,81 @@ def load_vi_bindings(get_search_state=None):
w.vertical_scroll = y
@text_object('%')
- def _(event):
- """
- Implements 'c%', 'd%', '%, 'y%' (Move to corresponding bracket.)
- If an 'arg' has been given, go this this % position in the file.
- """
- buffer = event.current_buffer
-
- if event._arg:
- # If 'arg' has been given, the meaning of % is to go to the 'x%'
- # row in the file.
- if 0 < event.arg <= 100:
- absolute_index = buffer.document.translate_row_col_to_index(
+ def _(event):
+ """
+ Implements 'c%', 'd%', '%, 'y%' (Move to corresponding bracket.)
+ If an 'arg' has been given, go this this % position in the file.
+ """
+ buffer = event.current_buffer
+
+ if event._arg:
+ # If 'arg' has been given, the meaning of % is to go to the 'x%'
+ # row in the file.
+ if 0 < event.arg <= 100:
+ absolute_index = buffer.document.translate_row_col_to_index(
int((event.arg * buffer.document.line_count - 1) / 100), 0)
return TextObject(absolute_index - buffer.document.cursor_position, type=TextObjectType.LINEWISE)
- else:
+ else:
return TextObject(0) # Do nothing.
-
- else:
- # Move to the corresponding opening/closing bracket (()'s, []'s and {}'s).
+
+ else:
+ # Move to the corresponding opening/closing bracket (()'s, []'s and {}'s).
match = buffer.document.find_matching_bracket_position()
if match:
return TextObject(match, type=TextObjectType.INCLUSIVE)
else:
return TextObject(0)
-
+
@text_object('|')
- def _(event):
- # Move to the n-th column (you may specify the argument n by typing
- # it on number keys, for example, 20|).
+ def _(event):
+ # Move to the n-th column (you may specify the argument n by typing
+ # it on number keys, for example, 20|).
return TextObject(event.current_buffer.document.get_column_cursor_position(event.arg - 1))
-
+
@text_object('g', 'g')
- def _(event):
- """
- Implements 'gg', 'cgg', 'ygg'
- """
- d = event.current_buffer.document
-
- if event._arg:
- # Move to the given line.
+ def _(event):
+ """
+ Implements 'gg', 'cgg', 'ygg'
+ """
+ d = event.current_buffer.document
+
+ if event._arg:
+ # Move to the given line.
return TextObject(d.translate_row_col_to_index(event.arg - 1, 0) - d.cursor_position, type=TextObjectType.LINEWISE)
- else:
- # Move to the top of the input.
+ else:
+ # Move to the top of the input.
return TextObject(d.get_start_of_document_position(), type=TextObjectType.LINEWISE)
-
+
@text_object('g', '_')
- def _(event):
- """
- Go to last non-blank of line.
- 'g_', 'cg_', 'yg_', etc..
- """
+ def _(event):
+ """
+ Go to last non-blank of line.
+ 'g_', 'cg_', 'yg_', etc..
+ """
return TextObject(
event.current_buffer.document.last_non_blank_of_current_line_position(), type=TextObjectType.INCLUSIVE)
-
+
@text_object('g', 'e')
- def _(event):
- """
- Go to last character of previous word.
- 'ge', 'cge', 'yge', etc..
- """
+ def _(event):
+ """
+ Go to last character of previous word.
+ 'ge', 'cge', 'yge', etc..
+ """
prev_end = event.current_buffer.document.find_previous_word_ending(count=event.arg)
return TextObject(prev_end - 1 if prev_end is not None else 0, type=TextObjectType.INCLUSIVE)
-
+
@text_object('g', 'E')
- def _(event):
- """
- Go to last character of previous WORD.
- 'gE', 'cgE', 'ygE', etc..
- """
+ def _(event):
+ """
+ Go to last character of previous WORD.
+ 'gE', 'cgE', 'ygE', etc..
+ """
prev_end = event.current_buffer.document.find_previous_word_ending(count=event.arg, WORD=True)
return TextObject(prev_end - 1 if prev_end is not None else 0, type=TextObjectType.INCLUSIVE)
-
+
@text_object('g', 'm')
- def _(event):
- """
+ def _(event):
+ """
Like g0, but half a screenwidth to the right. (Or as much as possible.)
"""
w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
@@ -1518,58 +1518,58 @@ def load_vi_bindings(get_search_state=None):
@text_object('G')
def _(event):
"""
- Go to the end of the document. (If no arg has been given.)
- """
+ Go to the end of the document. (If no arg has been given.)
+ """
buf = event.current_buffer
return TextObject(buf.document.translate_row_col_to_index(buf.document.line_count - 1, 0) -
buf.cursor_position, type=TextObjectType.LINEWISE)
-
+
#
# *** Other ***
#
- @handle('G', filter=HasArg())
- def _(event):
- """
- If an argument is given, move to this line in the history. (for
- example, 15G)
- """
- event.current_buffer.go_to_history(event.arg - 1)
-
+ @handle('G', filter=HasArg())
+ def _(event):
+ """
+ If an argument is given, move to this line in the history. (for
+ example, 15G)
+ """
+ event.current_buffer.go_to_history(event.arg - 1)
+
for n in '123456789':
@handle(n, filter=navigation_mode|selection_mode|operator_given)
def _(event):
"""
Always handle numberics in navigation mode as arg.
"""
- event.append_to_arg_count(event.data)
-
+ event.append_to_arg_count(event.data)
+
@handle('0', filter=(navigation_mode|selection_mode|operator_given) & HasArg())
def _(event):
" Zero when an argument was already give. "
event.append_to_arg_count(event.data)
- @handle(Keys.Any, filter=replace_mode)
- def _(event):
- """
- Insert data at cursor position.
- """
- event.current_buffer.insert_text(event.data, overwrite=True)
-
+ @handle(Keys.Any, filter=replace_mode)
+ def _(event):
+ """
+ Insert data at cursor position.
+ """
+ event.current_buffer.insert_text(event.data, overwrite=True)
+
@handle(Keys.Any, filter=insert_multiple_mode,
save_before=(lambda e: not e.is_repeat))
def _(event):
- """
+ """
Insert data at multiple cursor positions at once.
(Usually a result of pressing 'I' or 'A' in block-selection mode.)
- """
+ """
buff = event.current_buffer
original_text = buff.text
-
+
# Construct new text.
text = []
p = 0
-
+
for p2 in buff.multiple_cursor_positions:
text.append(original_text[p:p2])
text.append(event.data)
@@ -1654,27 +1654,27 @@ def load_vi_bindings(get_search_state=None):
event.cli.output.bell()
- @handle(Keys.ControlX, Keys.ControlL, filter=insert_mode)
- def _(event):
- """
- Pressing the ControlX - ControlL sequence in Vi mode does line
- completion based on the other lines in the document and the history.
- """
- event.current_buffer.start_history_lines_completion()
-
- @handle(Keys.ControlX, Keys.ControlF, filter=insert_mode)
- def _(event):
- """
- Complete file names.
- """
- # TODO
- pass
-
+ @handle(Keys.ControlX, Keys.ControlL, filter=insert_mode)
+ def _(event):
+ """
+ Pressing the ControlX - ControlL sequence in Vi mode does line
+ completion based on the other lines in the document and the history.
+ """
+ event.current_buffer.start_history_lines_completion()
+
+ @handle(Keys.ControlX, Keys.ControlF, filter=insert_mode)
+ def _(event):
+ """
+ Complete file names.
+ """
+ # TODO
+ pass
+
@handle(Keys.ControlK, filter=insert_mode|replace_mode)
def _(event):
" Go into digraph mode. "
event.cli.vi_state.waiting_for_digraph = True
-
+
@Condition
def digraph_symbol_1_given(cli):
return cli.vi_state.digraph_symbol1 is not None
@@ -1709,128 +1709,128 @@ def load_vi_bindings(get_search_state=None):
def load_vi_open_in_editor_bindings():
- """
- Pressing 'v' in navigation mode will open the buffer in an external editor.
- """
+ """
+ Pressing 'v' in navigation mode will open the buffer in an external editor.
+ """
registry = Registry()
navigation_mode = ViNavigationMode()
-
+
registry.add_binding('v', filter=navigation_mode)(
get_by_name('edit-and-execute-command'))
return registry
-
-
+
+
def load_vi_system_bindings():
registry = ConditionalRegistry(Registry(), ViMode())
handle = registry.add_binding
- has_focus = filters.HasFocus(SYSTEM_BUFFER)
+ has_focus = filters.HasFocus(SYSTEM_BUFFER)
navigation_mode = ViNavigationMode()
-
- @handle('!', filter=~has_focus & navigation_mode)
- def _(event):
- """
- '!' opens the system prompt.
- """
- event.cli.push_focus(SYSTEM_BUFFER)
+
+ @handle('!', filter=~has_focus & navigation_mode)
+ def _(event):
+ """
+ '!' opens the system prompt.
+ """
+ event.cli.push_focus(SYSTEM_BUFFER)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle(Keys.Escape, filter=has_focus)
- @handle(Keys.ControlC, filter=has_focus)
- def _(event):
- """
- Cancel system prompt.
- """
+
+ @handle(Keys.Escape, filter=has_focus)
+ @handle(Keys.ControlC, filter=has_focus)
+ def _(event):
+ """
+ Cancel system prompt.
+ """
event.cli.vi_state.input_mode = InputMode.NAVIGATION
- event.cli.buffers[SYSTEM_BUFFER].reset()
- event.cli.pop_focus()
-
- @handle(Keys.ControlJ, filter=has_focus)
- def _(event):
- """
- Run system command.
- """
+ event.cli.buffers[SYSTEM_BUFFER].reset()
+ event.cli.pop_focus()
+
+ @handle(Keys.ControlJ, filter=has_focus)
+ def _(event):
+ """
+ Run system command.
+ """
event.cli.vi_state.input_mode = InputMode.NAVIGATION
-
- system_buffer = event.cli.buffers[SYSTEM_BUFFER]
- event.cli.run_system_command(system_buffer.text)
- system_buffer.reset(append_to_history=True)
-
- # Focus previous buffer again.
- event.cli.pop_focus()
-
+
+ system_buffer = event.cli.buffers[SYSTEM_BUFFER]
+ event.cli.run_system_command(system_buffer.text)
+ system_buffer.reset(append_to_history=True)
+
+ # Focus previous buffer again.
+ event.cli.pop_focus()
+
return registry
-
+
def load_vi_search_bindings(get_search_state=None,
search_buffer_name=SEARCH_BUFFER):
- assert get_search_state is None or callable(get_search_state)
-
- if not get_search_state:
- def get_search_state(cli): return cli.search_state
-
+ assert get_search_state is None or callable(get_search_state)
+
+ if not get_search_state:
+ def get_search_state(cli): return cli.search_state
+
registry = ConditionalRegistry(Registry(), ViMode())
handle = registry.add_binding
- has_focus = filters.HasFocus(search_buffer_name)
+ has_focus = filters.HasFocus(search_buffer_name)
navigation_mode = ViNavigationMode()
selection_mode = ViSelectionMode()
-
+
reverse_vi_search_direction = Condition(
lambda cli: cli.application.reverse_vi_search_direction(cli))
@handle('/', filter=(navigation_mode|selection_mode)&~reverse_vi_search_direction)
@handle('?', filter=(navigation_mode|selection_mode)&reverse_vi_search_direction)
- @handle(Keys.ControlS, filter=~has_focus)
- def _(event):
- """
- Vi-style forward search.
- """
- # Set the ViState.
- get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD
+ @handle(Keys.ControlS, filter=~has_focus)
+ def _(event):
+ """
+ Vi-style forward search.
+ """
+ # Set the ViState.
+ get_search_state(event.cli).direction = IncrementalSearchDirection.FORWARD
event.cli.vi_state.input_mode = InputMode.INSERT
-
- # Focus search buffer.
- event.cli.push_focus(search_buffer_name)
-
+
+ # Focus search buffer.
+ event.cli.push_focus(search_buffer_name)
+
@handle('?', filter=(navigation_mode|selection_mode)&~reverse_vi_search_direction)
@handle('/', filter=(navigation_mode|selection_mode)&reverse_vi_search_direction)
- @handle(Keys.ControlR, filter=~has_focus)
- def _(event):
- """
- Vi-style backward search.
- """
- # Set the ViState.
- get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD
-
- # Focus search buffer.
- event.cli.push_focus(search_buffer_name)
+ @handle(Keys.ControlR, filter=~has_focus)
+ def _(event):
+ """
+ Vi-style backward search.
+ """
+ # Set the ViState.
+ get_search_state(event.cli).direction = IncrementalSearchDirection.BACKWARD
+
+ # Focus search buffer.
+ event.cli.push_focus(search_buffer_name)
event.cli.vi_state.input_mode = InputMode.INSERT
-
- @handle(Keys.ControlJ, filter=has_focus)
+
+ @handle(Keys.ControlJ, filter=has_focus)
@handle(Keys.Escape, filter=has_focus)
- def _(event):
- """
- Apply the search. (At the / or ? prompt.)
- """
- input_buffer = event.cli.buffers.previous(event.cli)
- search_buffer = event.cli.buffers[search_buffer_name]
-
- # Update search state.
- if search_buffer.text:
- get_search_state(event.cli).text = search_buffer.text
-
- # Apply search.
- input_buffer.apply_search(get_search_state(event.cli))
-
- # Add query to history of search line.
- search_buffer.append_to_history()
- search_buffer.reset()
-
- # Focus previous document again.
+ def _(event):
+ """
+ Apply the search. (At the / or ? prompt.)
+ """
+ input_buffer = event.cli.buffers.previous(event.cli)
+ search_buffer = event.cli.buffers[search_buffer_name]
+
+ # Update search state.
+ if search_buffer.text:
+ get_search_state(event.cli).text = search_buffer.text
+
+ # Apply search.
+ input_buffer.apply_search(get_search_state(event.cli))
+
+ # Add query to history of search line.
+ search_buffer.append_to_history()
+ search_buffer.reset()
+
+ # Focus previous document again.
event.cli.vi_state.input_mode = InputMode.NAVIGATION
- event.cli.pop_focus()
-
+ event.cli.pop_focus()
+
def incremental_search(cli, direction, count=1):
" Apply search, but keep search buffer focussed. "
# Update search_state.
@@ -1854,41 +1854,41 @@ def load_vi_search_bindings(get_search_state=None,
def _(event):
incremental_search(event.cli, IncrementalSearchDirection.FORWARD, count=event.arg)
- def search_buffer_is_empty(cli):
- """ Returns True when the search buffer is empty. """
- return cli.buffers[search_buffer_name].text == ''
-
- @handle(Keys.ControlC, filter=has_focus)
+ def search_buffer_is_empty(cli):
+ """ Returns True when the search buffer is empty. """
+ return cli.buffers[search_buffer_name].text == ''
+
+ @handle(Keys.ControlC, filter=has_focus)
@handle(Keys.ControlH, filter=has_focus & Condition(search_buffer_is_empty))
- @handle(Keys.Backspace, filter=has_focus & Condition(search_buffer_is_empty))
- def _(event):
- """
- Cancel search.
- """
+ @handle(Keys.Backspace, filter=has_focus & Condition(search_buffer_is_empty))
+ def _(event):
+ """
+ Cancel search.
+ """
event.cli.vi_state.input_mode = InputMode.NAVIGATION
-
- event.cli.pop_focus()
- event.cli.buffers[search_buffer_name].reset()
-
+
+ event.cli.pop_focus()
+ event.cli.buffers[search_buffer_name].reset()
+
return registry
-
+
def load_extra_vi_page_navigation_bindings():
- """
- Key bindings, for scrolling up and down through pages.
- This are separate bindings, because GNU readline doesn't have them.
- """
+ """
+ Key bindings, for scrolling up and down through pages.
+ This are separate bindings, because GNU readline doesn't have them.
+ """
registry = ConditionalRegistry(Registry(), ViMode())
handle = registry.add_binding
-
- handle(Keys.ControlF)(scroll_forward)
- handle(Keys.ControlB)(scroll_backward)
- handle(Keys.ControlD)(scroll_half_page_down)
- handle(Keys.ControlU)(scroll_half_page_up)
- handle(Keys.ControlE)(scroll_one_line_down)
- handle(Keys.ControlY)(scroll_one_line_up)
- handle(Keys.PageDown)(scroll_page_down)
- handle(Keys.PageUp)(scroll_page_up)
+
+ handle(Keys.ControlF)(scroll_forward)
+ handle(Keys.ControlB)(scroll_backward)
+ handle(Keys.ControlD)(scroll_half_page_down)
+ handle(Keys.ControlU)(scroll_half_page_up)
+ handle(Keys.ControlE)(scroll_one_line_down)
+ handle(Keys.ControlY)(scroll_one_line_up)
+ handle(Keys.PageDown)(scroll_page_down)
+ handle(Keys.PageUp)(scroll_page_up)
return registry
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py
index a94acad31c5..51a3110827a 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/input_processor.py
@@ -1,35 +1,35 @@
-# *** encoding: utf-8 ***
-"""
-An :class:`~.InputProcessor` receives callbacks for the keystrokes parsed from
-the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance.
-
-The `InputProcessor` will according to the implemented keybindings call the
+# *** encoding: utf-8 ***
+"""
+An :class:`~.InputProcessor` receives callbacks for the keystrokes parsed from
+the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance.
+
+The `InputProcessor` will according to the implemented keybindings call the
correct callbacks when new key presses are feed through `feed`.
-"""
-from __future__ import unicode_literals
-from prompt_toolkit.buffer import EditReadOnlyBuffer
+"""
+from __future__ import unicode_literals
+from prompt_toolkit.buffer import EditReadOnlyBuffer
from prompt_toolkit.filters.cli import ViNavigationMode
from prompt_toolkit.keys import Keys, Key
from prompt_toolkit.utils import Event
-
+
from .registry import BaseRegistry
from collections import deque
from six.moves import range
-import weakref
+import weakref
import six
-
-__all__ = (
- 'InputProcessor',
- 'KeyPress',
-)
-
-
-class KeyPress(object):
- """
+
+__all__ = (
+ 'InputProcessor',
+ 'KeyPress',
+)
+
+
+class KeyPress(object):
+ """
:param key: A `Keys` instance or text (one character).
- :param data: The received string on stdin. (Often vt100 escape codes.)
- """
+ :param data: The received string on stdin. (Often vt100 escape codes.)
+ """
def __init__(self, key, data=None):
assert isinstance(key, (six.text_type, Key))
assert data is None or isinstance(data, six.text_type)
@@ -37,44 +37,44 @@ class KeyPress(object):
if data is None:
data = key.name if isinstance(key, Key) else key
- self.key = key
- self.data = data
-
- def __repr__(self):
- return '%s(key=%r, data=%r)' % (
- self.__class__.__name__, self.key, self.data)
-
- def __eq__(self, other):
- return self.key == other.key and self.data == other.data
-
-
-class InputProcessor(object):
- """
- Statemachine that receives :class:`KeyPress` instances and according to the
- key bindings in the given :class:`Registry`, calls the matching handlers.
-
- ::
-
- p = InputProcessor(registry)
-
- # Send keys into the processor.
+ self.key = key
+ self.data = data
+
+ def __repr__(self):
+ return '%s(key=%r, data=%r)' % (
+ self.__class__.__name__, self.key, self.data)
+
+ def __eq__(self, other):
+ return self.key == other.key and self.data == other.data
+
+
+class InputProcessor(object):
+ """
+ Statemachine that receives :class:`KeyPress` instances and according to the
+ key bindings in the given :class:`Registry`, calls the matching handlers.
+
+ ::
+
+ p = InputProcessor(registry)
+
+ # Send keys into the processor.
p.feed(KeyPress(Keys.ControlX, '\x18'))
p.feed(KeyPress(Keys.ControlC, '\x03')
-
+
# Process all the keys in the queue.
p.process_keys()
- # Now the ControlX-ControlC callback will be called if this sequence is
- # registered in the registry.
-
+ # Now the ControlX-ControlC callback will be called if this sequence is
+ # registered in the registry.
+
:param registry: `BaseRegistry` instance.
- :param cli_ref: weakref to `CommandLineInterface`.
- """
- def __init__(self, registry, cli_ref):
+ :param cli_ref: weakref to `CommandLineInterface`.
+ """
+ def __init__(self, registry, cli_ref):
assert isinstance(registry, BaseRegistry)
- self._registry = registry
- self._cli_ref = cli_ref
+ self._registry = registry
+ self._cli_ref = cli_ref
self.beforeKeyPress = Event(self)
self.afterKeyPress = Event(self)
@@ -90,19 +90,19 @@ class InputProcessor(object):
self.record_macro = False
self.macro = []
- self.reset()
-
- def reset(self):
+ self.reset()
+
+ def reset(self):
self._previous_key_sequence = []
- self._previous_handler = None
-
- self._process_coroutine = self._process()
- self._process_coroutine.send(None)
-
- #: Readline argument (for repetition of commands.)
- #: https://www.gnu.org/software/bash/manual/html_node/Readline-Arguments.html
- self.arg = None
-
+ self._previous_handler = None
+
+ self._process_coroutine = self._process()
+ self._process_coroutine.send(None)
+
+ #: Readline argument (for repetition of commands.)
+ #: https://www.gnu.org/software/bash/manual/html_node/Readline-Arguments.html
+ self.arg = None
+
def start_macro(self):
" Start recording macro. "
self.record_macro = True
@@ -116,106 +116,106 @@ class InputProcessor(object):
for k in self.macro:
self.feed(k)
- def _get_matches(self, key_presses):
- """
- For a list of :class:`KeyPress` instances. Give the matching handlers
- that would handle this.
- """
- keys = tuple(k.key for k in key_presses)
- cli = self._cli_ref()
-
- # Try match, with mode flag
+ def _get_matches(self, key_presses):
+ """
+ For a list of :class:`KeyPress` instances. Give the matching handlers
+ that would handle this.
+ """
+ keys = tuple(k.key for k in key_presses)
+ cli = self._cli_ref()
+
+ # Try match, with mode flag
return [b for b in self._registry.get_bindings_for_keys(keys) if b.filter(cli)]
-
- def _is_prefix_of_longer_match(self, key_presses):
- """
- For a list of :class:`KeyPress` instances. Return True if there is any
- handler that is bound to a suffix of this keys.
- """
- keys = tuple(k.key for k in key_presses)
- cli = self._cli_ref()
-
- # Get the filters for all the key bindings that have a longer match.
- # Note that we transform it into a `set`, because we don't care about
- # the actual bindings and executing it more than once doesn't make
- # sense. (Many key bindings share the same filter.)
- filters = set(b.filter for b in self._registry.get_bindings_starting_with_keys(keys))
-
- # When any key binding is active, return True.
- return any(f(cli) for f in filters)
-
- def _process(self):
- """
- Coroutine implementing the key match algorithm. Key strokes are sent
- into this generator, and it calls the appropriate handlers.
- """
+
+ def _is_prefix_of_longer_match(self, key_presses):
+ """
+ For a list of :class:`KeyPress` instances. Return True if there is any
+ handler that is bound to a suffix of this keys.
+ """
+ keys = tuple(k.key for k in key_presses)
+ cli = self._cli_ref()
+
+ # Get the filters for all the key bindings that have a longer match.
+ # Note that we transform it into a `set`, because we don't care about
+ # the actual bindings and executing it more than once doesn't make
+ # sense. (Many key bindings share the same filter.)
+ filters = set(b.filter for b in self._registry.get_bindings_starting_with_keys(keys))
+
+ # When any key binding is active, return True.
+ return any(f(cli) for f in filters)
+
+ def _process(self):
+ """
+ Coroutine implementing the key match algorithm. Key strokes are sent
+ into this generator, and it calls the appropriate handlers.
+ """
buffer = self.key_buffer
- retry = False
-
- while True:
- if retry:
- retry = False
- else:
- buffer.append((yield))
-
- # If we have some key presses, check for matches.
- if buffer:
- is_prefix_of_longer_match = self._is_prefix_of_longer_match(buffer)
- matches = self._get_matches(buffer)
-
+ retry = False
+
+ while True:
+ if retry:
+ retry = False
+ else:
+ buffer.append((yield))
+
+ # If we have some key presses, check for matches.
+ if buffer:
+ is_prefix_of_longer_match = self._is_prefix_of_longer_match(buffer)
+ matches = self._get_matches(buffer)
+
# When eager matches were found, give priority to them and also
# ignore all the longer matches.
eager_matches = [m for m in matches if m.eager(self._cli_ref())]
if eager_matches:
matches = eager_matches
- is_prefix_of_longer_match = False
-
- # Exact matches found, call handler.
- if not is_prefix_of_longer_match and matches:
+ is_prefix_of_longer_match = False
+
+ # Exact matches found, call handler.
+ if not is_prefix_of_longer_match and matches:
self._call_handler(matches[-1], key_sequence=buffer[:])
del buffer[:] # Keep reference.
-
- # No match found.
- elif not is_prefix_of_longer_match and not matches:
- retry = True
- found = False
-
- # Loop over the input, try longest match first and shift.
- for i in range(len(buffer), 0, -1):
- matches = self._get_matches(buffer[:i])
- if matches:
- self._call_handler(matches[-1], key_sequence=buffer[:i])
+
+ # No match found.
+ elif not is_prefix_of_longer_match and not matches:
+ retry = True
+ found = False
+
+ # Loop over the input, try longest match first and shift.
+ for i in range(len(buffer), 0, -1):
+ matches = self._get_matches(buffer[:i])
+ if matches:
+ self._call_handler(matches[-1], key_sequence=buffer[:i])
del buffer[:i]
- found = True
+ found = True
break
-
- if not found:
+
+ if not found:
del buffer[:1]
-
+
def feed(self, key_press):
- """
+ """
Add a new :class:`KeyPress` to the input queue.
(Don't forget to call `process_keys` in order to process the queue.)
- """
- assert isinstance(key_press, KeyPress)
+ """
+ assert isinstance(key_press, KeyPress)
self.input_queue.append(key_press)
-
+
def process_keys(self):
"""
Process all the keys in the `input_queue`.
(To be called after `feed`.)
-
+
Note: because of the `feed`/`process_keys` separation, it is
possible to call `feed` from inside a key binding.
This function keeps looping until the queue is empty.
"""
while self.input_queue:
key_press = self.input_queue.popleft()
-
+
if key_press.key != Keys.CPRResponse:
self.beforeKeyPress.fire()
-
+
self._process_coroutine.send(key_press)
if key_press.key != Keys.CPRResponse:
@@ -226,16 +226,16 @@ class InputProcessor(object):
if cli:
cli.invalidate()
- def _call_handler(self, handler, key_sequence=None):
+ def _call_handler(self, handler, key_sequence=None):
was_recording = self.record_macro
- arg = self.arg
- self.arg = None
-
+ arg = self.arg
+ self.arg = None
+
event = KeyPressEvent(
weakref.ref(self), arg=arg, key_sequence=key_sequence,
previous_key_sequence=self._previous_key_sequence,
is_repeat=(handler == self._previous_handler))
-
+
# Save the state of the current buffer.
cli = event.cli # Can be `None` (In unit-tests only.)
@@ -243,18 +243,18 @@ class InputProcessor(object):
cli.current_buffer.save_to_undo_stack()
# Call handler.
- try:
- handler.call(event)
+ try:
+ handler.call(event)
self._fix_vi_cursor_position(event)
-
- except EditReadOnlyBuffer:
+
+ except EditReadOnlyBuffer:
# When a key binding does an attempt to change a buffer which is
# read-only, we can just silently ignore that.
- pass
-
- self._previous_key_sequence = key_sequence
- self._previous_handler = handler
-
+ pass
+
+ self._previous_key_sequence = key_sequence
+ self._previous_handler = handler
+
# Record the key sequence in our macro. (Only if we're in macro mode
# before and after executing the key.)
if self.record_macro and was_recording:
@@ -266,16 +266,16 @@ class InputProcessor(object):
never put the cursor after the last character of a line. (Unless it's
an empty line.)
"""
- cli = self._cli_ref()
+ cli = self._cli_ref()
if cli:
buff = cli.current_buffer
preferred_column = buff.preferred_column
-
+
if (ViNavigationMode()(event.cli) and
buff.document.is_cursor_at_the_end_of_line and
len(buff.document.current_line) > 0):
buff.cursor_position -= 1
-
+
# Set the preferred_column for arrow up/down again.
# (This was cleared after changing the cursor position.)
buff.preferred_column = preferred_column
@@ -283,60 +283,60 @@ class InputProcessor(object):
class KeyPressEvent(object):
- """
- Key press event, delivered to key bindings.
-
- :param input_processor_ref: Weak reference to the `InputProcessor`.
- :param arg: Repetition argument.
- :param key_sequence: List of `KeyPress` instances.
- :param previouskey_sequence: Previous list of `KeyPress` instances.
- :param is_repeat: True when the previous event was delivered to the same handler.
- """
- def __init__(self, input_processor_ref, arg=None, key_sequence=None,
- previous_key_sequence=None, is_repeat=False):
- self._input_processor_ref = input_processor_ref
- self.key_sequence = key_sequence
- self.previous_key_sequence = previous_key_sequence
-
- #: True when the previous key sequence was handled by the same handler.
- self.is_repeat = is_repeat
-
- self._arg = arg
-
- def __repr__(self):
+ """
+ Key press event, delivered to key bindings.
+
+ :param input_processor_ref: Weak reference to the `InputProcessor`.
+ :param arg: Repetition argument.
+ :param key_sequence: List of `KeyPress` instances.
+ :param previouskey_sequence: Previous list of `KeyPress` instances.
+ :param is_repeat: True when the previous event was delivered to the same handler.
+ """
+ def __init__(self, input_processor_ref, arg=None, key_sequence=None,
+ previous_key_sequence=None, is_repeat=False):
+ self._input_processor_ref = input_processor_ref
+ self.key_sequence = key_sequence
+ self.previous_key_sequence = previous_key_sequence
+
+ #: True when the previous key sequence was handled by the same handler.
+ self.is_repeat = is_repeat
+
+ self._arg = arg
+
+ def __repr__(self):
return 'KeyPressEvent(arg=%r, key_sequence=%r, is_repeat=%r)' % (
- self.arg, self.key_sequence, self.is_repeat)
-
- @property
- def data(self):
- return self.key_sequence[-1].data
-
- @property
- def input_processor(self):
- return self._input_processor_ref()
-
- @property
- def cli(self):
- """
- Command line interface.
- """
- return self.input_processor._cli_ref()
-
- @property
- def current_buffer(self):
- """
- The current buffer.
- """
- return self.cli.current_buffer
-
- @property
- def arg(self):
- """
- Repetition argument.
- """
+ self.arg, self.key_sequence, self.is_repeat)
+
+ @property
+ def data(self):
+ return self.key_sequence[-1].data
+
+ @property
+ def input_processor(self):
+ return self._input_processor_ref()
+
+ @property
+ def cli(self):
+ """
+ Command line interface.
+ """
+ return self.input_processor._cli_ref()
+
+ @property
+ def current_buffer(self):
+ """
+ The current buffer.
+ """
+ return self.cli.current_buffer
+
+ @property
+ def arg(self):
+ """
+ Repetition argument.
+ """
if self._arg == '-':
return -1
-
+
result = int(self._arg or 1)
# Don't exceed a million.
@@ -352,21 +352,21 @@ class KeyPressEvent(object):
"""
return self._arg is not None
- def append_to_arg_count(self, data):
- """
- Add digit to the input argument.
-
- :param data: the typed digit as string
- """
- assert data in '-0123456789'
- current = self._arg
-
+ def append_to_arg_count(self, data):
+ """
+ Add digit to the input argument.
+
+ :param data: the typed digit as string
+ """
+ assert data in '-0123456789'
+ current = self._arg
+
if data == '-':
assert current is None or current == '-'
result = data
elif current is None:
result = data
- else:
+ else:
result = "%s%s" % (current, data)
-
- self.input_processor.arg = result
+
+ self.input_processor.arg = result
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py
index 3e4bf7ff1f5..83612c2a5cc 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/manager.py
@@ -1,61 +1,61 @@
-"""
+"""
DEPRECATED:
Use `prompt_toolkit.key_binding.defaults.load_key_bindings` instead.
-:class:`KeyBindingManager` is a utility (or shortcut) for loading all the key
-bindings in a key binding registry, with a logic set of filters to quickly to
-quickly change from Vi to Emacs key bindings at runtime.
-
-You don't have to use this, but it's practical.
-
-Usage::
-
- manager = KeyBindingManager()
+:class:`KeyBindingManager` is a utility (or shortcut) for loading all the key
+bindings in a key binding registry, with a logic set of filters to quickly to
+quickly change from Vi to Emacs key bindings at runtime.
+
+You don't have to use this, but it's practical.
+
+Usage::
+
+ manager = KeyBindingManager()
app = Application(key_bindings_registry=manager.registry)
-"""
-from __future__ import unicode_literals
+"""
+from __future__ import unicode_literals
from .defaults import load_key_bindings
-from prompt_toolkit.filters import to_cli_filter
+from prompt_toolkit.filters import to_cli_filter
from prompt_toolkit.key_binding.registry import Registry, ConditionalRegistry, MergedRegistry
-
-__all__ = (
- 'KeyBindingManager',
-)
-
-
-class KeyBindingManager(object):
- """
- Utility for loading all key bindings into memory.
-
- :param registry: Optional `Registry` instance.
- :param enable_abort_and_exit_bindings: Filter to enable Ctrl-C and Ctrl-D.
- :param enable_system_bindings: Filter to enable the system bindings
- (meta-! prompt and Control-Z suspension.)
- :param enable_search: Filter to enable the search bindings.
- :param enable_open_in_editor: Filter to enable open-in-editor.
- :param enable_open_in_editor: Filter to enable open-in-editor.
- :param enable_extra_page_navigation: Filter for enabling extra page navigation.
- (Bindings for up/down scrolling through long pages, like in Emacs or Vi.)
- :param enable_auto_suggest_bindings: Filter to enable fish-style suggestions.
+
+__all__ = (
+ 'KeyBindingManager',
+)
+
+
+class KeyBindingManager(object):
+ """
+ Utility for loading all key bindings into memory.
+
+ :param registry: Optional `Registry` instance.
+ :param enable_abort_and_exit_bindings: Filter to enable Ctrl-C and Ctrl-D.
+ :param enable_system_bindings: Filter to enable the system bindings
+ (meta-! prompt and Control-Z suspension.)
+ :param enable_search: Filter to enable the search bindings.
+ :param enable_open_in_editor: Filter to enable open-in-editor.
+ :param enable_open_in_editor: Filter to enable open-in-editor.
+ :param enable_extra_page_navigation: Filter for enabling extra page navigation.
+ (Bindings for up/down scrolling through long pages, like in Emacs or Vi.)
+ :param enable_auto_suggest_bindings: Filter to enable fish-style suggestions.
:param enable_vi_mode: Deprecated!
- """
+ """
def __init__(self,
registry=None, # XXX: not used anymore.
enable_vi_mode=None, # (`enable_vi_mode` is deprecated.)
enable_all=True, #
- get_search_state=None,
- enable_abort_and_exit_bindings=False,
+ get_search_state=None,
+ enable_abort_and_exit_bindings=False,
enable_system_bindings=False,
enable_search=False,
enable_open_in_editor=False,
enable_extra_page_navigation=False,
enable_auto_suggest_bindings=False):
-
- assert registry is None or isinstance(registry, Registry)
- assert get_search_state is None or callable(get_search_state)
- enable_all = to_cli_filter(enable_all)
-
+
+ assert registry is None or isinstance(registry, Registry)
+ assert get_search_state is None or callable(get_search_state)
+ enable_all = to_cli_filter(enable_all)
+
defaults = load_key_bindings(
get_search_state=get_search_state,
enable_abort_and_exit_bindings=enable_abort_and_exit_bindings,
@@ -64,30 +64,30 @@ class KeyBindingManager(object):
enable_open_in_editor=enable_open_in_editor,
enable_extra_page_navigation=enable_extra_page_navigation,
enable_auto_suggest_bindings=enable_auto_suggest_bindings)
-
+
# Note, we wrap this whole thing again in a MergedRegistry, because we
# don't want the `enable_all` settings to apply on items that were
# added to the registry as a whole.
self.registry = MergedRegistry([
ConditionalRegistry(defaults, enable_all)
])
-
- @classmethod
- def for_prompt(cls, **kw):
- """
- Create a ``KeyBindingManager`` with the defaults for an input prompt.
+
+ @classmethod
+ def for_prompt(cls, **kw):
+ """
+ Create a ``KeyBindingManager`` with the defaults for an input prompt.
This activates the key bindings for abort/exit (Ctrl-C/Ctrl-D),
- incremental search and auto suggestions.
-
- (Not for full screen applications.)
- """
- kw.setdefault('enable_abort_and_exit_bindings', True)
- kw.setdefault('enable_search', True)
- kw.setdefault('enable_auto_suggest_bindings', True)
-
- return cls(**kw)
-
- def reset(self, cli):
+ incremental search and auto suggestions.
+
+ (Not for full screen applications.)
+ """
+ kw.setdefault('enable_abort_and_exit_bindings', True)
+ kw.setdefault('enable_search', True)
+ kw.setdefault('enable_auto_suggest_bindings', True)
+
+ return cls(**kw)
+
+ def reset(self, cli):
# For backwards compatibility.
pass
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py
index 5df089b20c5..24d0e729a1b 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/registry.py
@@ -23,110 +23,110 @@ others contain the Vi bindings. They are merged together using a
We also have a `ConditionalRegistry` object that can enable/disable a group of
key bindings at once.
"""
-from __future__ import unicode_literals
+from __future__ import unicode_literals
from abc import ABCMeta, abstractmethod
from prompt_toolkit.cache import SimpleCache
from prompt_toolkit.filters import CLIFilter, to_cli_filter, Never
from prompt_toolkit.keys import Key, Keys
-
+
from six import text_type, with_metaclass
-
-__all__ = (
+
+__all__ = (
'BaseRegistry',
- 'Registry',
+ 'Registry',
'ConditionalRegistry',
'MergedRegistry',
-)
-
-
-class _Binding(object):
- """
- (Immutable binding class.)
- """
+)
+
+
+class _Binding(object):
+ """
+ (Immutable binding class.)
+ """
def __init__(self, keys, handler, filter=None, eager=None, save_before=None):
- assert isinstance(keys, tuple)
- assert callable(handler)
- assert isinstance(filter, CLIFilter)
- assert isinstance(eager, CLIFilter)
+ assert isinstance(keys, tuple)
+ assert callable(handler)
+ assert isinstance(filter, CLIFilter)
+ assert isinstance(eager, CLIFilter)
assert callable(save_before)
-
- self.keys = keys
- self.handler = handler
- self.filter = filter
- self.eager = eager
+
+ self.keys = keys
+ self.handler = handler
+ self.filter = filter
+ self.eager = eager
self.save_before = save_before
-
- def call(self, event):
- return self.handler(event)
-
- def __repr__(self):
- return '%s(keys=%r, handler=%r)' % (
- self.__class__.__name__, self.keys, self.handler)
-
-
+
+ def call(self, event):
+ return self.handler(event)
+
+ def __repr__(self):
+ return '%s(keys=%r, handler=%r)' % (
+ self.__class__.__name__, self.keys, self.handler)
+
+
class BaseRegistry(with_metaclass(ABCMeta, object)):
- """
+ """
Interface for a Registry.
"""
_version = 0 # For cache invalidation.
-
+
@abstractmethod
def get_bindings_for_keys(self, keys):
pass
-
+
@abstractmethod
def get_bindings_starting_with_keys(self, keys):
pass
-
+
# `add_binding` and `remove_binding` don't have to be part of this
# interface.
class Registry(BaseRegistry):
- """
+ """
Key binding registry.
"""
- def __init__(self):
- self.key_bindings = []
+ def __init__(self):
+ self.key_bindings = []
self._get_bindings_for_keys_cache = SimpleCache(maxsize=10000)
self._get_bindings_starting_with_keys_cache = SimpleCache(maxsize=1000)
self._version = 0 # For cache invalidation.
-
+
def _clear_cache(self):
self._version += 1
self._get_bindings_for_keys_cache.clear()
self._get_bindings_starting_with_keys_cache.clear()
-
- def add_binding(self, *keys, **kwargs):
- """
- Decorator for annotating key bindings.
-
- :param filter: :class:`~prompt_toolkit.filters.CLIFilter` to determine
- when this key binding is active.
- :param eager: :class:`~prompt_toolkit.filters.CLIFilter` or `bool`.
- When True, ignore potential longer matches when this key binding is
- hit. E.g. when there is an active eager key binding for Ctrl-X,
- execute the handler immediately and ignore the key binding for
- Ctrl-X Ctrl-E of which it is a prefix.
+
+ def add_binding(self, *keys, **kwargs):
+ """
+ Decorator for annotating key bindings.
+
+ :param filter: :class:`~prompt_toolkit.filters.CLIFilter` to determine
+ when this key binding is active.
+ :param eager: :class:`~prompt_toolkit.filters.CLIFilter` or `bool`.
+ When True, ignore potential longer matches when this key binding is
+ hit. E.g. when there is an active eager key binding for Ctrl-X,
+ execute the handler immediately and ignore the key binding for
+ Ctrl-X Ctrl-E of which it is a prefix.
:param save_before: Callable that takes an `Event` and returns True if
we should save the current buffer, before handling the event.
(That's the default.)
- """
- filter = to_cli_filter(kwargs.pop('filter', True))
- eager = to_cli_filter(kwargs.pop('eager', False))
+ """
+ filter = to_cli_filter(kwargs.pop('filter', True))
+ eager = to_cli_filter(kwargs.pop('eager', False))
save_before = kwargs.pop('save_before', lambda e: True)
to_cli_filter(kwargs.pop('invalidate_ui', True)) # Deprecated! (ignored.)
-
- assert not kwargs
- assert keys
- assert all(isinstance(k, (Key, text_type)) for k in keys), \
- 'Key bindings should consist of Key and string (unicode) instances.'
+
+ assert not kwargs
+ assert keys
+ assert all(isinstance(k, (Key, text_type)) for k in keys), \
+ 'Key bindings should consist of Key and string (unicode) instances.'
assert callable(save_before)
-
+
if isinstance(filter, Never):
- # When a filter is Never, it will always stay disabled, so in that case
- # don't bother putting it in the registry. It will slow down every key
+ # When a filter is Never, it will always stay disabled, so in that case
+ # don't bother putting it in the registry. It will slow down every key
# press otherwise.
def decorator(func):
return func
@@ -136,44 +136,44 @@ class Registry(BaseRegistry):
_Binding(keys, func, filter=filter, eager=eager,
save_before=save_before))
self._clear_cache()
-
+
return func
- return decorator
-
- def remove_binding(self, function):
- """
- Remove a key binding.
-
- This expects a function that was given to `add_binding` method as
- parameter. Raises `ValueError` when the given function was not
- registered before.
- """
- assert callable(function)
-
- for b in self.key_bindings:
- if b.handler == function:
- self.key_bindings.remove(b)
+ return decorator
+
+ def remove_binding(self, function):
+ """
+ Remove a key binding.
+
+ This expects a function that was given to `add_binding` method as
+ parameter. Raises `ValueError` when the given function was not
+ registered before.
+ """
+ assert callable(function)
+
+ for b in self.key_bindings:
+ if b.handler == function:
+ self.key_bindings.remove(b)
self._clear_cache()
- return
-
- # No key binding found for this function. Raise ValueError.
- raise ValueError('Binding not found: %r' % (function, ))
-
- def get_bindings_for_keys(self, keys):
- """
- Return a list of key bindings that can handle this key.
- (This return also inactive bindings, so the `filter` still has to be
- called, for checking it.)
-
- :param keys: tuple of keys.
- """
+ return
+
+ # No key binding found for this function. Raise ValueError.
+ raise ValueError('Binding not found: %r' % (function, ))
+
+ def get_bindings_for_keys(self, keys):
+ """
+ Return a list of key bindings that can handle this key.
+ (This return also inactive bindings, so the `filter` still has to be
+ called, for checking it.)
+
+ :param keys: tuple of keys.
+ """
def get():
result = []
for b in self.key_bindings:
if len(keys) == len(b.keys):
match = True
any_count = 0
-
+
for i, j in zip(b.keys, keys):
if i != j and i != Keys.Any:
match = False
@@ -192,15 +192,15 @@ class Registry(BaseRegistry):
return self._get_bindings_for_keys_cache.get(keys, get)
- def get_bindings_starting_with_keys(self, keys):
- """
- Return a list of key bindings that handle a key sequence starting with
- `keys`. (It does only return bindings for which the sequences are
- longer than `keys`. And like `get_bindings_for_keys`, it also includes
- inactive bindings.)
-
- :param keys: tuple of keys.
- """
+ def get_bindings_starting_with_keys(self, keys):
+ """
+ Return a list of key bindings that handle a key sequence starting with
+ `keys`. (It does only return bindings for which the sequences are
+ longer than `keys`. And like `get_bindings_for_keys`, it also includes
+ inactive bindings.)
+
+ :param keys: tuple of keys.
+ """
def get():
result = []
for b in self.key_bindings:
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py
index c6e3e366b0c..92ce3cbd292 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/key_binding/vi_state.py
@@ -1,34 +1,34 @@
-from __future__ import unicode_literals
-
-__all__ = (
- 'InputMode',
- 'CharacterFind',
- 'ViState',
-)
-
-
-class InputMode(object):
- INSERT = 'vi-insert'
+from __future__ import unicode_literals
+
+__all__ = (
+ 'InputMode',
+ 'CharacterFind',
+ 'ViState',
+)
+
+
+class InputMode(object):
+ INSERT = 'vi-insert'
INSERT_MULTIPLE = 'vi-insert-multiple'
- NAVIGATION = 'vi-navigation'
- REPLACE = 'vi-replace'
-
-
-class CharacterFind(object):
- def __init__(self, character, backwards=False):
- self.character = character
- self.backwards = backwards
-
-
-class ViState(object):
- """
- Mutable class to hold the state of the Vi navigation.
- """
- def __init__(self):
- #: None or CharacterFind instance. (This is used to repeat the last
- #: search in Vi mode, by pressing the 'n' or 'N' in navigation mode.)
- self.last_character_find = None
-
+ NAVIGATION = 'vi-navigation'
+ REPLACE = 'vi-replace'
+
+
+class CharacterFind(object):
+ def __init__(self, character, backwards=False):
+ self.character = character
+ self.backwards = backwards
+
+
+class ViState(object):
+ """
+ Mutable class to hold the state of the Vi navigation.
+ """
+ def __init__(self):
+ #: None or CharacterFind instance. (This is used to repeat the last
+ #: search in Vi mode, by pressing the 'n' or 'N' in navigation mode.)
+ self.last_character_find = None
+
# When an operator is given and we are waiting for text object,
# -- e.g. in the case of 'dw', after the 'd' --, an operator callback
# is set here.
@@ -39,9 +39,9 @@ class ViState(object):
#: :class:`ClipboardData` instances.
self.named_registers = {}
- #: The Vi mode we're currently in to.
- self.input_mode = InputMode.INSERT
-
+ #: The Vi mode we're currently in to.
+ self.input_mode = InputMode.INSERT
+
#: Waiting for digraph.
self.waiting_for_digraph = False
self.digraph_symbol1 = None # (None or a symbol.)
@@ -53,7 +53,7 @@ class ViState(object):
"""
Reset state, go back to the given mode. INSERT by default.
"""
- # Go back to insert mode.
+ # Go back to insert mode.
self.input_mode = mode
self.waiting_for_digraph = False
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py
index ffa11f813e2..d5df9bff416 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/keys.py
@@ -1,128 +1,128 @@
-from __future__ import unicode_literals
-
-__all__ = (
- 'Key',
- 'Keys',
-)
-
-
-class Key(object):
- def __init__(self, name):
-
- #: Descriptive way of writing keys in configuration files. e.g. <C-A>
- #: for ``Control-A``.
- self.name = name
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.name)
-
-
-class Keys(object):
- Escape = Key('<Escape>')
-
- ControlA = Key('<C-A>')
- ControlB = Key('<C-B>')
- ControlC = Key('<C-C>')
- ControlD = Key('<C-D>')
- ControlE = Key('<C-E>')
- ControlF = Key('<C-F>')
- ControlG = Key('<C-G>')
- ControlH = Key('<C-H>')
- ControlI = Key('<C-I>') # Tab
- ControlJ = Key('<C-J>') # Enter
- ControlK = Key('<C-K>')
- ControlL = Key('<C-L>')
- ControlM = Key('<C-M>') # Enter
- ControlN = Key('<C-N>')
- ControlO = Key('<C-O>')
- ControlP = Key('<C-P>')
- ControlQ = Key('<C-Q>')
- ControlR = Key('<C-R>')
- ControlS = Key('<C-S>')
- ControlT = Key('<C-T>')
- ControlU = Key('<C-U>')
- ControlV = Key('<C-V>')
- ControlW = Key('<C-W>')
- ControlX = Key('<C-X>')
- ControlY = Key('<C-Y>')
- ControlZ = Key('<C-Z>')
-
- ControlSpace = Key('<C-Space>')
- ControlBackslash = Key('<C-Backslash>')
- ControlSquareClose = Key('<C-SquareClose>')
- ControlCircumflex = Key('<C-Circumflex>')
- ControlUnderscore = Key('<C-Underscore>')
- ControlLeft = Key('<C-Left>')
- ControlRight = Key('<C-Right>')
- ControlUp = Key('<C-Up>')
- ControlDown = Key('<C-Down>')
-
- Up = Key('<Up>')
- Down = Key('<Down>')
- Right = Key('<Right>')
- Left = Key('<Left>')
+from __future__ import unicode_literals
+
+__all__ = (
+ 'Key',
+ 'Keys',
+)
+
+
+class Key(object):
+ def __init__(self, name):
+
+ #: Descriptive way of writing keys in configuration files. e.g. <C-A>
+ #: for ``Control-A``.
+ self.name = name
+
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.name)
+
+
+class Keys(object):
+ Escape = Key('<Escape>')
+
+ ControlA = Key('<C-A>')
+ ControlB = Key('<C-B>')
+ ControlC = Key('<C-C>')
+ ControlD = Key('<C-D>')
+ ControlE = Key('<C-E>')
+ ControlF = Key('<C-F>')
+ ControlG = Key('<C-G>')
+ ControlH = Key('<C-H>')
+ ControlI = Key('<C-I>') # Tab
+ ControlJ = Key('<C-J>') # Enter
+ ControlK = Key('<C-K>')
+ ControlL = Key('<C-L>')
+ ControlM = Key('<C-M>') # Enter
+ ControlN = Key('<C-N>')
+ ControlO = Key('<C-O>')
+ ControlP = Key('<C-P>')
+ ControlQ = Key('<C-Q>')
+ ControlR = Key('<C-R>')
+ ControlS = Key('<C-S>')
+ ControlT = Key('<C-T>')
+ ControlU = Key('<C-U>')
+ ControlV = Key('<C-V>')
+ ControlW = Key('<C-W>')
+ ControlX = Key('<C-X>')
+ ControlY = Key('<C-Y>')
+ ControlZ = Key('<C-Z>')
+
+ ControlSpace = Key('<C-Space>')
+ ControlBackslash = Key('<C-Backslash>')
+ ControlSquareClose = Key('<C-SquareClose>')
+ ControlCircumflex = Key('<C-Circumflex>')
+ ControlUnderscore = Key('<C-Underscore>')
+ ControlLeft = Key('<C-Left>')
+ ControlRight = Key('<C-Right>')
+ ControlUp = Key('<C-Up>')
+ ControlDown = Key('<C-Down>')
+
+ Up = Key('<Up>')
+ Down = Key('<Down>')
+ Right = Key('<Right>')
+ Left = Key('<Left>')
ShiftLeft = Key('<ShiftLeft>')
ShiftUp = Key('<ShiftUp>')
ShiftDown = Key('<ShiftDown>')
ShiftRight = Key('<ShiftRight>')
- Home = Key('<Home>')
- End = Key('<End>')
- Delete = Key('<Delete>')
- ShiftDelete = Key('<ShiftDelete>')
+ Home = Key('<Home>')
+ End = Key('<End>')
+ Delete = Key('<Delete>')
+ ShiftDelete = Key('<ShiftDelete>')
ControlDelete = Key('<C-Delete>')
- PageUp = Key('<PageUp>')
- PageDown = Key('<PageDown>')
- BackTab = Key('<BackTab>') # shift + tab
- Insert = Key('<Insert>')
+ PageUp = Key('<PageUp>')
+ PageDown = Key('<PageDown>')
+ BackTab = Key('<BackTab>') # shift + tab
+ Insert = Key('<Insert>')
Backspace = Key('<Backspace>')
-
+
# Aliases.
- Tab = ControlI
+ Tab = ControlI
Enter = ControlJ
# XXX: Actually Enter equals ControlM, not ControlJ,
# However, in prompt_toolkit, we made the mistake of translating
# \r into \n during the input, so everyone is now handling the
# enter key by binding ControlJ.
-
+
# From now on, it's better to bind `Keys.Enter` everywhere,
# because that's future compatible, and will still work when we
# stop replacing \r by \n.
- F1 = Key('<F1>')
- F2 = Key('<F2>')
- F3 = Key('<F3>')
- F4 = Key('<F4>')
- F5 = Key('<F5>')
- F6 = Key('<F6>')
- F7 = Key('<F7>')
- F8 = Key('<F8>')
- F9 = Key('<F9>')
- F10 = Key('<F10>')
- F11 = Key('<F11>')
- F12 = Key('<F12>')
- F13 = Key('<F13>')
- F14 = Key('<F14>')
- F15 = Key('<F15>')
- F16 = Key('<F16>')
- F17 = Key('<F17>')
- F18 = Key('<F18>')
- F19 = Key('<F19>')
- F20 = Key('<F20>')
+ F1 = Key('<F1>')
+ F2 = Key('<F2>')
+ F3 = Key('<F3>')
+ F4 = Key('<F4>')
+ F5 = Key('<F5>')
+ F6 = Key('<F6>')
+ F7 = Key('<F7>')
+ F8 = Key('<F8>')
+ F9 = Key('<F9>')
+ F10 = Key('<F10>')
+ F11 = Key('<F11>')
+ F12 = Key('<F12>')
+ F13 = Key('<F13>')
+ F14 = Key('<F14>')
+ F15 = Key('<F15>')
+ F16 = Key('<F16>')
+ F17 = Key('<F17>')
+ F18 = Key('<F18>')
+ F19 = Key('<F19>')
+ F20 = Key('<F20>')
F21 = Key('<F21>')
F22 = Key('<F22>')
F23 = Key('<F23>')
F24 = Key('<F24>')
-
- # Matches any key.
- Any = Key('<Any>')
-
- # Special
- CPRResponse = Key('<Cursor-Position-Response>')
- Vt100MouseEvent = Key('<Vt100-Mouse-Event>')
- WindowsMouseEvent = Key('<Windows-Mouse-Event>')
- BracketedPaste = Key('<Bracketed-Paste>')
+
+ # Matches any key.
+ Any = Key('<Any>')
+
+ # Special
+ CPRResponse = Key('<Cursor-Position-Response>')
+ Vt100MouseEvent = Key('<Vt100-Mouse-Event>')
+ WindowsMouseEvent = Key('<Windows-Mouse-Event>')
+ BracketedPaste = Key('<Bracketed-Paste>')
# Key which is ignored. (The key binding for this key should not do
# anything.)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py
index 01ba850d6cb..0dec5ecfaf3 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/__init__.py
@@ -1,51 +1,51 @@
-"""
-Command line layout definitions
--------------------------------
-
-The layout of a command line interface is defined by a Container instance.
-There are two main groups of classes here. Containers and controls:
-
-- A container can contain other containers or controls, it can have multiple
- children and it decides about the dimensions.
-- A control is responsible for rendering the actual content to a screen.
+"""
+Command line layout definitions
+-------------------------------
+
+The layout of a command line interface is defined by a Container instance.
+There are two main groups of classes here. Containers and controls:
+
+- A container can contain other containers or controls, it can have multiple
+ children and it decides about the dimensions.
+- A control is responsible for rendering the actual content to a screen.
A control can propose some dimensions, but it's the container who decides
- about the dimensions -- or when the control consumes more space -- which part
- of the control will be visible.
-
-
-Container classes::
-
- - Container (Abstract base class)
- |- HSplit (Horizontal split)
- |- VSplit (Vertical split)
- |- FloatContainer (Container which can also contain menus and other floats)
- `- Window (Container which contains one actual control
-
-Control classes::
-
- - UIControl (Abstract base class)
- |- TokenListControl (Renders a simple list of tokens)
- |- FillControl (Fills control with one token/character.)
- `- BufferControl (Renders an input buffer.)
-
-
-Usually, you end up wrapping every control inside a `Window` object, because
-that's the only way to render it in a layout.
-
-There are some prepared toolbars which are ready to use::
-
-- SystemToolbar (Shows the 'system' input buffer, for entering system commands.)
-- ArgToolbar (Shows the input 'arg', for repetition of input commands.)
-- SearchToolbar (Shows the 'search' input buffer, for incremental search.)
-- CompletionsToolbar (Shows the completions of the current buffer.)
-- ValidationToolbar (Shows validation errors of the current buffer.)
-
-And one prepared menu:
-
-- CompletionsMenu
-
-"""
-from __future__ import unicode_literals
-
-from .containers import Float, FloatContainer, HSplit, VSplit, Window, ConditionalContainer
-from .controls import TokenListControl, FillControl, BufferControl
+ about the dimensions -- or when the control consumes more space -- which part
+ of the control will be visible.
+
+
+Container classes::
+
+ - Container (Abstract base class)
+ |- HSplit (Horizontal split)
+ |- VSplit (Vertical split)
+ |- FloatContainer (Container which can also contain menus and other floats)
+ `- Window (Container which contains one actual control
+
+Control classes::
+
+ - UIControl (Abstract base class)
+ |- TokenListControl (Renders a simple list of tokens)
+ |- FillControl (Fills control with one token/character.)
+ `- BufferControl (Renders an input buffer.)
+
+
+Usually, you end up wrapping every control inside a `Window` object, because
+that's the only way to render it in a layout.
+
+There are some prepared toolbars which are ready to use::
+
+- SystemToolbar (Shows the 'system' input buffer, for entering system commands.)
+- ArgToolbar (Shows the input 'arg', for repetition of input commands.)
+- SearchToolbar (Shows the 'search' input buffer, for incremental search.)
+- CompletionsToolbar (Shows the completions of the current buffer.)
+- ValidationToolbar (Shows validation errors of the current buffer.)
+
+And one prepared menu:
+
+- CompletionsMenu
+
+"""
+from __future__ import unicode_literals
+
+from .containers import Float, FloatContainer, HSplit, VSplit, Window, ConditionalContainer
+from .controls import TokenListControl, FillControl, BufferControl
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py
index 512c9122d04..0bdafe18e04 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/containers.py
@@ -1,16 +1,16 @@
-"""
-Container for the layout.
-(Containers can contain other containers or user interface controls.)
-"""
-from __future__ import unicode_literals
-
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
+"""
+Container for the layout.
+(Containers can contain other containers or user interface controls.)
+"""
+from __future__ import unicode_literals
+
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
from six.moves import range
-
+
from .controls import UIControl, TokenListControl, UIContent
-from .dimension import LayoutDimension, sum_layout_dimensions, max_layout_dimensions
-from .margins import Margin
+from .dimension import LayoutDimension, sum_layout_dimensions, max_layout_dimensions
+from .margins import Margin
from .screen import Point, WritePosition, _CHAR_CACHE
from .utils import token_list_to_text, explode_tokens
from prompt_toolkit.cache import SimpleCache
@@ -19,495 +19,495 @@ from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
from prompt_toolkit.reactive import Integer
from prompt_toolkit.token import Token
from prompt_toolkit.utils import take_using_weights, get_cwidth
-
-__all__ = (
- 'Container',
- 'HSplit',
- 'VSplit',
- 'FloatContainer',
- 'Float',
- 'Window',
- 'WindowRenderInfo',
- 'ConditionalContainer',
+
+__all__ = (
+ 'Container',
+ 'HSplit',
+ 'VSplit',
+ 'FloatContainer',
+ 'Float',
+ 'Window',
+ 'WindowRenderInfo',
+ 'ConditionalContainer',
'ScrollOffsets',
'ColorColumn',
-)
-
-Transparent = Token.Transparent
-
-
-class Container(with_metaclass(ABCMeta, object)):
- """
- Base class for user interface layout.
- """
- @abstractmethod
- def reset(self):
- """
- Reset the state of this container and all the children.
- (E.g. reset scroll offsets, etc...)
- """
-
- @abstractmethod
- def preferred_width(self, cli, max_available_width):
- """
- Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that
- represents the desired width for this container.
-
- :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
- """
-
- @abstractmethod
+)
+
+Transparent = Token.Transparent
+
+
+class Container(with_metaclass(ABCMeta, object)):
+ """
+ Base class for user interface layout.
+ """
+ @abstractmethod
+ def reset(self):
+ """
+ Reset the state of this container and all the children.
+ (E.g. reset scroll offsets, etc...)
+ """
+
+ @abstractmethod
+ def preferred_width(self, cli, max_available_width):
+ """
+ Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that
+ represents the desired width for this container.
+
+ :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
+ """
+
+ @abstractmethod
def preferred_height(self, cli, width, max_available_height):
- """
- Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that
- represents the desired height for this container.
-
- :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
- """
-
- @abstractmethod
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- """
- Write the actual content to the screen.
-
- :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
- :param screen: :class:`~prompt_toolkit.layout.screen.Screen`
- :param mouse_handlers: :class:`~prompt_toolkit.layout.mouse_handlers.MouseHandlers`.
- """
-
- @abstractmethod
- def walk(self, cli):
- """
- Walk through all the layout nodes (and their children) and yield them.
- """
-
-
-def _window_too_small():
- " Create a `Window` that displays the 'Window too small' text. "
- return Window(TokenListControl.static(
- [(Token.WindowTooSmall, ' Window too small... ')]))
-
-
-class HSplit(Container):
- """
- Several layouts, one stacked above/under the other.
-
- :param children: List of child :class:`.Container` objects.
- :param window_too_small: A :class:`.Container` object that is displayed if
- there is not enough space for all the children. By default, this is a
- "Window too small" message.
- :param get_dimensions: (`None` or a callable that takes a
- `CommandLineInterface` and returns a list of `LayoutDimension`
- instances.) By default the dimensions are taken from the children and
- divided by the available space. However, when `get_dimensions` is specified,
- this is taken instead.
- :param report_dimensions_callback: When rendering, this function is called
- with the `CommandLineInterface` and the list of used dimensions. (As a
- list of integers.)
- """
- def __init__(self, children, window_too_small=None,
- get_dimensions=None, report_dimensions_callback=None):
- assert all(isinstance(c, Container) for c in children)
- assert window_too_small is None or isinstance(window_too_small, Container)
- assert get_dimensions is None or callable(get_dimensions)
- assert report_dimensions_callback is None or callable(report_dimensions_callback)
-
- self.children = children
- self.window_too_small = window_too_small or _window_too_small()
- self.get_dimensions = get_dimensions
- self.report_dimensions_callback = report_dimensions_callback
-
- def preferred_width(self, cli, max_available_width):
- if self.children:
- dimensions = [c.preferred_width(cli, max_available_width) for c in self.children]
- return max_layout_dimensions(dimensions)
- else:
- return LayoutDimension(0)
-
+ """
+ Return a :class:`~prompt_toolkit.layout.dimension.LayoutDimension` that
+ represents the desired height for this container.
+
+ :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
+ """
+
+ @abstractmethod
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ """
+ Write the actual content to the screen.
+
+ :param cli: :class:`~prompt_toolkit.interface.CommandLineInterface`.
+ :param screen: :class:`~prompt_toolkit.layout.screen.Screen`
+ :param mouse_handlers: :class:`~prompt_toolkit.layout.mouse_handlers.MouseHandlers`.
+ """
+
+ @abstractmethod
+ def walk(self, cli):
+ """
+ Walk through all the layout nodes (and their children) and yield them.
+ """
+
+
+def _window_too_small():
+ " Create a `Window` that displays the 'Window too small' text. "
+ return Window(TokenListControl.static(
+ [(Token.WindowTooSmall, ' Window too small... ')]))
+
+
+class HSplit(Container):
+ """
+ Several layouts, one stacked above/under the other.
+
+ :param children: List of child :class:`.Container` objects.
+ :param window_too_small: A :class:`.Container` object that is displayed if
+ there is not enough space for all the children. By default, this is a
+ "Window too small" message.
+ :param get_dimensions: (`None` or a callable that takes a
+ `CommandLineInterface` and returns a list of `LayoutDimension`
+ instances.) By default the dimensions are taken from the children and
+ divided by the available space. However, when `get_dimensions` is specified,
+ this is taken instead.
+ :param report_dimensions_callback: When rendering, this function is called
+ with the `CommandLineInterface` and the list of used dimensions. (As a
+ list of integers.)
+ """
+ def __init__(self, children, window_too_small=None,
+ get_dimensions=None, report_dimensions_callback=None):
+ assert all(isinstance(c, Container) for c in children)
+ assert window_too_small is None or isinstance(window_too_small, Container)
+ assert get_dimensions is None or callable(get_dimensions)
+ assert report_dimensions_callback is None or callable(report_dimensions_callback)
+
+ self.children = children
+ self.window_too_small = window_too_small or _window_too_small()
+ self.get_dimensions = get_dimensions
+ self.report_dimensions_callback = report_dimensions_callback
+
+ def preferred_width(self, cli, max_available_width):
+ if self.children:
+ dimensions = [c.preferred_width(cli, max_available_width) for c in self.children]
+ return max_layout_dimensions(dimensions)
+ else:
+ return LayoutDimension(0)
+
def preferred_height(self, cli, width, max_available_height):
dimensions = [c.preferred_height(cli, width, max_available_height) for c in self.children]
- return sum_layout_dimensions(dimensions)
-
- def reset(self):
- for c in self.children:
- c.reset()
-
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- """
- Render the prompt to a `Screen` instance.
-
- :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class
- to which the output has to be written.
- """
- sizes = self._divide_heigths(cli, write_position)
-
- if self.report_dimensions_callback:
- self.report_dimensions_callback(cli, sizes)
-
- if sizes is None:
- self.window_too_small.write_to_screen(
- cli, screen, mouse_handlers, write_position)
- else:
- # Draw child panes.
- ypos = write_position.ypos
- xpos = write_position.xpos
- width = write_position.width
-
- for s, c in zip(sizes, self.children):
- c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, width, s))
- ypos += s
-
- def _divide_heigths(self, cli, write_position):
- """
- Return the heights for all rows.
- Or None when there is not enough space.
- """
- if not self.children:
- return []
-
- # Calculate heights.
- given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None
-
- def get_dimension_for_child(c, index):
- if given_dimensions and given_dimensions[index] is not None:
- return given_dimensions[index]
- else:
+ return sum_layout_dimensions(dimensions)
+
+ def reset(self):
+ for c in self.children:
+ c.reset()
+
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ """
+ Render the prompt to a `Screen` instance.
+
+ :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class
+ to which the output has to be written.
+ """
+ sizes = self._divide_heigths(cli, write_position)
+
+ if self.report_dimensions_callback:
+ self.report_dimensions_callback(cli, sizes)
+
+ if sizes is None:
+ self.window_too_small.write_to_screen(
+ cli, screen, mouse_handlers, write_position)
+ else:
+ # Draw child panes.
+ ypos = write_position.ypos
+ xpos = write_position.xpos
+ width = write_position.width
+
+ for s, c in zip(sizes, self.children):
+ c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, width, s))
+ ypos += s
+
+ def _divide_heigths(self, cli, write_position):
+ """
+ Return the heights for all rows.
+ Or None when there is not enough space.
+ """
+ if not self.children:
+ return []
+
+ # Calculate heights.
+ given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None
+
+ def get_dimension_for_child(c, index):
+ if given_dimensions and given_dimensions[index] is not None:
+ return given_dimensions[index]
+ else:
return c.preferred_height(cli, write_position.width, write_position.extended_height)
-
- dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)]
-
- # Sum dimensions
- sum_dimensions = sum_layout_dimensions(dimensions)
-
- # If there is not enough space for both.
- # Don't do anything.
- if sum_dimensions.min > write_position.extended_height:
- return
-
- # Find optimal sizes. (Start with minimal size, increase until we cover
- # the whole height.)
- sizes = [d.min for d in dimensions]
-
- child_generator = take_using_weights(
- items=list(range(len(dimensions))),
- weights=[d.weight for d in dimensions])
-
- i = next(child_generator)
-
- while sum(sizes) < min(write_position.extended_height, sum_dimensions.preferred):
- # Increase until we meet at least the 'preferred' size.
- if sizes[i] < dimensions[i].preferred:
- sizes[i] += 1
- i = next(child_generator)
-
- if not any([cli.is_returning, cli.is_exiting, cli.is_aborting]):
- while sum(sizes) < min(write_position.height, sum_dimensions.max):
- # Increase until we use all the available space. (or until "max")
- if sizes[i] < dimensions[i].max:
- sizes[i] += 1
- i = next(child_generator)
-
- return sizes
-
- def walk(self, cli):
- """ Walk through children. """
- yield self
- for c in self.children:
- for i in c.walk(cli):
- yield i
-
-
-class VSplit(Container):
- """
- Several layouts, one stacked left/right of the other.
-
- :param children: List of child :class:`.Container` objects.
- :param window_too_small: A :class:`.Container` object that is displayed if
- there is not enough space for all the children. By default, this is a
- "Window too small" message.
- :param get_dimensions: (`None` or a callable that takes a
- `CommandLineInterface` and returns a list of `LayoutDimension`
- instances.) By default the dimensions are taken from the children and
- divided by the available space. However, when `get_dimensions` is specified,
- this is taken instead.
- :param report_dimensions_callback: When rendering, this function is called
- with the `CommandLineInterface` and the list of used dimensions. (As a
- list of integers.)
- """
- def __init__(self, children, window_too_small=None,
- get_dimensions=None, report_dimensions_callback=None):
- assert all(isinstance(c, Container) for c in children)
- assert window_too_small is None or isinstance(window_too_small, Container)
- assert get_dimensions is None or callable(get_dimensions)
- assert report_dimensions_callback is None or callable(report_dimensions_callback)
-
- self.children = children
- self.window_too_small = window_too_small or _window_too_small()
- self.get_dimensions = get_dimensions
- self.report_dimensions_callback = report_dimensions_callback
-
- def preferred_width(self, cli, max_available_width):
- dimensions = [c.preferred_width(cli, max_available_width) for c in self.children]
- return sum_layout_dimensions(dimensions)
-
+
+ dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)]
+
+ # Sum dimensions
+ sum_dimensions = sum_layout_dimensions(dimensions)
+
+ # If there is not enough space for both.
+ # Don't do anything.
+ if sum_dimensions.min > write_position.extended_height:
+ return
+
+ # Find optimal sizes. (Start with minimal size, increase until we cover
+ # the whole height.)
+ sizes = [d.min for d in dimensions]
+
+ child_generator = take_using_weights(
+ items=list(range(len(dimensions))),
+ weights=[d.weight for d in dimensions])
+
+ i = next(child_generator)
+
+ while sum(sizes) < min(write_position.extended_height, sum_dimensions.preferred):
+ # Increase until we meet at least the 'preferred' size.
+ if sizes[i] < dimensions[i].preferred:
+ sizes[i] += 1
+ i = next(child_generator)
+
+ if not any([cli.is_returning, cli.is_exiting, cli.is_aborting]):
+ while sum(sizes) < min(write_position.height, sum_dimensions.max):
+ # Increase until we use all the available space. (or until "max")
+ if sizes[i] < dimensions[i].max:
+ sizes[i] += 1
+ i = next(child_generator)
+
+ return sizes
+
+ def walk(self, cli):
+ """ Walk through children. """
+ yield self
+ for c in self.children:
+ for i in c.walk(cli):
+ yield i
+
+
+class VSplit(Container):
+ """
+ Several layouts, one stacked left/right of the other.
+
+ :param children: List of child :class:`.Container` objects.
+ :param window_too_small: A :class:`.Container` object that is displayed if
+ there is not enough space for all the children. By default, this is a
+ "Window too small" message.
+ :param get_dimensions: (`None` or a callable that takes a
+ `CommandLineInterface` and returns a list of `LayoutDimension`
+ instances.) By default the dimensions are taken from the children and
+ divided by the available space. However, when `get_dimensions` is specified,
+ this is taken instead.
+ :param report_dimensions_callback: When rendering, this function is called
+ with the `CommandLineInterface` and the list of used dimensions. (As a
+ list of integers.)
+ """
+ def __init__(self, children, window_too_small=None,
+ get_dimensions=None, report_dimensions_callback=None):
+ assert all(isinstance(c, Container) for c in children)
+ assert window_too_small is None or isinstance(window_too_small, Container)
+ assert get_dimensions is None or callable(get_dimensions)
+ assert report_dimensions_callback is None or callable(report_dimensions_callback)
+
+ self.children = children
+ self.window_too_small = window_too_small or _window_too_small()
+ self.get_dimensions = get_dimensions
+ self.report_dimensions_callback = report_dimensions_callback
+
+ def preferred_width(self, cli, max_available_width):
+ dimensions = [c.preferred_width(cli, max_available_width) for c in self.children]
+ return sum_layout_dimensions(dimensions)
+
def preferred_height(self, cli, width, max_available_height):
- sizes = self._divide_widths(cli, width)
- if sizes is None:
- return LayoutDimension()
- else:
+ sizes = self._divide_widths(cli, width)
+ if sizes is None:
+ return LayoutDimension()
+ else:
dimensions = [c.preferred_height(cli, s, max_available_height)
- for s, c in zip(sizes, self.children)]
- return max_layout_dimensions(dimensions)
-
- def reset(self):
- for c in self.children:
- c.reset()
-
- def _divide_widths(self, cli, width):
- """
- Return the widths for all columns.
- Or None when there is not enough space.
- """
- if not self.children:
- return []
-
- # Calculate widths.
- given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None
-
- def get_dimension_for_child(c, index):
- if given_dimensions and given_dimensions[index] is not None:
- return given_dimensions[index]
- else:
- return c.preferred_width(cli, width)
-
- dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)]
-
- # Sum dimensions
- sum_dimensions = sum_layout_dimensions(dimensions)
-
- # If there is not enough space for both.
- # Don't do anything.
- if sum_dimensions.min > width:
- return
-
- # Find optimal sizes. (Start with minimal size, increase until we cover
- # the whole height.)
- sizes = [d.min for d in dimensions]
-
- child_generator = take_using_weights(
- items=list(range(len(dimensions))),
- weights=[d.weight for d in dimensions])
-
- i = next(child_generator)
-
- while sum(sizes) < min(width, sum_dimensions.preferred):
- # Increase until we meet at least the 'preferred' size.
- if sizes[i] < dimensions[i].preferred:
- sizes[i] += 1
- i = next(child_generator)
-
- while sum(sizes) < min(width, sum_dimensions.max):
- # Increase until we use all the available space.
- if sizes[i] < dimensions[i].max:
- sizes[i] += 1
- i = next(child_generator)
-
- return sizes
-
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- """
- Render the prompt to a `Screen` instance.
-
- :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class
- to which the output has to be written.
- """
- if not self.children:
- return
-
- sizes = self._divide_widths(cli, write_position.width)
-
- if self.report_dimensions_callback:
- self.report_dimensions_callback(cli, sizes)
-
- # If there is not enough space.
- if sizes is None:
- self.window_too_small.write_to_screen(
- cli, screen, mouse_handlers, write_position)
- return
-
- # Calculate heights, take the largest possible, but not larger than write_position.extended_height.
+ for s, c in zip(sizes, self.children)]
+ return max_layout_dimensions(dimensions)
+
+ def reset(self):
+ for c in self.children:
+ c.reset()
+
+ def _divide_widths(self, cli, width):
+ """
+ Return the widths for all columns.
+ Or None when there is not enough space.
+ """
+ if not self.children:
+ return []
+
+ # Calculate widths.
+ given_dimensions = self.get_dimensions(cli) if self.get_dimensions else None
+
+ def get_dimension_for_child(c, index):
+ if given_dimensions and given_dimensions[index] is not None:
+ return given_dimensions[index]
+ else:
+ return c.preferred_width(cli, width)
+
+ dimensions = [get_dimension_for_child(c, index) for index, c in enumerate(self.children)]
+
+ # Sum dimensions
+ sum_dimensions = sum_layout_dimensions(dimensions)
+
+ # If there is not enough space for both.
+ # Don't do anything.
+ if sum_dimensions.min > width:
+ return
+
+ # Find optimal sizes. (Start with minimal size, increase until we cover
+ # the whole height.)
+ sizes = [d.min for d in dimensions]
+
+ child_generator = take_using_weights(
+ items=list(range(len(dimensions))),
+ weights=[d.weight for d in dimensions])
+
+ i = next(child_generator)
+
+ while sum(sizes) < min(width, sum_dimensions.preferred):
+ # Increase until we meet at least the 'preferred' size.
+ if sizes[i] < dimensions[i].preferred:
+ sizes[i] += 1
+ i = next(child_generator)
+
+ while sum(sizes) < min(width, sum_dimensions.max):
+ # Increase until we use all the available space.
+ if sizes[i] < dimensions[i].max:
+ sizes[i] += 1
+ i = next(child_generator)
+
+ return sizes
+
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ """
+ Render the prompt to a `Screen` instance.
+
+ :param screen: The :class:`~prompt_toolkit.layout.screen.Screen` class
+ to which the output has to be written.
+ """
+ if not self.children:
+ return
+
+ sizes = self._divide_widths(cli, write_position.width)
+
+ if self.report_dimensions_callback:
+ self.report_dimensions_callback(cli, sizes)
+
+ # If there is not enough space.
+ if sizes is None:
+ self.window_too_small.write_to_screen(
+ cli, screen, mouse_handlers, write_position)
+ return
+
+ # Calculate heights, take the largest possible, but not larger than write_position.extended_height.
heights = [child.preferred_height(cli, width, write_position.extended_height).preferred
- for width, child in zip(sizes, self.children)]
- height = max(write_position.height, min(write_position.extended_height, max(heights)))
-
- # Draw child panes.
- ypos = write_position.ypos
- xpos = write_position.xpos
-
- for s, c in zip(sizes, self.children):
- c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, s, height))
- xpos += s
-
- def walk(self, cli):
- """ Walk through children. """
- yield self
- for c in self.children:
- for i in c.walk(cli):
- yield i
-
-
-class FloatContainer(Container):
- """
- Container which can contain another container for the background, as well
- as a list of floating containers on top of it.
-
- Example Usage::
-
- FloatContainer(content=Window(...),
- floats=[
- Float(xcursor=True,
- ycursor=True,
- layout=CompletionMenu(...))
- ])
- """
- def __init__(self, content, floats):
- assert isinstance(content, Container)
- assert all(isinstance(f, Float) for f in floats)
-
- self.content = content
- self.floats = floats
-
- def reset(self):
- self.content.reset()
-
- for f in self.floats:
- f.content.reset()
-
- def preferred_width(self, cli, write_position):
- return self.content.preferred_width(cli, write_position)
-
+ for width, child in zip(sizes, self.children)]
+ height = max(write_position.height, min(write_position.extended_height, max(heights)))
+
+ # Draw child panes.
+ ypos = write_position.ypos
+ xpos = write_position.xpos
+
+ for s, c in zip(sizes, self.children):
+ c.write_to_screen(cli, screen, mouse_handlers, WritePosition(xpos, ypos, s, height))
+ xpos += s
+
+ def walk(self, cli):
+ """ Walk through children. """
+ yield self
+ for c in self.children:
+ for i in c.walk(cli):
+ yield i
+
+
+class FloatContainer(Container):
+ """
+ Container which can contain another container for the background, as well
+ as a list of floating containers on top of it.
+
+ Example Usage::
+
+ FloatContainer(content=Window(...),
+ floats=[
+ Float(xcursor=True,
+ ycursor=True,
+ layout=CompletionMenu(...))
+ ])
+ """
+ def __init__(self, content, floats):
+ assert isinstance(content, Container)
+ assert all(isinstance(f, Float) for f in floats)
+
+ self.content = content
+ self.floats = floats
+
+ def reset(self):
+ self.content.reset()
+
+ for f in self.floats:
+ f.content.reset()
+
+ def preferred_width(self, cli, write_position):
+ return self.content.preferred_width(cli, write_position)
+
def preferred_height(self, cli, width, max_available_height):
- """
- Return the preferred height of the float container.
- (We don't care about the height of the floats, they should always fit
- into the dimensions provided by the container.)
- """
+ """
+ Return the preferred height of the float container.
+ (We don't care about the height of the floats, they should always fit
+ into the dimensions provided by the container.)
+ """
return self.content.preferred_height(cli, width, max_available_height)
-
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- self.content.write_to_screen(cli, screen, mouse_handlers, write_position)
-
- for fl in self.floats:
- # When a menu_position was given, use this instead of the cursor
- # position. (These cursor positions are absolute, translate again
- # relative to the write_position.)
- # Note: This should be inside the for-loop, because one float could
- # set the cursor position to be used for the next one.
- cursor_position = screen.menu_position or screen.cursor_position
- cursor_position = Point(x=cursor_position.x - write_position.xpos,
- y=cursor_position.y - write_position.ypos)
-
- fl_width = fl.get_width(cli)
- fl_height = fl.get_height(cli)
-
- # Left & width given.
- if fl.left is not None and fl_width is not None:
- xpos = fl.left
- width = fl_width
- # Left & right given -> calculate width.
- elif fl.left is not None and fl.right is not None:
- xpos = fl.left
- width = write_position.width - fl.left - fl.right
- # Width & right given -> calculate left.
- elif fl_width is not None and fl.right is not None:
- xpos = write_position.width - fl.right - fl_width
- width = fl_width
- elif fl.xcursor:
- width = fl_width
- if width is None:
- width = fl.content.preferred_width(cli, write_position.width).preferred
- width = min(write_position.width, width)
-
- xpos = cursor_position.x
- if xpos + width > write_position.width:
- xpos = max(0, write_position.width - width)
- # Only width given -> center horizontally.
- elif fl_width:
- xpos = int((write_position.width - fl_width) / 2)
- width = fl_width
- # Otherwise, take preferred width from float content.
- else:
- width = fl.content.preferred_width(cli, write_position.width).preferred
-
- if fl.left is not None:
- xpos = fl.left
- elif fl.right is not None:
- xpos = max(0, write_position.width - width - fl.right)
- else: # Center horizontally.
- xpos = max(0, int((write_position.width - width) / 2))
-
- # Trim.
- width = min(width, write_position.width - xpos)
-
- # Top & height given.
- if fl.top is not None and fl_height is not None:
- ypos = fl.top
- height = fl_height
- # Top & bottom given -> calculate height.
- elif fl.top is not None and fl.bottom is not None:
- ypos = fl.top
- height = write_position.height - fl.top - fl.bottom
- # Height & bottom given -> calculate top.
- elif fl_height is not None and fl.bottom is not None:
- ypos = write_position.height - fl_height - fl.bottom
- height = fl_height
- # Near cursor
- elif fl.ycursor:
- ypos = cursor_position.y + 1
-
- height = fl_height
- if height is None:
+
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ self.content.write_to_screen(cli, screen, mouse_handlers, write_position)
+
+ for fl in self.floats:
+ # When a menu_position was given, use this instead of the cursor
+ # position. (These cursor positions are absolute, translate again
+ # relative to the write_position.)
+ # Note: This should be inside the for-loop, because one float could
+ # set the cursor position to be used for the next one.
+ cursor_position = screen.menu_position or screen.cursor_position
+ cursor_position = Point(x=cursor_position.x - write_position.xpos,
+ y=cursor_position.y - write_position.ypos)
+
+ fl_width = fl.get_width(cli)
+ fl_height = fl.get_height(cli)
+
+ # Left & width given.
+ if fl.left is not None and fl_width is not None:
+ xpos = fl.left
+ width = fl_width
+ # Left & right given -> calculate width.
+ elif fl.left is not None and fl.right is not None:
+ xpos = fl.left
+ width = write_position.width - fl.left - fl.right
+ # Width & right given -> calculate left.
+ elif fl_width is not None and fl.right is not None:
+ xpos = write_position.width - fl.right - fl_width
+ width = fl_width
+ elif fl.xcursor:
+ width = fl_width
+ if width is None:
+ width = fl.content.preferred_width(cli, write_position.width).preferred
+ width = min(write_position.width, width)
+
+ xpos = cursor_position.x
+ if xpos + width > write_position.width:
+ xpos = max(0, write_position.width - width)
+ # Only width given -> center horizontally.
+ elif fl_width:
+ xpos = int((write_position.width - fl_width) / 2)
+ width = fl_width
+ # Otherwise, take preferred width from float content.
+ else:
+ width = fl.content.preferred_width(cli, write_position.width).preferred
+
+ if fl.left is not None:
+ xpos = fl.left
+ elif fl.right is not None:
+ xpos = max(0, write_position.width - width - fl.right)
+ else: # Center horizontally.
+ xpos = max(0, int((write_position.width - width) / 2))
+
+ # Trim.
+ width = min(width, write_position.width - xpos)
+
+ # Top & height given.
+ if fl.top is not None and fl_height is not None:
+ ypos = fl.top
+ height = fl_height
+ # Top & bottom given -> calculate height.
+ elif fl.top is not None and fl.bottom is not None:
+ ypos = fl.top
+ height = write_position.height - fl.top - fl.bottom
+ # Height & bottom given -> calculate top.
+ elif fl_height is not None and fl.bottom is not None:
+ ypos = write_position.height - fl_height - fl.bottom
+ height = fl_height
+ # Near cursor
+ elif fl.ycursor:
+ ypos = cursor_position.y + 1
+
+ height = fl_height
+ if height is None:
height = fl.content.preferred_height(
cli, width, write_position.extended_height).preferred
-
- # Reduce height if not enough space. (We can use the
- # extended_height when the content requires it.)
- if height > write_position.extended_height - ypos:
- if write_position.extended_height - ypos + 1 >= ypos:
- # When the space below the cursor is more than
- # the space above, just reduce the height.
- height = write_position.extended_height - ypos
- else:
- # Otherwise, fit the float above the cursor.
- height = min(height, cursor_position.y)
- ypos = cursor_position.y - height
-
- # Only height given -> center vertically.
- elif fl_width:
- ypos = int((write_position.height - fl_height) / 2)
- height = fl_height
- # Otherwise, take preferred height from content.
- else:
+
+ # Reduce height if not enough space. (We can use the
+ # extended_height when the content requires it.)
+ if height > write_position.extended_height - ypos:
+ if write_position.extended_height - ypos + 1 >= ypos:
+ # When the space below the cursor is more than
+ # the space above, just reduce the height.
+ height = write_position.extended_height - ypos
+ else:
+ # Otherwise, fit the float above the cursor.
+ height = min(height, cursor_position.y)
+ ypos = cursor_position.y - height
+
+ # Only height given -> center vertically.
+ elif fl_width:
+ ypos = int((write_position.height - fl_height) / 2)
+ height = fl_height
+ # Otherwise, take preferred height from content.
+ else:
height = fl.content.preferred_height(
cli, width, write_position.extended_height).preferred
-
- if fl.top is not None:
- ypos = fl.top
- elif fl.bottom is not None:
- ypos = max(0, write_position.height - height - fl.bottom)
- else: # Center vertically.
- ypos = max(0, int((write_position.height - height) / 2))
-
- # Trim.
- height = min(height, write_position.height - ypos)
-
- # Write float.
- # (xpos and ypos can be negative: a float can be partially visible.)
- if height > 0 and width > 0:
- wp = WritePosition(xpos=xpos + write_position.xpos,
- ypos=ypos + write_position.ypos,
- width=width, height=height)
-
+
+ if fl.top is not None:
+ ypos = fl.top
+ elif fl.bottom is not None:
+ ypos = max(0, write_position.height - height - fl.bottom)
+ else: # Center vertically.
+ ypos = max(0, int((write_position.height - height) / 2))
+
+ # Trim.
+ height = min(height, write_position.height - ypos)
+
+ # Write float.
+ # (xpos and ypos can be negative: a float can be partially visible.)
+ if height > 0 and width > 0:
+ wp = WritePosition(xpos=xpos + write_position.xpos,
+ ypos=ypos + write_position.ypos,
+ width=width, height=height)
+
if not fl.hide_when_covering_content or self._area_is_empty(screen, wp):
fl.content.write_to_screen(cli, screen, mouse_handlers, wp)
@@ -530,80 +530,80 @@ class FloatContainer(Container):
return True
- def walk(self, cli):
- """ Walk through children. """
- yield self
-
- for i in self.content.walk(cli):
- yield i
-
- for f in self.floats:
- for i in f.content.walk(cli):
- yield i
-
-
-class Float(object):
- """
- Float for use in a :class:`.FloatContainer`.
-
- :param content: :class:`.Container` instance.
+ def walk(self, cli):
+ """ Walk through children. """
+ yield self
+
+ for i in self.content.walk(cli):
+ yield i
+
+ for f in self.floats:
+ for i in f.content.walk(cli):
+ yield i
+
+
+class Float(object):
+ """
+ Float for use in a :class:`.FloatContainer`.
+
+ :param content: :class:`.Container` instance.
:param hide_when_covering_content: Hide the float when it covers content underneath.
- """
- def __init__(self, top=None, right=None, bottom=None, left=None,
- width=None, height=None, get_width=None, get_height=None,
+ """
+ def __init__(self, top=None, right=None, bottom=None, left=None,
+ width=None, height=None, get_width=None, get_height=None,
xcursor=False, ycursor=False, content=None,
hide_when_covering_content=False):
- assert isinstance(content, Container)
- assert width is None or get_width is None
- assert height is None or get_height is None
-
- self.left = left
- self.right = right
- self.top = top
- self.bottom = bottom
-
- self._width = width
- self._height = height
-
- self._get_width = get_width
- self._get_height = get_height
-
- self.xcursor = xcursor
- self.ycursor = ycursor
-
- self.content = content
+ assert isinstance(content, Container)
+ assert width is None or get_width is None
+ assert height is None or get_height is None
+
+ self.left = left
+ self.right = right
+ self.top = top
+ self.bottom = bottom
+
+ self._width = width
+ self._height = height
+
+ self._get_width = get_width
+ self._get_height = get_height
+
+ self.xcursor = xcursor
+ self.ycursor = ycursor
+
+ self.content = content
self.hide_when_covering_content = hide_when_covering_content
-
- def get_width(self, cli):
- if self._width:
- return self._width
- if self._get_width:
- return self._get_width(cli)
-
- def get_height(self, cli):
- if self._height:
- return self._height
- if self._get_height:
- return self._get_height(cli)
-
- def __repr__(self):
- return 'Float(content=%r)' % self.content
-
-
-class WindowRenderInfo(object):
- """
- Render information, for the last render time of this control.
- It stores mapping information between the input buffers (in case of a
- :class:`~prompt_toolkit.layout.controls.BufferControl`) and the actual
- render position on the output screen.
-
- (Could be used for implementation of the Vi 'H' and 'L' key bindings as
- well as implementing mouse support.)
-
+
+ def get_width(self, cli):
+ if self._width:
+ return self._width
+ if self._get_width:
+ return self._get_width(cli)
+
+ def get_height(self, cli):
+ if self._height:
+ return self._height
+ if self._get_height:
+ return self._get_height(cli)
+
+ def __repr__(self):
+ return 'Float(content=%r)' % self.content
+
+
+class WindowRenderInfo(object):
+ """
+ Render information, for the last render time of this control.
+ It stores mapping information between the input buffers (in case of a
+ :class:`~prompt_toolkit.layout.controls.BufferControl`) and the actual
+ render position on the output screen.
+
+ (Could be used for implementation of the Vi 'H' and 'L' key bindings as
+ well as implementing mouse support.)
+
:param ui_content: The original :class:`.UIContent` instance that contains
the whole input, without clipping. (ui_content)
- :param horizontal_scroll: The horizontal scroll of the :class:`.Window` instance.
- :param vertical_scroll: The vertical scroll of the :class:`.Window` instance.
+ :param horizontal_scroll: The horizontal scroll of the :class:`.Window` instance.
+ :param vertical_scroll: The vertical scroll of the :class:`.Window` instance.
:param window_width: The width of the window that displays the content,
without the margins.
:param window_height: The height of the window that displays the content.
@@ -615,7 +615,7 @@ class WindowRenderInfo(object):
:param rowcol_to_yx: Mapping that maps (row, column) tuples representing
coordinates of the :class:`UIContent` to (y, x) absolute coordinates at
the rendered screen.
- """
+ """
def __init__(self, ui_content, horizontal_scroll, vertical_scroll,
window_width, window_height,
configured_scroll_offsets,
@@ -634,20 +634,20 @@ class WindowRenderInfo(object):
assert isinstance(wrap_lines, bool)
self.ui_content = ui_content
- self.vertical_scroll = vertical_scroll
+ self.vertical_scroll = vertical_scroll
self.window_width = window_width # Width without margins.
- self.window_height = window_height
+ self.window_height = window_height
- self.configured_scroll_offsets = configured_scroll_offsets
+ self.configured_scroll_offsets = configured_scroll_offsets
self.visible_line_to_row_col = visible_line_to_row_col
self.wrap_lines = wrap_lines
-
+
self._rowcol_to_yx = rowcol_to_yx # row/col from input to absolute y/x
# screen coordinates.
self._x_offset = x_offset
self._y_offset = y_offset
- @property
+ @property
def visible_line_to_input_line(self):
return dict(
(visible_line, rowcol[0])
@@ -655,29 +655,29 @@ class WindowRenderInfo(object):
@property
def cursor_position(self):
- """
+ """
Return the cursor position coordinates, relative to the left/top corner
of the rendered screen.
- """
+ """
cpos = self.ui_content.cursor_position
y, x = self._rowcol_to_yx[cpos.y, cpos.x]
return Point(x=x - self._x_offset, y=y - self._y_offset)
-
- @property
+
+ @property
def applied_scroll_offsets(self):
- """
+ """
Return a :class:`.ScrollOffsets` instance that indicates the actual
offset. This can be less than or equal to what's configured. E.g, when
the cursor is completely at the top, the top offset will be zero rather
than what's configured.
- """
+ """
if self.displayed_lines[0] == 0:
top = 0
else:
# Get row where the cursor is displayed.
y = self.input_line_to_visible_line[self.ui_content.cursor_position.y]
top = min(y, self.configured_scroll_offsets.top)
-
+
return ScrollOffsets(
top=top,
bottom=min(self.ui_content.line_count - self.displayed_lines[-1] - 1,
@@ -688,14 +688,14 @@ class WindowRenderInfo(object):
# double width characters in mind.)
left=0, right=0)
- @property
+ @property
def displayed_lines(self):
- """
+ """
List of all the visible rows. (Line numbers of the input buffer.)
The last line may not be entirely visible.
- """
+ """
return sorted(row for row, col in self.visible_line_to_row_col.values())
-
+
@property
def input_line_to_visible_line(self):
"""
@@ -711,74 +711,74 @@ class WindowRenderInfo(object):
result[v] = k
return result
- def first_visible_line(self, after_scroll_offset=False):
- """
- Return the line number (0 based) of the input document that corresponds
- with the first visible line.
- """
- if after_scroll_offset:
+ def first_visible_line(self, after_scroll_offset=False):
+ """
+ Return the line number (0 based) of the input document that corresponds
+ with the first visible line.
+ """
+ if after_scroll_offset:
return self.displayed_lines[self.applied_scroll_offsets.top]
else:
return self.displayed_lines[0]
-
- def last_visible_line(self, before_scroll_offset=False):
- """
- Like `first_visible_line`, but for the last visible line.
- """
- if before_scroll_offset:
+
+ def last_visible_line(self, before_scroll_offset=False):
+ """
+ Like `first_visible_line`, but for the last visible line.
+ """
+ if before_scroll_offset:
return self.displayed_lines[-1 - self.applied_scroll_offsets.bottom]
else:
return self.displayed_lines[-1]
-
- def center_visible_line(self, before_scroll_offset=False,
- after_scroll_offset=False):
- """
- Like `first_visible_line`, but for the center visible line.
- """
- return (self.first_visible_line(after_scroll_offset) +
- (self.last_visible_line(before_scroll_offset) -
+
+ def center_visible_line(self, before_scroll_offset=False,
+ after_scroll_offset=False):
+ """
+ Like `first_visible_line`, but for the center visible line.
+ """
+ return (self.first_visible_line(after_scroll_offset) +
+ (self.last_visible_line(before_scroll_offset) -
self.first_visible_line(after_scroll_offset)) // 2
- )
-
- @property
- def content_height(self):
- """
- The full height of the user control.
- """
+ )
+
+ @property
+ def content_height(self):
+ """
+ The full height of the user control.
+ """
return self.ui_content.line_count
-
- @property
- def full_height_visible(self):
- """
- True when the full height is visible (There is no vertical scroll.)
- """
+
+ @property
+ def full_height_visible(self):
+ """
+ True when the full height is visible (There is no vertical scroll.)
+ """
return self.vertical_scroll == 0 and self.last_visible_line() == self.content_height
-
- @property
- def top_visible(self):
- """
- True when the top of the buffer is visible.
- """
- return self.vertical_scroll == 0
-
- @property
- def bottom_visible(self):
- """
- True when the bottom of the buffer is visible.
- """
+
+ @property
+ def top_visible(self):
+ """
+ True when the top of the buffer is visible.
+ """
+ return self.vertical_scroll == 0
+
+ @property
+ def bottom_visible(self):
+ """
+ True when the bottom of the buffer is visible.
+ """
return self.last_visible_line() == self.content_height - 1
-
- @property
- def vertical_scroll_percentage(self):
- """
- Vertical scroll as a percentage. (0 means: the top is visible,
- 100 means: the bottom is visible.)
- """
+
+ @property
+ def vertical_scroll_percentage(self):
+ """
+ Vertical scroll as a percentage. (0 means: the top is visible,
+ 100 means: the bottom is visible.)
+ """
if self.bottom_visible:
return 100
else:
return (100 * self.vertical_scroll // self.content_height)
-
+
def get_height_for_line(self, lineno):
"""
Return the height of the given line.
@@ -788,20 +788,20 @@ class WindowRenderInfo(object):
return self.ui_content.get_height_for_line(lineno, self.window_width)
else:
return 1
-
-
-class ScrollOffsets(object):
- """
- Scroll offsets for the :class:`.Window` class.
-
- Note that left/right offsets only make sense if line wrapping is disabled.
- """
- def __init__(self, top=0, bottom=0, left=0, right=0):
+
+
+class ScrollOffsets(object):
+ """
+ Scroll offsets for the :class:`.Window` class.
+
+ Note that left/right offsets only make sense if line wrapping is disabled.
+ """
+ def __init__(self, top=0, bottom=0, left=0, right=0):
assert isinstance(top, Integer)
assert isinstance(bottom, Integer)
assert isinstance(left, Integer)
assert isinstance(right, Integer)
-
+
self._top = top
self._bottom = bottom
self._left = left
@@ -823,11 +823,11 @@ class ScrollOffsets(object):
def right(self):
return int(self._right)
- def __repr__(self):
- return 'ScrollOffsets(top=%r, bottom=%r, left=%r, right=%r)' % (
- self.top, self.bottom, self.left, self.right)
-
-
+ def __repr__(self):
+ return 'ScrollOffsets(top=%r, bottom=%r, left=%r, right=%r)' % (
+ self.top, self.bottom, self.left, self.right)
+
+
class ColorColumn(object):
def __init__(self, position, token=Token.ColorColumn):
self.position = position
@@ -837,46 +837,46 @@ class ColorColumn(object):
_in_insert_mode = ViInsertMode() | EmacsInsertMode()
-class Window(Container):
- """
- Container that holds a control.
-
- :param content: :class:`~prompt_toolkit.layout.controls.UIControl` instance.
- :param width: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance.
- :param height: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance.
- :param get_width: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`.
- :param get_height: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`.
- :param dont_extend_width: When `True`, don't take up more width then the
- preferred width reported by the control.
- :param dont_extend_height: When `True`, don't take up more width then the
- preferred height reported by the control.
- :param left_margins: A list of :class:`~prompt_toolkit.layout.margins.Margin`
- instance to be displayed on the left. For instance:
- :class:`~prompt_toolkit.layout.margins.NumberredMargin` can be one of
- them in order to show line numbers.
- :param right_margins: Like `left_margins`, but on the other side.
- :param scroll_offsets: :class:`.ScrollOffsets` instance, representing the
- preferred amount of lines/columns to be always visible before/after the
- cursor. When both top and bottom are a very high number, the cursor
- will be centered vertically most of the time.
- :param allow_scroll_beyond_bottom: A `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, allow
- scrolling so far, that the top part of the content is not visible
- anymore, while there is still empty space available at the bottom of
- the window. In the Vi editor for instance, this is possible. You will
- see tildes while the top part of the body is hidden.
+class Window(Container):
+ """
+ Container that holds a control.
+
+ :param content: :class:`~prompt_toolkit.layout.controls.UIControl` instance.
+ :param width: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance.
+ :param height: :class:`~prompt_toolkit.layout.dimension.LayoutDimension` instance.
+ :param get_width: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`.
+ :param get_height: callable which takes a `CommandLineInterface` and returns a `LayoutDimension`.
+ :param dont_extend_width: When `True`, don't take up more width then the
+ preferred width reported by the control.
+ :param dont_extend_height: When `True`, don't take up more width then the
+ preferred height reported by the control.
+ :param left_margins: A list of :class:`~prompt_toolkit.layout.margins.Margin`
+ instance to be displayed on the left. For instance:
+ :class:`~prompt_toolkit.layout.margins.NumberredMargin` can be one of
+ them in order to show line numbers.
+ :param right_margins: Like `left_margins`, but on the other side.
+ :param scroll_offsets: :class:`.ScrollOffsets` instance, representing the
+ preferred amount of lines/columns to be always visible before/after the
+ cursor. When both top and bottom are a very high number, the cursor
+ will be centered vertically most of the time.
+ :param allow_scroll_beyond_bottom: A `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, allow
+ scrolling so far, that the top part of the content is not visible
+ anymore, while there is still empty space available at the bottom of
+ the window. In the Vi editor for instance, this is possible. You will
+ see tildes while the top part of the body is hidden.
:param wrap_lines: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter`
instance. When True, don't scroll horizontally, but wrap lines instead.
- :param get_vertical_scroll: Callable that takes this window
- instance as input and returns a preferred vertical scroll.
- (When this is `None`, the scroll is only determined by the last and
- current cursor position.)
- :param get_horizontal_scroll: Callable that takes this window
- instance as input and returns a preferred vertical scroll.
- :param always_hide_cursor: A `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, never
- display the cursor, even when the user control specifies a cursor
- position.
+ :param get_vertical_scroll: Callable that takes this window
+ instance as input and returns a preferred vertical scroll.
+ (When this is `None`, the scroll is only determined by the last and
+ current cursor position.)
+ :param get_horizontal_scroll: Callable that takes this window
+ instance as input and returns a preferred vertical scroll.
+ :param always_hide_cursor: A `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter` instance. When True, never
+ display the cursor, even when the user control specifies a cursor
+ position.
:param cursorline: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter`
instance. When True, display a cursorline.
:param cursorcolumn: A `bool` or :class:`~prompt_toolkit.filters.CLIFilter`
@@ -888,73 +888,73 @@ class Window(Container):
if `cursorline` is True.
:param cursorcolumn_token: The token to be used for highlighting the current line,
if `cursorcolumn` is True.
- """
- def __init__(self, content, width=None, height=None, get_width=None,
- get_height=None, dont_extend_width=False, dont_extend_height=False,
- left_margins=None, right_margins=None, scroll_offsets=None,
+ """
+ def __init__(self, content, width=None, height=None, get_width=None,
+ get_height=None, dont_extend_width=False, dont_extend_height=False,
+ left_margins=None, right_margins=None, scroll_offsets=None,
allow_scroll_beyond_bottom=False, wrap_lines=False,
get_vertical_scroll=None, get_horizontal_scroll=None, always_hide_cursor=False,
cursorline=False, cursorcolumn=False, get_colorcolumns=None,
cursorline_token=Token.CursorLine, cursorcolumn_token=Token.CursorColumn):
- assert isinstance(content, UIControl)
- assert width is None or isinstance(width, LayoutDimension)
- assert height is None or isinstance(height, LayoutDimension)
- assert get_width is None or callable(get_width)
- assert get_height is None or callable(get_height)
- assert width is None or get_width is None
- assert height is None or get_height is None
- assert scroll_offsets is None or isinstance(scroll_offsets, ScrollOffsets)
- assert left_margins is None or all(isinstance(m, Margin) for m in left_margins)
- assert right_margins is None or all(isinstance(m, Margin) for m in right_margins)
- assert get_vertical_scroll is None or callable(get_vertical_scroll)
- assert get_horizontal_scroll is None or callable(get_horizontal_scroll)
+ assert isinstance(content, UIControl)
+ assert width is None or isinstance(width, LayoutDimension)
+ assert height is None or isinstance(height, LayoutDimension)
+ assert get_width is None or callable(get_width)
+ assert get_height is None or callable(get_height)
+ assert width is None or get_width is None
+ assert height is None or get_height is None
+ assert scroll_offsets is None or isinstance(scroll_offsets, ScrollOffsets)
+ assert left_margins is None or all(isinstance(m, Margin) for m in left_margins)
+ assert right_margins is None or all(isinstance(m, Margin) for m in right_margins)
+ assert get_vertical_scroll is None or callable(get_vertical_scroll)
+ assert get_horizontal_scroll is None or callable(get_horizontal_scroll)
assert get_colorcolumns is None or callable(get_colorcolumns)
-
- self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom)
- self.always_hide_cursor = to_cli_filter(always_hide_cursor)
+
+ self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom)
+ self.always_hide_cursor = to_cli_filter(always_hide_cursor)
self.wrap_lines = to_cli_filter(wrap_lines)
self.cursorline = to_cli_filter(cursorline)
self.cursorcolumn = to_cli_filter(cursorcolumn)
-
- self.content = content
- self.dont_extend_width = dont_extend_width
- self.dont_extend_height = dont_extend_height
- self.left_margins = left_margins or []
- self.right_margins = right_margins or []
- self.scroll_offsets = scroll_offsets or ScrollOffsets()
- self.get_vertical_scroll = get_vertical_scroll
- self.get_horizontal_scroll = get_horizontal_scroll
- self._width = get_width or (lambda cli: width)
- self._height = get_height or (lambda cli: height)
+
+ self.content = content
+ self.dont_extend_width = dont_extend_width
+ self.dont_extend_height = dont_extend_height
+ self.left_margins = left_margins or []
+ self.right_margins = right_margins or []
+ self.scroll_offsets = scroll_offsets or ScrollOffsets()
+ self.get_vertical_scroll = get_vertical_scroll
+ self.get_horizontal_scroll = get_horizontal_scroll
+ self._width = get_width or (lambda cli: width)
+ self._height = get_height or (lambda cli: height)
self.get_colorcolumns = get_colorcolumns or (lambda cli: [])
self.cursorline_token = cursorline_token
self.cursorcolumn_token = cursorcolumn_token
-
- # Cache for the screens generated by the margin.
+
+ # Cache for the screens generated by the margin.
self._ui_content_cache = SimpleCache(maxsize=8)
self._margin_width_cache = SimpleCache(maxsize=1)
-
- self.reset()
-
- def __repr__(self):
- return 'Window(content=%r)' % self.content
-
- def reset(self):
- self.content.reset()
-
- #: Scrolling position of the main content.
- self.vertical_scroll = 0
- self.horizontal_scroll = 0
-
+
+ self.reset()
+
+ def __repr__(self):
+ return 'Window(content=%r)' % self.content
+
+ def reset(self):
+ self.content.reset()
+
+ #: Scrolling position of the main content.
+ self.vertical_scroll = 0
+ self.horizontal_scroll = 0
+
# Vertical scroll 2: this is the vertical offset that a line is
# scrolled if a single line (the one that contains the cursor) consumes
# all of the vertical space.
self.vertical_scroll_2 = 0
- #: Keep render information (mappings between buffer input and render
- #: output.)
- self.render_info = None
-
+ #: Keep render information (mappings between buffer input and render
+ #: output.)
+ self.render_info = None
+
def _get_margin_width(self, cli, margin):
"""
Return the width for this margin.
@@ -970,70 +970,70 @@ class Window(Container):
key = (margin, cli.render_counter)
return self._margin_width_cache.get(key, get_width)
- def preferred_width(self, cli, max_available_width):
+ def preferred_width(self, cli, max_available_width):
# Calculate the width of the margin.
total_margin_width = sum(self._get_margin_width(cli, m) for m in
- self.left_margins + self.right_margins)
-
+ self.left_margins + self.right_margins)
+
# Window of the content. (Can be `None`.)
- preferred_width = self.content.preferred_width(
- cli, max_available_width - total_margin_width)
-
- if preferred_width is not None:
+ preferred_width = self.content.preferred_width(
+ cli, max_available_width - total_margin_width)
+
+ if preferred_width is not None:
# Include width of the margins.
- preferred_width += total_margin_width
-
- # Merge.
- return self._merge_dimensions(
- dimension=self._width(cli),
- preferred=preferred_width,
- dont_extend=self.dont_extend_width)
-
+ preferred_width += total_margin_width
+
+ # Merge.
+ return self._merge_dimensions(
+ dimension=self._width(cli),
+ preferred=preferred_width,
+ dont_extend=self.dont_extend_width)
+
def preferred_height(self, cli, width, max_available_height):
total_margin_width = sum(self._get_margin_width(cli, m) for m in
self.left_margins + self.right_margins)
wrap_lines = self.wrap_lines(cli)
- return self._merge_dimensions(
- dimension=self._height(cli),
+ return self._merge_dimensions(
+ dimension=self._height(cli),
preferred=self.content.preferred_height(
cli, width - total_margin_width, max_available_height, wrap_lines),
- dont_extend=self.dont_extend_height)
-
- @staticmethod
- def _merge_dimensions(dimension, preferred=None, dont_extend=False):
- """
- Take the LayoutDimension from this `Window` class and the received
- preferred size from the `UIControl` and return a `LayoutDimension` to
- report to the parent container.
- """
- dimension = dimension or LayoutDimension()
-
- # When a preferred dimension was explicitly given to the Window,
- # ignore the UIControl.
- if dimension.preferred_specified:
- preferred = dimension.preferred
-
- # When a 'preferred' dimension is given by the UIControl, make sure
- # that it stays within the bounds of the Window.
- if preferred is not None:
- if dimension.max:
- preferred = min(preferred, dimension.max)
-
- if dimension.min:
- preferred = max(preferred, dimension.min)
-
- # When a `dont_extend` flag has been given, use the preferred dimension
- # also as the max dimension.
- if dont_extend and preferred is not None:
- max_ = min(dimension.max, preferred)
- else:
- max_ = dimension.max
-
+ dont_extend=self.dont_extend_height)
+
+ @staticmethod
+ def _merge_dimensions(dimension, preferred=None, dont_extend=False):
+ """
+ Take the LayoutDimension from this `Window` class and the received
+ preferred size from the `UIControl` and return a `LayoutDimension` to
+ report to the parent container.
+ """
+ dimension = dimension or LayoutDimension()
+
+ # When a preferred dimension was explicitly given to the Window,
+ # ignore the UIControl.
+ if dimension.preferred_specified:
+ preferred = dimension.preferred
+
+ # When a 'preferred' dimension is given by the UIControl, make sure
+ # that it stays within the bounds of the Window.
+ if preferred is not None:
+ if dimension.max:
+ preferred = min(preferred, dimension.max)
+
+ if dimension.min:
+ preferred = max(preferred, dimension.min)
+
+ # When a `dont_extend` flag has been given, use the preferred dimension
+ # also as the max dimension.
+ if dont_extend and preferred is not None:
+ max_ = min(dimension.max, preferred)
+ else:
+ max_ = dimension.max
+
return LayoutDimension(
min=dimension.min, max=max_,
preferred=preferred, weight=dimension.weight)
-
+
def _get_ui_content(self, cli, width, height):
"""
Create a `UIContent` instance.
@@ -1054,28 +1054,28 @@ class Window(Container):
return '?'
return False
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- """
- Write window to screen. This renders the user control, the margins and
- copies everything over to the absolute position at the given screen.
- """
- # Calculate margin sizes.
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ """
+ Write window to screen. This renders the user control, the margins and
+ copies everything over to the absolute position at the given screen.
+ """
+ # Calculate margin sizes.
left_margin_widths = [self._get_margin_width(cli, m) for m in self.left_margins]
right_margin_widths = [self._get_margin_width(cli, m) for m in self.right_margins]
- total_margin_width = sum(left_margin_widths + right_margin_widths)
-
- # Render UserControl.
+ total_margin_width = sum(left_margin_widths + right_margin_widths)
+
+ # Render UserControl.
ui_content = self.content.create_content(
- cli, write_position.width - total_margin_width, write_position.height)
+ cli, write_position.width - total_margin_width, write_position.height)
assert isinstance(ui_content, UIContent)
-
- # Scroll content.
+
+ # Scroll content.
wrap_lines = self.wrap_lines(cli)
scroll_func = self._scroll_when_linewrapping if wrap_lines else self._scroll_without_linewrapping
-
+
scroll_func(
ui_content, write_position.width - total_margin_width, write_position.height, cli)
-
+
# Write body
visible_line_to_row_col, rowcol_to_yx = self._copy_body(
cli, ui_content, screen, write_position,
@@ -1086,37 +1086,37 @@ class Window(Container):
vertical_scroll_2=self.vertical_scroll_2,
always_hide_cursor=self.always_hide_cursor(cli))
- # Remember render info. (Set before generating the margins. They need this.)
+ # Remember render info. (Set before generating the margins. They need this.)
x_offset=write_position.xpos + sum(left_margin_widths)
y_offset=write_position.ypos
- self.render_info = WindowRenderInfo(
+ self.render_info = WindowRenderInfo(
ui_content=ui_content,
- horizontal_scroll=self.horizontal_scroll,
- vertical_scroll=self.vertical_scroll,
+ horizontal_scroll=self.horizontal_scroll,
+ vertical_scroll=self.vertical_scroll,
window_width=write_position.width - total_margin_width,
- window_height=write_position.height,
- configured_scroll_offsets=self.scroll_offsets,
+ window_height=write_position.height,
+ configured_scroll_offsets=self.scroll_offsets,
visible_line_to_row_col=visible_line_to_row_col,
rowcol_to_yx=rowcol_to_yx,
x_offset=x_offset,
y_offset=y_offset,
wrap_lines=wrap_lines)
-
- # Set mouse handlers.
- def mouse_handler(cli, mouse_event):
- """ Wrapper around the mouse_handler of the `UIControl` that turns
+
+ # Set mouse handlers.
+ def mouse_handler(cli, mouse_event):
+ """ Wrapper around the mouse_handler of the `UIControl` that turns
screen coordinates into line coordinates. """
# Find row/col position first.
yx_to_rowcol = dict((v, k) for k, v in rowcol_to_yx.items())
y = mouse_event.position.y
x = mouse_event.position.x
-
+
# If clicked below the content area, look for a position in the
# last line instead.
max_y = write_position.ypos + len(visible_line_to_row_col) - 1
y = min(max_y, y)
-
+
while x >= 0:
try:
row, col = yx_to_rowcol[y, x]
@@ -1139,72 +1139,72 @@ class Window(Container):
cli, MouseEvent(position=Point(x=0, y=0),
event_type=mouse_event.event_type))
- # If it returns NotImplemented, handle it here.
- if result == NotImplemented:
- return self._mouse_handler(cli, mouse_event)
-
- return result
-
- mouse_handlers.set_mouse_handler_for_range(
- x_min=write_position.xpos + sum(left_margin_widths),
- x_max=write_position.xpos + write_position.width - total_margin_width,
- y_min=write_position.ypos,
- y_max=write_position.ypos + write_position.height,
- handler=mouse_handler)
-
- # Render and copy margins.
- move_x = 0
-
- def render_margin(m, width):
- " Render margin. Return `Screen`. "
- # Retrieve margin tokens.
- tokens = m.create_margin(cli, self.render_info, width, write_position.height)
-
+ # If it returns NotImplemented, handle it here.
+ if result == NotImplemented:
+ return self._mouse_handler(cli, mouse_event)
+
+ return result
+
+ mouse_handlers.set_mouse_handler_for_range(
+ x_min=write_position.xpos + sum(left_margin_widths),
+ x_max=write_position.xpos + write_position.width - total_margin_width,
+ y_min=write_position.ypos,
+ y_max=write_position.ypos + write_position.height,
+ handler=mouse_handler)
+
+ # Render and copy margins.
+ move_x = 0
+
+ def render_margin(m, width):
+ " Render margin. Return `Screen`. "
+ # Retrieve margin tokens.
+ tokens = m.create_margin(cli, self.render_info, width, write_position.height)
+
# Turn it into a UIContent object.
- # already rendered those tokens using this size.)
+ # already rendered those tokens using this size.)
return TokenListControl.static(tokens).create_content(
cli, width + 1, write_position.height)
-
- for m, width in zip(self.left_margins, left_margin_widths):
- # Create screen for margin.
- margin_screen = render_margin(m, width)
-
- # Copy and shift X.
+
+ for m, width in zip(self.left_margins, left_margin_widths):
+ # Create screen for margin.
+ margin_screen = render_margin(m, width)
+
+ # Copy and shift X.
self._copy_margin(cli, margin_screen, screen, write_position, move_x, width)
- move_x += width
-
- move_x = write_position.width - sum(right_margin_widths)
-
- for m, width in zip(self.right_margins, right_margin_widths):
- # Create screen for margin.
- margin_screen = render_margin(m, width)
-
- # Copy and shift X.
+ move_x += width
+
+ move_x = write_position.width - sum(right_margin_widths)
+
+ for m, width in zip(self.right_margins, right_margin_widths):
+ # Create screen for margin.
+ margin_screen = render_margin(m, width)
+
+ # Copy and shift X.
self._copy_margin(cli, margin_screen, screen, write_position, move_x, width)
- move_x += width
-
+ move_x += width
+
def _copy_body(self, cli, ui_content, new_screen, write_position, move_x,
width, vertical_scroll=0, horizontal_scroll=0,
has_focus=False, wrap_lines=False, highlight_lines=False,
vertical_scroll_2=0, always_hide_cursor=False):
- """
+ """
Copy the UIContent into the output screen.
- """
- xpos = write_position.xpos + move_x
- ypos = write_position.ypos
+ """
+ xpos = write_position.xpos + move_x
+ ypos = write_position.ypos
line_count = ui_content.line_count
- new_buffer = new_screen.data_buffer
+ new_buffer = new_screen.data_buffer
empty_char = _CHAR_CACHE['', Token]
ZeroWidthEscape = Token.ZeroWidthEscape
-
+
# Map visible line number to (row, col) of input.
# 'col' will always be zero if line wrapping is off.
visible_line_to_row_col = {}
rowcol_to_yx = {} # Maps (row, col) from the input to (y, x) screen coordinates.
-
+
# Fill background with default_char first.
default_char = ui_content.default_char
-
+
if default_char:
for y in range(ypos, ypos + write_position.height):
new_buffer_row = new_buffer[y]
@@ -1295,33 +1295,33 @@ class Window(Container):
# 'Invalid position. row=%r col=%r, vertical_scroll=%r, '
# 'horizontal_scroll=%r, height=%r' %
# (row, col, vertical_scroll, horizontal_scroll, write_position.height))
- else:
+ else:
return Point(y=y, x=x)
-
+
# Set cursor and menu positions.
if ui_content.cursor_position:
screen_cursor_position = cursor_pos_to_screen_pos(
ui_content.cursor_position.y, ui_content.cursor_position.x)
-
+
if has_focus:
new_screen.cursor_position = screen_cursor_position
-
+
if always_hide_cursor:
new_screen.show_cursor = False
else:
new_screen.show_cursor = ui_content.show_cursor
-
+
self._highlight_digraph(cli, new_screen)
-
+
if highlight_lines:
self._highlight_cursorlines(
cli, new_screen, screen_cursor_position, xpos, ypos, width,
write_position.height)
-
+
# Draw input characters from the input processor queue.
if has_focus and ui_content.cursor_position:
self._show_input_processor_key_buffer(cli, new_screen)
-
+
# Set menu position.
if not new_screen.menu_position and ui_content.menu_position:
new_screen.menu_position = cursor_pos_to_screen_pos(
@@ -1333,7 +1333,7 @@ class Window(Container):
return visible_line_to_row_col, rowcol_to_yx
def _highlight_digraph(self, cli, new_screen):
- """
+ """
When we are in Vi digraph mode, put a question mark underneath the
cursor.
"""
@@ -1403,24 +1403,24 @@ class Window(Container):
def _copy_margin(self, cli, lazy_screen, new_screen, write_position, move_x, width):
"""
- Copy characters from the margin screen to the real screen.
- """
- xpos = write_position.xpos + move_x
- ypos = write_position.ypos
-
+ Copy characters from the margin screen to the real screen.
+ """
+ xpos = write_position.xpos + move_x
+ ypos = write_position.ypos
+
margin_write_position = WritePosition(xpos, ypos, width, write_position.height)
self._copy_body(cli, lazy_screen, new_screen, margin_write_position, 0, width)
-
+
def _scroll_when_linewrapping(self, ui_content, width, height, cli):
"""
Scroll to make sure the cursor position is visible and that we maintain
the requested scroll offset.
-
+
Set `self.horizontal_scroll/vertical_scroll`.
"""
scroll_offsets_bottom = self.scroll_offsets.bottom
scroll_offsets_top = self.scroll_offsets.top
-
+
# We don't have horizontal scrolling.
self.horizontal_scroll = 0
@@ -1506,12 +1506,12 @@ class Window(Container):
self.vertical_scroll = min(self.vertical_scroll, topmost_visible)
def _scroll_without_linewrapping(self, ui_content, width, height, cli):
- """
+ """
Scroll to make sure the cursor position is visible and that we maintain
the requested scroll offset.
Set `self.horizontal_scroll/vertical_scroll`.
- """
+ """
cursor_position = ui_content.cursor_position or Point(0, 0)
# Without line wrapping, we will never have to scroll vertically inside
@@ -1525,141 +1525,141 @@ class Window(Container):
else:
current_line_text = token_list_to_text(ui_content.get_line(cursor_position.y))
- def do_scroll(current_scroll, scroll_offset_start, scroll_offset_end,
- cursor_pos, window_size, content_size):
- " Scrolling algorithm. Used for both horizontal and vertical scrolling. "
- # Calculate the scroll offset to apply.
- # This can obviously never be more than have the screen size. Also, when the
- # cursor appears at the top or bottom, we don't apply the offset.
- scroll_offset_start = int(min(scroll_offset_start, window_size / 2, cursor_pos))
- scroll_offset_end = int(min(scroll_offset_end, window_size / 2,
- content_size - 1 - cursor_pos))
-
- # Prevent negative scroll offsets.
- if current_scroll < 0:
- current_scroll = 0
-
- # Scroll back if we scrolled to much and there's still space to show more of the document.
- if (not self.allow_scroll_beyond_bottom(cli) and
- current_scroll > content_size - window_size):
- current_scroll = max(0, content_size - window_size)
-
- # Scroll up if cursor is before visible part.
- if current_scroll > cursor_pos - scroll_offset_start:
- current_scroll = max(0, cursor_pos - scroll_offset_start)
-
- # Scroll down if cursor is after visible part.
- if current_scroll < (cursor_pos + 1) - window_size + scroll_offset_end:
- current_scroll = (cursor_pos + 1) - window_size + scroll_offset_end
-
+ def do_scroll(current_scroll, scroll_offset_start, scroll_offset_end,
+ cursor_pos, window_size, content_size):
+ " Scrolling algorithm. Used for both horizontal and vertical scrolling. "
+ # Calculate the scroll offset to apply.
+ # This can obviously never be more than have the screen size. Also, when the
+ # cursor appears at the top or bottom, we don't apply the offset.
+ scroll_offset_start = int(min(scroll_offset_start, window_size / 2, cursor_pos))
+ scroll_offset_end = int(min(scroll_offset_end, window_size / 2,
+ content_size - 1 - cursor_pos))
+
+ # Prevent negative scroll offsets.
+ if current_scroll < 0:
+ current_scroll = 0
+
+ # Scroll back if we scrolled to much and there's still space to show more of the document.
+ if (not self.allow_scroll_beyond_bottom(cli) and
+ current_scroll > content_size - window_size):
+ current_scroll = max(0, content_size - window_size)
+
+ # Scroll up if cursor is before visible part.
+ if current_scroll > cursor_pos - scroll_offset_start:
+ current_scroll = max(0, cursor_pos - scroll_offset_start)
+
+ # Scroll down if cursor is after visible part.
+ if current_scroll < (cursor_pos + 1) - window_size + scroll_offset_end:
+ current_scroll = (cursor_pos + 1) - window_size + scroll_offset_end
+
return current_scroll
-
- # When a preferred scroll is given, take that first into account.
- if self.get_vertical_scroll:
- self.vertical_scroll = self.get_vertical_scroll(self)
- assert isinstance(self.vertical_scroll, int)
- if self.get_horizontal_scroll:
- self.horizontal_scroll = self.get_horizontal_scroll(self)
- assert isinstance(self.horizontal_scroll, int)
-
- # Update horizontal/vertical scroll to make sure that the cursor
- # remains visible.
- offsets = self.scroll_offsets
-
+
+ # When a preferred scroll is given, take that first into account.
+ if self.get_vertical_scroll:
+ self.vertical_scroll = self.get_vertical_scroll(self)
+ assert isinstance(self.vertical_scroll, int)
+ if self.get_horizontal_scroll:
+ self.horizontal_scroll = self.get_horizontal_scroll(self)
+ assert isinstance(self.horizontal_scroll, int)
+
+ # Update horizontal/vertical scroll to make sure that the cursor
+ # remains visible.
+ offsets = self.scroll_offsets
+
self.vertical_scroll = do_scroll(
- current_scroll=self.vertical_scroll,
- scroll_offset_start=offsets.top,
- scroll_offset_end=offsets.bottom,
+ current_scroll=self.vertical_scroll,
+ scroll_offset_start=offsets.top,
+ scroll_offset_end=offsets.bottom,
cursor_pos=ui_content.cursor_position.y,
- window_size=height,
+ window_size=height,
content_size=ui_content.line_count)
-
+
self.horizontal_scroll = do_scroll(
- current_scroll=self.horizontal_scroll,
- scroll_offset_start=offsets.left,
- scroll_offset_end=offsets.right,
+ current_scroll=self.horizontal_scroll,
+ scroll_offset_start=offsets.left,
+ scroll_offset_end=offsets.right,
cursor_pos=get_cwidth(current_line_text[:ui_content.cursor_position.x]),
- window_size=width,
+ window_size=width,
# We can only analyse the current line. Calculating the width off
# all the lines is too expensive.
content_size=max(get_cwidth(current_line_text), self.horizontal_scroll + width))
-
- def _mouse_handler(self, cli, mouse_event):
- """
- Mouse handler. Called when the UI control doesn't handle this
- particular event.
- """
+
+ def _mouse_handler(self, cli, mouse_event):
+ """
+ Mouse handler. Called when the UI control doesn't handle this
+ particular event.
+ """
if mouse_event.event_type == MouseEventType.SCROLL_DOWN:
- self._scroll_down(cli)
+ self._scroll_down(cli)
elif mouse_event.event_type == MouseEventType.SCROLL_UP:
- self._scroll_up(cli)
-
- def _scroll_down(self, cli):
- " Scroll window down. "
- info = self.render_info
-
- if self.vertical_scroll < info.content_height - info.window_height:
- if info.cursor_position.y <= info.configured_scroll_offsets.top:
- self.content.move_cursor_down(cli)
-
- self.vertical_scroll += 1
-
- def _scroll_up(self, cli):
- " Scroll window up. "
- info = self.render_info
-
- if info.vertical_scroll > 0:
+ self._scroll_up(cli)
+
+ def _scroll_down(self, cli):
+ " Scroll window down. "
+ info = self.render_info
+
+ if self.vertical_scroll < info.content_height - info.window_height:
+ if info.cursor_position.y <= info.configured_scroll_offsets.top:
+ self.content.move_cursor_down(cli)
+
+ self.vertical_scroll += 1
+
+ def _scroll_up(self, cli):
+ " Scroll window up. "
+ info = self.render_info
+
+ if info.vertical_scroll > 0:
# TODO: not entirely correct yet in case of line wrapping and long lines.
- if info.cursor_position.y >= info.window_height - 1 - info.configured_scroll_offsets.bottom:
- self.content.move_cursor_up(cli)
-
- self.vertical_scroll -= 1
-
- def walk(self, cli):
- # Only yield self. A window doesn't have children.
- yield self
-
-
-class ConditionalContainer(Container):
- """
- Wrapper around any other container that can change the visibility. The
- received `filter` determines whether the given container should be
- displayed or not.
-
- :param content: :class:`.Container` instance.
- :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance.
- """
- def __init__(self, content, filter):
- assert isinstance(content, Container)
-
- self.content = content
- self.filter = to_cli_filter(filter)
-
+ if info.cursor_position.y >= info.window_height - 1 - info.configured_scroll_offsets.bottom:
+ self.content.move_cursor_up(cli)
+
+ self.vertical_scroll -= 1
+
+ def walk(self, cli):
+ # Only yield self. A window doesn't have children.
+ yield self
+
+
+class ConditionalContainer(Container):
+ """
+ Wrapper around any other container that can change the visibility. The
+ received `filter` determines whether the given container should be
+ displayed or not.
+
+ :param content: :class:`.Container` instance.
+ :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance.
+ """
+ def __init__(self, content, filter):
+ assert isinstance(content, Container)
+
+ self.content = content
+ self.filter = to_cli_filter(filter)
+
def __repr__(self):
return 'ConditionalContainer(%r, filter=%r)' % (self.content, self.filter)
- def reset(self):
- self.content.reset()
-
- def preferred_width(self, cli, max_available_width):
- if self.filter(cli):
- return self.content.preferred_width(cli, max_available_width)
- else:
- return LayoutDimension.exact(0)
-
+ def reset(self):
+ self.content.reset()
+
+ def preferred_width(self, cli, max_available_width):
+ if self.filter(cli):
+ return self.content.preferred_width(cli, max_available_width)
+ else:
+ return LayoutDimension.exact(0)
+
def preferred_height(self, cli, width, max_available_height):
- if self.filter(cli):
+ if self.filter(cli):
return self.content.preferred_height(cli, width, max_available_height)
- else:
- return LayoutDimension.exact(0)
-
- def write_to_screen(self, cli, screen, mouse_handlers, write_position):
- if self.filter(cli):
- return self.content.write_to_screen(cli, screen, mouse_handlers, write_position)
-
- def walk(self, cli):
- return self.content.walk(cli)
-
-
-# Deprecated alias for 'Container'.
-Layout = Container
+ else:
+ return LayoutDimension.exact(0)
+
+ def write_to_screen(self, cli, screen, mouse_handlers, write_position):
+ if self.filter(cli):
+ return self.content.write_to_screen(cli, screen, mouse_handlers, write_position)
+
+ def walk(self, cli):
+ return self.content.walk(cli)
+
+
+# Deprecated alias for 'Container'.
+Layout = Container
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
index 59107c7e5ed..ca74931dbc2 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
@@ -1,99 +1,99 @@
-"""
-User interface Controls for the layout.
-"""
-from __future__ import unicode_literals
-
-from abc import ABCMeta, abstractmethod
+"""
+User interface Controls for the layout.
+"""
+from __future__ import unicode_literals
+
+from abc import ABCMeta, abstractmethod
from collections import namedtuple
-from six import with_metaclass
+from six import with_metaclass
from six.moves import range
-
+
from prompt_toolkit.cache import SimpleCache
-from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
-from prompt_toolkit.filters import to_cli_filter
+from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
+from prompt_toolkit.filters import to_cli_filter
from prompt_toolkit.mouse_events import MouseEventType
-from prompt_toolkit.search_state import SearchState
-from prompt_toolkit.selection import SelectionType
+from prompt_toolkit.search_state import SearchState
+from prompt_toolkit.selection import SelectionType
from prompt_toolkit.token import Token
from prompt_toolkit.utils import get_cwidth
-
-from .lexers import Lexer, SimpleLexer
+
+from .lexers import Lexer, SimpleLexer
from .processors import Processor
from .screen import Char, Point
from .utils import token_list_width, split_lines, token_list_to_text
-
+
import six
-import time
-
-
-__all__ = (
- 'BufferControl',
- 'FillControl',
- 'TokenListControl',
- 'UIControl',
+import time
+
+
+__all__ = (
+ 'BufferControl',
+ 'FillControl',
+ 'TokenListControl',
+ 'UIControl',
'UIContent',
-)
-
-
-class UIControl(with_metaclass(ABCMeta, object)):
- """
- Base class for all user interface controls.
- """
- def reset(self):
- # Default reset. (Doesn't have to be implemented.)
- pass
-
- def preferred_width(self, cli, max_available_width):
- return None
-
+)
+
+
+class UIControl(with_metaclass(ABCMeta, object)):
+ """
+ Base class for all user interface controls.
+ """
+ def reset(self):
+ # Default reset. (Doesn't have to be implemented.)
+ pass
+
+ def preferred_width(self, cli, max_available_width):
+ return None
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
- return None
-
- def has_focus(self, cli):
- """
- Return ``True`` when this user control has the focus.
-
- If so, the cursor will be displayed according to the cursor position
+ return None
+
+ def has_focus(self, cli):
+ """
+ Return ``True`` when this user control has the focus.
+
+ If so, the cursor will be displayed according to the cursor position
reported by :meth:`.UIControl.create_content`. If the created content
has the property ``show_cursor=False``, the cursor will be hidden from
the output.
- """
- return False
-
- @abstractmethod
+ """
+ return False
+
+ @abstractmethod
def create_content(self, cli, width, height):
- """
+ """
Generate the content for this user control.
-
+
Returns a :class:`.UIContent` instance.
- """
-
- def mouse_handler(self, cli, mouse_event):
- """
- Handle mouse events.
-
- When `NotImplemented` is returned, it means that the given event is not
- handled by the `UIControl` itself. The `Window` or key bindings can
- decide to handle this event as scrolling or changing focus.
-
- :param cli: `CommandLineInterface` instance.
- :param mouse_event: `MouseEvent` instance.
- """
- return NotImplemented
-
- def move_cursor_down(self, cli):
- """
- Request to move the cursor down.
- This happens when scrolling down and the cursor is completely at the
- top.
- """
-
- def move_cursor_up(self, cli):
- """
- Request to move the cursor up.
- """
-
-
+ """
+
+ def mouse_handler(self, cli, mouse_event):
+ """
+ Handle mouse events.
+
+ When `NotImplemented` is returned, it means that the given event is not
+ handled by the `UIControl` itself. The `Window` or key bindings can
+ decide to handle this event as scrolling or changing focus.
+
+ :param cli: `CommandLineInterface` instance.
+ :param mouse_event: `MouseEvent` instance.
+ """
+ return NotImplemented
+
+ def move_cursor_down(self, cli):
+ """
+ Request to move the cursor down.
+ This happens when scrolling down and the cursor is completely at the
+ top.
+ """
+
+ def move_cursor_up(self, cli):
+ """
+ Request to move the cursor up.
+ """
+
+
class UIContent(object):
"""
Content generated by a user control. This content consists of a list of
@@ -166,135 +166,135 @@ class UIContent(object):
return max(1, quotient)
-class TokenListControl(UIControl):
- """
- Control that displays a list of (Token, text) tuples.
- (It's mostly optimized for rather small widgets, like toolbars, menus, etc...)
-
- Mouse support:
-
- The list of tokens can also contain tuples of three items, looking like:
- (Token, text, handler). When mouse support is enabled and the user
- clicks on this token, then the given handler is called. That handler
- should accept two inputs: (CommandLineInterface, MouseEvent) and it
- should either handle the event or return `NotImplemented` in case we
- want the containing Window to handle this event.
-
- :param get_tokens: Callable that takes a `CommandLineInterface` instance
- and returns the list of (Token, text) tuples to be displayed right now.
- :param default_char: default :class:`.Char` (character and Token) to use
- for the background when there is more space available than `get_tokens`
- returns.
- :param get_default_char: Like `default_char`, but this is a callable that
- takes a :class:`prompt_toolkit.interface.CommandLineInterface` and
- returns a :class:`.Char` instance.
- :param has_focus: `bool` or `CLIFilter`, when this evaluates to `True`,
- this UI control will take the focus. The cursor will be shown in the
- upper left corner of this control, unless `get_token` returns a
- ``Token.SetCursorPosition`` token somewhere in the token list, then the
- cursor will be shown there.
- """
- def __init__(self, get_tokens, default_char=None, get_default_char=None,
+class TokenListControl(UIControl):
+ """
+ Control that displays a list of (Token, text) tuples.
+ (It's mostly optimized for rather small widgets, like toolbars, menus, etc...)
+
+ Mouse support:
+
+ The list of tokens can also contain tuples of three items, looking like:
+ (Token, text, handler). When mouse support is enabled and the user
+ clicks on this token, then the given handler is called. That handler
+ should accept two inputs: (CommandLineInterface, MouseEvent) and it
+ should either handle the event or return `NotImplemented` in case we
+ want the containing Window to handle this event.
+
+ :param get_tokens: Callable that takes a `CommandLineInterface` instance
+ and returns the list of (Token, text) tuples to be displayed right now.
+ :param default_char: default :class:`.Char` (character and Token) to use
+ for the background when there is more space available than `get_tokens`
+ returns.
+ :param get_default_char: Like `default_char`, but this is a callable that
+ takes a :class:`prompt_toolkit.interface.CommandLineInterface` and
+ returns a :class:`.Char` instance.
+ :param has_focus: `bool` or `CLIFilter`, when this evaluates to `True`,
+ this UI control will take the focus. The cursor will be shown in the
+ upper left corner of this control, unless `get_token` returns a
+ ``Token.SetCursorPosition`` token somewhere in the token list, then the
+ cursor will be shown there.
+ """
+ def __init__(self, get_tokens, default_char=None, get_default_char=None,
align_right=False, align_center=False, has_focus=False):
assert callable(get_tokens)
- assert default_char is None or isinstance(default_char, Char)
- assert get_default_char is None or callable(get_default_char)
- assert not (default_char and get_default_char)
-
- self.align_right = to_cli_filter(align_right)
- self.align_center = to_cli_filter(align_center)
- self._has_focus_filter = to_cli_filter(has_focus)
-
- self.get_tokens = get_tokens
-
- # Construct `get_default_char` callable.
- if default_char:
- get_default_char = lambda _: default_char
- elif not get_default_char:
+ assert default_char is None or isinstance(default_char, Char)
+ assert get_default_char is None or callable(get_default_char)
+ assert not (default_char and get_default_char)
+
+ self.align_right = to_cli_filter(align_right)
+ self.align_center = to_cli_filter(align_center)
+ self._has_focus_filter = to_cli_filter(has_focus)
+
+ self.get_tokens = get_tokens
+
+ # Construct `get_default_char` callable.
+ if default_char:
+ get_default_char = lambda _: default_char
+ elif not get_default_char:
get_default_char = lambda _: Char(' ', Token.Transparent)
-
- self.get_default_char = get_default_char
-
+
+ self.get_default_char = get_default_char
+
#: Cache for the content.
self._content_cache = SimpleCache(maxsize=18)
self._token_cache = SimpleCache(maxsize=1)
- # Only cache one token list. We don't need the previous item.
-
- # Render info for the mouse support.
+ # Only cache one token list. We don't need the previous item.
+
+ # Render info for the mouse support.
self._tokens = None
-
+
def reset(self):
self._tokens = None
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.get_tokens)
-
- def _get_tokens_cached(self, cli):
- """
- Get tokens, but only retrieve tokens once during one render run.
- (This function is called several times during one rendering, because
- we also need those for calculating the dimensions.)
- """
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.get_tokens)
+
+ def _get_tokens_cached(self, cli):
+ """
+ Get tokens, but only retrieve tokens once during one render run.
+ (This function is called several times during one rendering, because
+ we also need those for calculating the dimensions.)
+ """
return self._token_cache.get(
- cli.render_counter, lambda: self.get_tokens(cli))
-
- def has_focus(self, cli):
- return self._has_focus_filter(cli)
-
- def preferred_width(self, cli, max_available_width):
- """
- Return the preferred width for this control.
- That is the width of the longest line.
- """
+ cli.render_counter, lambda: self.get_tokens(cli))
+
+ def has_focus(self, cli):
+ return self._has_focus_filter(cli)
+
+ def preferred_width(self, cli, max_available_width):
+ """
+ Return the preferred width for this control.
+ That is the width of the longest line.
+ """
text = token_list_to_text(self._get_tokens_cached(cli))
- line_lengths = [get_cwidth(l) for l in text.split('\n')]
- return max(line_lengths)
-
+ line_lengths = [get_cwidth(l) for l in text.split('\n')]
+ return max(line_lengths)
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
content = self.create_content(cli, width, None)
return content.line_count
-
+
def create_content(self, cli, width, height):
- # Get tokens
- tokens_with_mouse_handlers = self._get_tokens_cached(cli)
-
- default_char = self.get_default_char(cli)
-
- # Wrap/align right/center parameters.
- right = self.align_right(cli)
- center = self.align_center(cli)
-
- def process_line(line):
- " Center or right align a single line. "
- used_width = token_list_width(line)
- padding = width - used_width
- if center:
- padding = int(padding / 2)
+ # Get tokens
+ tokens_with_mouse_handlers = self._get_tokens_cached(cli)
+
+ default_char = self.get_default_char(cli)
+
+ # Wrap/align right/center parameters.
+ right = self.align_right(cli)
+ center = self.align_center(cli)
+
+ def process_line(line):
+ " Center or right align a single line. "
+ used_width = token_list_width(line)
+ padding = width - used_width
+ if center:
+ padding = int(padding / 2)
return [(default_char.token, default_char.char * padding)] + line
-
- if right or center:
+
+ if right or center:
token_lines_with_mouse_handlers = []
- for line in split_lines(tokens_with_mouse_handlers):
+ for line in split_lines(tokens_with_mouse_handlers):
token_lines_with_mouse_handlers.append(process_line(line))
else:
token_lines_with_mouse_handlers = list(split_lines(tokens_with_mouse_handlers))
-
- # Strip mouse handlers from tokens.
+
+ # Strip mouse handlers from tokens.
token_lines = [
[tuple(item[:2]) for item in line]
for line in token_lines_with_mouse_handlers
]
-
+
# Keep track of the tokens with mouse handler, for later use in
# `mouse_handler`.
- self._tokens = tokens_with_mouse_handlers
-
+ self._tokens = tokens_with_mouse_handlers
+
# If there is a `Token.SetCursorPosition` in the token list, set the
# cursor position here.
def get_cursor_position():
SetCursorPosition = Token.SetCursorPosition
-
+
for y, line in enumerate(token_lines):
x = 0
for token, text in line:
@@ -302,38 +302,38 @@ class TokenListControl(UIControl):
return Point(x=x, y=y)
x += len(text)
return None
-
+
# Create content, or take it from the cache.
key = (default_char.char, default_char.token,
tuple(tokens_with_mouse_handlers), width, right, center)
-
+
def get_content():
return UIContent(get_line=lambda i: token_lines[i],
line_count=len(token_lines),
default_char=default_char,
cursor_position=get_cursor_position())
-
+
return self._content_cache.get(key, get_content)
- @classmethod
- def static(cls, tokens):
- def get_static_tokens(cli):
- return tokens
- return cls(get_static_tokens)
-
- def mouse_handler(self, cli, mouse_event):
- """
- Handle mouse events.
-
- (When the token list contained mouse handlers and the user clicked on
- on any of these, the matching handler is called. This handler can still
- return `NotImplemented` in case we want the `Window` to handle this
- particular event.)
- """
+ @classmethod
+ def static(cls, tokens):
+ def get_static_tokens(cli):
+ return tokens
+ return cls(get_static_tokens)
+
+ def mouse_handler(self, cli, mouse_event):
+ """
+ Handle mouse events.
+
+ (When the token list contained mouse handlers and the user clicked on
+ on any of these, the matching handler is called. This handler can still
+ return `NotImplemented` in case we want the `Window` to handle this
+ particular event.)
+ """
if self._tokens:
# Read the generator.
tokens_for_line = list(split_lines(self._tokens))
-
+
try:
tokens = tokens_for_line[mouse_event.position.y]
except IndexError:
@@ -342,38 +342,38 @@ class TokenListControl(UIControl):
# Find position in the token list.
xpos = mouse_event.position.x
- # Find mouse handler for this character.
- count = 0
+ # Find mouse handler for this character.
+ count = 0
for item in tokens:
- count += len(item[1])
+ count += len(item[1])
if count >= xpos:
- if len(item) >= 3:
- # Handler found. Call it.
+ if len(item) >= 3:
+ # Handler found. Call it.
# (Handler can return NotImplemented, so return
# that result.)
- handler = item[2]
+ handler = item[2]
return handler(cli, mouse_event)
- else:
- break
-
- # Otherwise, don't handle here.
- return NotImplemented
-
-
-class FillControl(UIControl):
- """
- Fill whole control with characters with this token.
- (Also helpful for debugging.)
+ else:
+ break
+
+ # Otherwise, don't handle here.
+ return NotImplemented
+
+
+class FillControl(UIControl):
+ """
+ Fill whole control with characters with this token.
+ (Also helpful for debugging.)
:param char: :class:`.Char` instance to use for filling.
:param get_char: A callable that takes a CommandLineInterface and returns a
:class:`.Char` object.
- """
+ """
def __init__(self, character=None, token=Token, char=None, get_char=None): # 'character' and 'token' parameters are deprecated.
assert char is None or isinstance(char, Char)
assert get_char is None or callable(get_char)
assert not (char and get_char)
-
+
self.char = char
if character:
@@ -391,110 +391,110 @@ class FillControl(UIControl):
self.get_char = lambda cli: self.char
self.char = char
- def __repr__(self):
+ def __repr__(self):
if self.char:
return '%s(char=%r)' % (self.__class__.__name__, self.char)
else:
return '%s(get_char=%r)' % (self.__class__.__name__, self.get_char)
-
- def reset(self):
- pass
-
- def has_focus(self, cli):
- return False
-
+
+ def reset(self):
+ pass
+
+ def has_focus(self, cli):
+ return False
+
def create_content(self, cli, width, height):
def get_line(i):
return []
-
+
return UIContent(
get_line=get_line,
line_count=100 ** 100, # Something very big.
default_char=self.get_char(cli))
-
+
_ProcessedLine = namedtuple('_ProcessedLine', 'tokens source_to_display display_to_source')
-class BufferControl(UIControl):
- """
- Control for visualising the content of a `Buffer`.
-
- :param input_processors: list of :class:`~prompt_toolkit.layout.processors.Processor`.
- :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` instance for syntax highlighting.
- :param preview_search: `bool` or `CLIFilter`: Show search while typing.
- :param get_search_state: Callable that takes a CommandLineInterface and
- returns the SearchState to be used. (If not CommandLineInterface.search_state.)
- :param buffer_name: String representing the name of the buffer to display.
- :param default_char: :class:`.Char` instance to use to fill the background. This is
- transparent by default.
- :param focus_on_click: Focus this buffer when it's click, but not yet focussed.
- """
- def __init__(self,
- buffer_name=DEFAULT_BUFFER,
- input_processors=None,
- lexer=None,
- preview_search=False,
- search_buffer_name=SEARCH_BUFFER,
- get_search_state=None,
- menu_position=None,
- default_char=None,
- focus_on_click=False):
- assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
- assert menu_position is None or callable(menu_position)
- assert lexer is None or isinstance(lexer, Lexer)
- assert get_search_state is None or callable(get_search_state)
+class BufferControl(UIControl):
+ """
+ Control for visualising the content of a `Buffer`.
+
+ :param input_processors: list of :class:`~prompt_toolkit.layout.processors.Processor`.
+ :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` instance for syntax highlighting.
+ :param preview_search: `bool` or `CLIFilter`: Show search while typing.
+ :param get_search_state: Callable that takes a CommandLineInterface and
+ returns the SearchState to be used. (If not CommandLineInterface.search_state.)
+ :param buffer_name: String representing the name of the buffer to display.
+ :param default_char: :class:`.Char` instance to use to fill the background. This is
+ transparent by default.
+ :param focus_on_click: Focus this buffer when it's click, but not yet focussed.
+ """
+ def __init__(self,
+ buffer_name=DEFAULT_BUFFER,
+ input_processors=None,
+ lexer=None,
+ preview_search=False,
+ search_buffer_name=SEARCH_BUFFER,
+ get_search_state=None,
+ menu_position=None,
+ default_char=None,
+ focus_on_click=False):
+ assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
+ assert menu_position is None or callable(menu_position)
+ assert lexer is None or isinstance(lexer, Lexer)
+ assert get_search_state is None or callable(get_search_state)
assert default_char is None or isinstance(default_char, Char)
-
- self.preview_search = to_cli_filter(preview_search)
- self.get_search_state = get_search_state
- self.focus_on_click = to_cli_filter(focus_on_click)
-
- self.input_processors = input_processors or []
- self.buffer_name = buffer_name
- self.menu_position = menu_position
- self.lexer = lexer or SimpleLexer()
- self.default_char = default_char or Char(token=Token.Transparent)
- self.search_buffer_name = search_buffer_name
-
+
+ self.preview_search = to_cli_filter(preview_search)
+ self.get_search_state = get_search_state
+ self.focus_on_click = to_cli_filter(focus_on_click)
+
+ self.input_processors = input_processors or []
+ self.buffer_name = buffer_name
+ self.menu_position = menu_position
+ self.lexer = lexer or SimpleLexer()
+ self.default_char = default_char or Char(token=Token.Transparent)
+ self.search_buffer_name = search_buffer_name
+
#: Cache for the lexer.
- #: Often, due to cursor movement, undo/redo and window resizing
- #: operations, it happens that a short time, the same document has to be
- #: lexed. This is a faily easy way to cache such an expensive operation.
+ #: Often, due to cursor movement, undo/redo and window resizing
+ #: operations, it happens that a short time, the same document has to be
+ #: lexed. This is a faily easy way to cache such an expensive operation.
self._token_cache = SimpleCache(maxsize=8)
-
- self._xy_to_cursor_position = None
- self._last_click_timestamp = None
+
+ self._xy_to_cursor_position = None
+ self._last_click_timestamp = None
self._last_get_processed_line = None
-
- def _buffer(self, cli):
- """
- The buffer object that contains the 'main' content.
- """
- return cli.buffers[self.buffer_name]
-
- def has_focus(self, cli):
- # This control gets the focussed if the actual `Buffer` instance has the
- # focus or when any of the `InputProcessor` classes tells us that it
- # wants the focus. (E.g. in case of a reverse-search, where the actual
- # search buffer may not be displayed, but the "reverse-i-search" text
- # should get the focus.)
- return cli.current_buffer_name == self.buffer_name or \
- any(i.has_focus(cli) for i in self.input_processors)
-
- def preferred_width(self, cli, max_available_width):
+
+ def _buffer(self, cli):
+ """
+ The buffer object that contains the 'main' content.
+ """
+ return cli.buffers[self.buffer_name]
+
+ def has_focus(self, cli):
+ # This control gets the focussed if the actual `Buffer` instance has the
+ # focus or when any of the `InputProcessor` classes tells us that it
+ # wants the focus. (E.g. in case of a reverse-search, where the actual
+ # search buffer may not be displayed, but the "reverse-i-search" text
+ # should get the focus.)
+ return cli.current_buffer_name == self.buffer_name or \
+ any(i.has_focus(cli) for i in self.input_processors)
+
+ def preferred_width(self, cli, max_available_width):
"""
This should return the preferred width.
-
+
Note: We don't specify a preferred width according to the content,
because it would be too expensive. Calculating the preferred
width can be done by calculating the longest line, but this would
require applying all the processors to each line. This is
unfeasible for a larger document, and doing it for small
documents only would result in inconsistent behaviour.
- """
+ """
return None
-
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
# Calculate the content height, if it was drawn on a screen with the
# given width.
@@ -520,15 +520,15 @@ class BufferControl(UIControl):
return height
def _get_tokens_for_line_func(self, cli, document):
- """
+ """
Create a function that returns the tokens for a given line.
"""
# Cache using `document.text`.
def get_tokens_for_line():
return self.lexer.lex_document(cli, document)
-
+
return self._token_cache.get(document.text, get_tokens_for_line)
-
+
def _create_get_processed_line_func(self, cli, document):
"""
Create a function that takes a line number of the current document and
@@ -537,15 +537,15 @@ class BufferControl(UIControl):
"""
def transform(lineno, tokens):
" Transform the tokens for a given line number. "
- source_to_display_functions = []
- display_to_source_functions = []
-
+ source_to_display_functions = []
+ display_to_source_functions = []
+
# Get cursor position at this line.
if document.cursor_position_row == lineno:
cursor_column = document.cursor_position_col
else:
cursor_column = None
-
+
def source_to_display(i):
""" Translate x position from the buffer to the x position in the
processed token list. """
@@ -554,28 +554,28 @@ class BufferControl(UIControl):
return i
# Apply each processor.
- for p in self.input_processors:
+ for p in self.input_processors:
transformation = p.apply_transformation(
cli, document, lineno, source_to_display, tokens)
- tokens = transformation.tokens
-
+ tokens = transformation.tokens
+
if cursor_column:
cursor_column = transformation.source_to_display(cursor_column)
-
+
display_to_source_functions.append(transformation.display_to_source)
source_to_display_functions.append(transformation.source_to_display)
-
+
def display_to_source(i):
- for f in reversed(display_to_source_functions):
+ for f in reversed(display_to_source_functions):
i = f(i)
return i
-
+
return _ProcessedLine(tokens, source_to_display, display_to_source)
-
+
def create_func():
get_line = self._get_tokens_for_line_func(cli, document)
cache = {}
-
+
def get_processed_line(i):
try:
return cache[i]
@@ -584,48 +584,48 @@ class BufferControl(UIControl):
cache[i] = processed_line
return processed_line
return get_processed_line
-
+
return create_func()
-
+
def create_content(self, cli, width, height):
"""
Create a UIContent.
"""
- buffer = self._buffer(cli)
-
- # Get the document to be shown. If we are currently searching (the
- # search buffer has focus, and the preview_search filter is enabled),
- # then use the search document, which has possibly a different
- # text/cursor position.)
- def preview_now():
- """ True when we should preview a search. """
- return bool(self.preview_search(cli) and
- cli.buffers[self.search_buffer_name].text)
-
- if preview_now():
- if self.get_search_state:
- ss = self.get_search_state(cli)
- else:
- ss = cli.search_state
-
- document = buffer.document_for_search(SearchState(
- text=cli.current_buffer.text,
- direction=ss.direction,
- ignore_case=ss.ignore_case))
- else:
- document = buffer.document
-
+ buffer = self._buffer(cli)
+
+ # Get the document to be shown. If we are currently searching (the
+ # search buffer has focus, and the preview_search filter is enabled),
+ # then use the search document, which has possibly a different
+ # text/cursor position.)
+ def preview_now():
+ """ True when we should preview a search. """
+ return bool(self.preview_search(cli) and
+ cli.buffers[self.search_buffer_name].text)
+
+ if preview_now():
+ if self.get_search_state:
+ ss = self.get_search_state(cli)
+ else:
+ ss = cli.search_state
+
+ document = buffer.document_for_search(SearchState(
+ text=cli.current_buffer.text,
+ direction=ss.direction,
+ ignore_case=ss.ignore_case))
+ else:
+ document = buffer.document
+
get_processed_line = self._create_get_processed_line_func(cli, document)
self._last_get_processed_line = get_processed_line
-
+
def translate_rowcol(row, col):
" Return the content column for this coordinate. "
return Point(y=row, x=get_processed_line(row).source_to_display(col))
-
+
def get_line(i):
" Return the tokens for a given line number. "
tokens = get_processed_line(i).tokens
-
+
# Add a space at the end, because that is a possible cursor
# position. (When inserting after the input.) We should do this on
# all the lines, not just the line containing the cursor. (Because
@@ -633,60 +633,60 @@ class BufferControl(UIControl):
# cursor around.)
tokens = tokens + [(self.default_char.token, ' ')]
return tokens
-
+
content = UIContent(
get_line=get_line,
line_count=document.line_count,
cursor_position=translate_rowcol(document.cursor_position_row,
document.cursor_position_col),
default_char=self.default_char)
-
- # If there is an auto completion going on, use that start point for a
- # pop-up menu position. (But only when this buffer has the focus --
- # there is only one place for a menu, determined by the focussed buffer.)
- if cli.current_buffer_name == self.buffer_name:
- menu_position = self.menu_position(cli) if self.menu_position else None
- if menu_position is not None:
- assert isinstance(menu_position, int)
+
+ # If there is an auto completion going on, use that start point for a
+ # pop-up menu position. (But only when this buffer has the focus --
+ # there is only one place for a menu, determined by the focussed buffer.)
+ if cli.current_buffer_name == self.buffer_name:
+ menu_position = self.menu_position(cli) if self.menu_position else None
+ if menu_position is not None:
+ assert isinstance(menu_position, int)
menu_row, menu_col = buffer.document.translate_index_to_position(menu_position)
content.menu_position = translate_rowcol(menu_row, menu_col)
- elif buffer.complete_state:
- # Position for completion menu.
- # Note: We use 'min', because the original cursor position could be
- # behind the input string when the actual completion is for
- # some reason shorter than the text we had before. (A completion
- # can change and shorten the input.)
+ elif buffer.complete_state:
+ # Position for completion menu.
+ # Note: We use 'min', because the original cursor position could be
+ # behind the input string when the actual completion is for
+ # some reason shorter than the text we had before. (A completion
+ # can change and shorten the input.)
menu_row, menu_col = buffer.document.translate_index_to_position(
- min(buffer.cursor_position,
- buffer.complete_state.original_document.cursor_position))
+ min(buffer.cursor_position,
+ buffer.complete_state.original_document.cursor_position))
content.menu_position = translate_rowcol(menu_row, menu_col)
- else:
+ else:
content.menu_position = None
-
+
return content
-
- def mouse_handler(self, cli, mouse_event):
- """
- Mouse handler for this control.
- """
- buffer = self._buffer(cli)
- position = mouse_event.position
-
- # Focus buffer when clicked.
- if self.has_focus(cli):
+
+ def mouse_handler(self, cli, mouse_event):
+ """
+ Mouse handler for this control.
+ """
+ buffer = self._buffer(cli)
+ position = mouse_event.position
+
+ # Focus buffer when clicked.
+ if self.has_focus(cli):
if self._last_get_processed_line:
processed_line = self._last_get_processed_line(position.y)
- # Translate coordinates back to the cursor position of the
- # original input.
+ # Translate coordinates back to the cursor position of the
+ # original input.
xpos = processed_line.display_to_source(position.x)
index = buffer.document.translate_row_col_to_index(position.y, xpos)
-
- # Set the cursor position.
+
+ # Set the cursor position.
if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
buffer.exit_selection()
buffer.cursor_position = index
-
+
elif mouse_event.event_type == MouseEventType.MOUSE_UP:
# When the cursor was moved to another place, select the text.
# (The >1 is actually a small but acceptable workaround for
@@ -696,12 +696,12 @@ class BufferControl(UIControl):
if abs(buffer.cursor_position - index) > 1:
buffer.start_selection(selection_type=SelectionType.CHARACTERS)
buffer.cursor_position = index
-
+
# Select word around cursor on double click.
# Two MOUSE_UP events in a short timespan are considered a double click.
double_click = self._last_click_timestamp and time.time() - self._last_click_timestamp < .3
self._last_click_timestamp = time.time()
-
+
if double_click:
start, end = buffer.document.find_boundaries_of_current_word()
buffer.cursor_position += start
@@ -710,21 +710,21 @@ class BufferControl(UIControl):
else:
# Don't handle scroll events here.
return NotImplemented
-
- # Not focussed, but focussing on click events.
- else:
+
+ # Not focussed, but focussing on click events.
+ else:
if self.focus_on_click(cli) and mouse_event.event_type == MouseEventType.MOUSE_UP:
- # Focus happens on mouseup. (If we did this on mousedown, the
- # up event will be received at the point where this widget is
- # focussed and be handled anyway.)
- cli.focus(self.buffer_name)
- else:
- return NotImplemented
-
- def move_cursor_down(self, cli):
- b = self._buffer(cli)
- b.cursor_position += b.document.get_cursor_down_position()
-
- def move_cursor_up(self, cli):
- b = self._buffer(cli)
- b.cursor_position += b.document.get_cursor_up_position()
+ # Focus happens on mouseup. (If we did this on mousedown, the
+ # up event will be received at the point where this widget is
+ # focussed and be handled anyway.)
+ cli.focus(self.buffer_name)
+ else:
+ return NotImplemented
+
+ def move_cursor_down(self, cli):
+ b = self._buffer(cli)
+ b.cursor_position += b.document.get_cursor_down_position()
+
+ def move_cursor_up(self, cli):
+ b = self._buffer(cli)
+ b.cursor_position += b.document.get_cursor_up_position()
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py
index 82d2bb82f1b..717ad7a81fa 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/dimension.py
@@ -1,92 +1,92 @@
-"""
-Layout dimensions are used to give the minimum, maximum and preferred
-dimensions for containers and controls.
-"""
-from __future__ import unicode_literals
-
-__all__ = (
- 'LayoutDimension',
- 'sum_layout_dimensions',
- 'max_layout_dimensions',
-)
-
-
-class LayoutDimension(object):
- """
- Specified dimension (width/height) of a user control or window.
-
- The layout engine tries to honor the preferred size. If that is not
- possible, because the terminal is larger or smaller, it tries to keep in
- between min and max.
-
- :param min: Minimum size.
- :param max: Maximum size.
- :param weight: For a VSplit/HSplit, the actual size will be determined
- by taking the proportion of weights from all the children.
- E.g. When there are two children, one width a weight of 1,
- and the other with a weight of 2. The second will always be
- twice as big as the first, if the min/max values allow it.
- :param preferred: Preferred size.
- """
- def __init__(self, min=None, max=None, weight=1, preferred=None):
- assert isinstance(weight, int) and weight > 0 # Cannot be a float.
-
- self.min_specified = min is not None
- self.max_specified = max is not None
- self.preferred_specified = preferred is not None
-
- if min is None:
- min = 0 # Smallest possible value.
- if max is None: # 0-values are allowed, so use "is None"
- max = 1000 ** 10 # Something huge.
- if preferred is None:
- preferred = min
-
- self.min = min
- self.max = max
- self.preferred = preferred
- self.weight = weight
-
- # Make sure that the 'preferred' size is always in the min..max range.
- if self.preferred < self.min:
- self.preferred = self.min
-
- if self.preferred > self.max:
- self.preferred = self.max
-
- @classmethod
- def exact(cls, amount):
- """
- Return a :class:`.LayoutDimension` with an exact size. (min, max and
- preferred set to ``amount``).
- """
- return cls(min=amount, max=amount, preferred=amount)
-
- def __repr__(self):
- return 'LayoutDimension(min=%r, max=%r, preferred=%r, weight=%r)' % (
- self.min, self.max, self.preferred, self.weight)
-
- def __add__(self, other):
- return sum_layout_dimensions([self, other])
-
-
-def sum_layout_dimensions(dimensions):
- """
- Sum a list of :class:`.LayoutDimension` instances.
- """
- min = sum([d.min for d in dimensions if d.min is not None])
- max = sum([d.max for d in dimensions if d.max is not None])
- preferred = sum([d.preferred for d in dimensions])
-
- return LayoutDimension(min=min, max=max, preferred=preferred)
-
-
-def max_layout_dimensions(dimensions):
- """
- Take the maximum of a list of :class:`.LayoutDimension` instances.
- """
- min_ = max([d.min for d in dimensions if d.min is not None])
- max_ = max([d.max for d in dimensions if d.max is not None])
- preferred = max([d.preferred for d in dimensions])
-
- return LayoutDimension(min=min_, max=max_, preferred=preferred)
+"""
+Layout dimensions are used to give the minimum, maximum and preferred
+dimensions for containers and controls.
+"""
+from __future__ import unicode_literals
+
+__all__ = (
+ 'LayoutDimension',
+ 'sum_layout_dimensions',
+ 'max_layout_dimensions',
+)
+
+
+class LayoutDimension(object):
+ """
+ Specified dimension (width/height) of a user control or window.
+
+ The layout engine tries to honor the preferred size. If that is not
+ possible, because the terminal is larger or smaller, it tries to keep in
+ between min and max.
+
+ :param min: Minimum size.
+ :param max: Maximum size.
+ :param weight: For a VSplit/HSplit, the actual size will be determined
+ by taking the proportion of weights from all the children.
+ E.g. When there are two children, one width a weight of 1,
+ and the other with a weight of 2. The second will always be
+ twice as big as the first, if the min/max values allow it.
+ :param preferred: Preferred size.
+ """
+ def __init__(self, min=None, max=None, weight=1, preferred=None):
+ assert isinstance(weight, int) and weight > 0 # Cannot be a float.
+
+ self.min_specified = min is not None
+ self.max_specified = max is not None
+ self.preferred_specified = preferred is not None
+
+ if min is None:
+ min = 0 # Smallest possible value.
+ if max is None: # 0-values are allowed, so use "is None"
+ max = 1000 ** 10 # Something huge.
+ if preferred is None:
+ preferred = min
+
+ self.min = min
+ self.max = max
+ self.preferred = preferred
+ self.weight = weight
+
+ # Make sure that the 'preferred' size is always in the min..max range.
+ if self.preferred < self.min:
+ self.preferred = self.min
+
+ if self.preferred > self.max:
+ self.preferred = self.max
+
+ @classmethod
+ def exact(cls, amount):
+ """
+ Return a :class:`.LayoutDimension` with an exact size. (min, max and
+ preferred set to ``amount``).
+ """
+ return cls(min=amount, max=amount, preferred=amount)
+
+ def __repr__(self):
+ return 'LayoutDimension(min=%r, max=%r, preferred=%r, weight=%r)' % (
+ self.min, self.max, self.preferred, self.weight)
+
+ def __add__(self, other):
+ return sum_layout_dimensions([self, other])
+
+
+def sum_layout_dimensions(dimensions):
+ """
+ Sum a list of :class:`.LayoutDimension` instances.
+ """
+ min = sum([d.min for d in dimensions if d.min is not None])
+ max = sum([d.max for d in dimensions if d.max is not None])
+ preferred = sum([d.preferred for d in dimensions])
+
+ return LayoutDimension(min=min, max=max, preferred=preferred)
+
+
+def max_layout_dimensions(dimensions):
+ """
+ Take the maximum of a list of :class:`.LayoutDimension` instances.
+ """
+ min_ = max([d.min for d in dimensions if d.min is not None])
+ max_ = max([d.max for d in dimensions if d.max is not None])
+ preferred = max([d.preferred for d in dimensions])
+
+ return LayoutDimension(min=min_, max=max_, preferred=preferred)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py
index 8f3f36e2e29..a928fd82264 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/lexers.py
@@ -1,12 +1,12 @@
-"""
-Lexer interface and implementation.
-Used for syntax highlighting.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
+"""
+Lexer interface and implementation.
+Used for syntax highlighting.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
from six.moves import range
-
+
from prompt_toolkit.token import Token
from prompt_toolkit.filters import to_cli_filter
from .utils import split_lines
@@ -14,44 +14,44 @@ from .utils import split_lines
import re
import six
-__all__ = (
- 'Lexer',
- 'SimpleLexer',
- 'PygmentsLexer',
+__all__ = (
+ 'Lexer',
+ 'SimpleLexer',
+ 'PygmentsLexer',
'SyntaxSync',
'SyncFromStart',
'RegexSync',
-)
-
-
-class Lexer(with_metaclass(ABCMeta, object)):
- """
- Base class for all lexers.
- """
- @abstractmethod
+)
+
+
+class Lexer(with_metaclass(ABCMeta, object)):
+ """
+ Base class for all lexers.
+ """
+ @abstractmethod
def lex_document(self, cli, document):
- """
+ """
Takes a :class:`~prompt_toolkit.document.Document` and returns a
callable that takes a line number and returns the tokens for that line.
- """
-
-
-class SimpleLexer(Lexer):
- """
+ """
+
+
+class SimpleLexer(Lexer):
+ """
Lexer that doesn't do any tokenizing and returns the whole input as one token.
:param token: The `Token` for this lexer.
- """
+ """
# `default_token` parameter is deprecated!
def __init__(self, token=Token, default_token=None):
self.token = token
-
+
if default_token is not None:
self.token = default_token
-
+
def lex_document(self, cli, document):
lines = document.lines
-
+
def get_line(lineno):
" Return the tokens for the given line. "
try:
@@ -146,9 +146,9 @@ class RegexSync(SyntaxSync):
return cls(p)
-class PygmentsLexer(Lexer):
- """
- Lexer that calls a pygments lexer.
+class PygmentsLexer(Lexer):
+ """
+ Lexer that calls a pygments lexer.
Example::
@@ -169,7 +169,7 @@ class PygmentsLexer(Lexer):
recommended to disable this for inputs that are expected to be more
than 1,000 lines.
:param syntax_sync: `SyntaxSync` object.
- """
+ """
# Minimum amount of lines to go backwards when starting the parser.
# This is important when the lines are retrieved in reverse order, or when
# scrolling upwards. (Due to the complexity of calculating the vertical
@@ -185,15 +185,15 @@ class PygmentsLexer(Lexer):
def __init__(self, pygments_lexer_cls, sync_from_start=True, syntax_sync=None):
assert syntax_sync is None or isinstance(syntax_sync, SyntaxSync)
- self.pygments_lexer_cls = pygments_lexer_cls
+ self.pygments_lexer_cls = pygments_lexer_cls
self.sync_from_start = to_cli_filter(sync_from_start)
-
- # Instantiate the Pygments lexer.
- self.pygments_lexer = pygments_lexer_cls(
- stripnl=False,
- stripall=False,
- ensurenl=False)
-
+
+ # Instantiate the Pygments lexer.
+ self.pygments_lexer = pygments_lexer_cls(
+ stripnl=False,
+ stripall=False,
+ ensurenl=False)
+
# Create syntax sync instance.
self.syntax_sync = syntax_sync or RegexSync.from_pygments_lexer_cls(pygments_lexer_cls)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py
index 5b3e116f65e..2934dfc9a75 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/margins.py
@@ -1,166 +1,166 @@
-"""
-Margin implementations for a :class:`~prompt_toolkit.layout.containers.Window`.
-"""
-from __future__ import unicode_literals
-
+"""
+Margin implementations for a :class:`~prompt_toolkit.layout.containers.Window`.
+"""
+from __future__ import unicode_literals
+
from abc import ABCMeta, abstractmethod
-from six import with_metaclass
+from six import with_metaclass
from six.moves import range
-
-from prompt_toolkit.filters import to_cli_filter
+
+from prompt_toolkit.filters import to_cli_filter
from prompt_toolkit.token import Token
from prompt_toolkit.utils import get_cwidth
from .utils import token_list_to_text
-
-__all__ = (
- 'Margin',
- 'NumberredMargin',
- 'ScrollbarMargin',
- 'ConditionalMargin',
+
+__all__ = (
+ 'Margin',
+ 'NumberredMargin',
+ 'ScrollbarMargin',
+ 'ConditionalMargin',
'PromptMargin',
-)
-
-
-class Margin(with_metaclass(ABCMeta, object)):
- """
- Base interface for a margin.
- """
- @abstractmethod
+)
+
+
+class Margin(with_metaclass(ABCMeta, object)):
+ """
+ Base interface for a margin.
+ """
+ @abstractmethod
def get_width(self, cli, get_ui_content):
- """
- Return the width that this margin is going to consume.
+ """
+ Return the width that this margin is going to consume.
:param cli: :class:`.CommandLineInterface` instance.
:param get_ui_content: Callable that asks the user control to create
a :class:`.UIContent` instance. This can be used for instance to
obtain the number of lines.
- """
- return 0
-
- @abstractmethod
- def create_margin(self, cli, window_render_info, width, height):
- """
- Creates a margin.
- This should return a list of (Token, text) tuples.
-
+ """
+ return 0
+
+ @abstractmethod
+ def create_margin(self, cli, window_render_info, width, height):
+ """
+ Creates a margin.
+ This should return a list of (Token, text) tuples.
+
:param cli: :class:`.CommandLineInterface` instance.
- :param window_render_info:
- :class:`~prompt_toolkit.layout.containers.WindowRenderInfo`
- instance, generated after rendering and copying the visible part of
- the :class:`~prompt_toolkit.layout.controls.UIControl` into the
- :class:`~prompt_toolkit.layout.containers.Window`.
- :param width: The width that's available for this margin. (As reported
- by :meth:`.get_width`.)
- :param height: The height that's available for this margin. (The height
- of the :class:`~prompt_toolkit.layout.containers.Window`.)
- """
- return []
-
-
-class NumberredMargin(Margin):
- """
- Margin that displays the line numbers.
-
- :param relative: Number relative to the cursor position. Similar to the Vi
- 'relativenumber' option.
+ :param window_render_info:
+ :class:`~prompt_toolkit.layout.containers.WindowRenderInfo`
+ instance, generated after rendering and copying the visible part of
+ the :class:`~prompt_toolkit.layout.controls.UIControl` into the
+ :class:`~prompt_toolkit.layout.containers.Window`.
+ :param width: The width that's available for this margin. (As reported
+ by :meth:`.get_width`.)
+ :param height: The height that's available for this margin. (The height
+ of the :class:`~prompt_toolkit.layout.containers.Window`.)
+ """
+ return []
+
+
+class NumberredMargin(Margin):
+ """
+ Margin that displays the line numbers.
+
+ :param relative: Number relative to the cursor position. Similar to the Vi
+ 'relativenumber' option.
:param display_tildes: Display tildes after the end of the document, just
like Vi does.
- """
+ """
def __init__(self, relative=False, display_tildes=False):
- self.relative = to_cli_filter(relative)
+ self.relative = to_cli_filter(relative)
self.display_tildes = to_cli_filter(display_tildes)
-
+
def get_width(self, cli, get_ui_content):
line_count = get_ui_content().line_count
return max(3, len('%s' % line_count) + 1)
-
- def create_margin(self, cli, window_render_info, width, height):
- relative = self.relative(cli)
-
- token = Token.LineNumber
- token_current = Token.LineNumber.Current
-
- # Get current line number.
+
+ def create_margin(self, cli, window_render_info, width, height):
+ relative = self.relative(cli)
+
+ token = Token.LineNumber
+ token_current = Token.LineNumber.Current
+
+ # Get current line number.
current_lineno = window_render_info.ui_content.cursor_position.y
-
- # Construct margin.
- result = []
+
+ # Construct margin.
+ result = []
last_lineno = None
-
+
for y, lineno in enumerate(window_render_info.displayed_lines):
# Only display line number if this line is not a continuation of the previous line.
if lineno != last_lineno:
if lineno is None:
pass
elif lineno == current_lineno:
- # Current line.
- if relative:
- # Left align current number in relative mode.
+ # Current line.
+ if relative:
+ # Left align current number in relative mode.
result.append((token_current, '%i' % (lineno + 1)))
- else:
+ else:
result.append((token_current, ('%i ' % (lineno + 1)).rjust(width)))
- else:
- # Other lines.
- if relative:
+ else:
+ # Other lines.
+ if relative:
lineno = abs(lineno - current_lineno) - 1
-
+
result.append((token, ('%i ' % (lineno + 1)).rjust(width)))
-
+
last_lineno = lineno
- result.append((Token, '\n'))
-
+ result.append((Token, '\n'))
+
# Fill with tildes.
if self.display_tildes(cli):
while y < window_render_info.window_height:
result.append((Token.Tilde, '~\n'))
y += 1
- return result
-
-
-class ConditionalMargin(Margin):
- """
- Wrapper around other :class:`.Margin` classes to show/hide them.
- """
- def __init__(self, margin, filter):
- assert isinstance(margin, Margin)
-
- self.margin = margin
- self.filter = to_cli_filter(filter)
-
+ return result
+
+
+class ConditionalMargin(Margin):
+ """
+ Wrapper around other :class:`.Margin` classes to show/hide them.
+ """
+ def __init__(self, margin, filter):
+ assert isinstance(margin, Margin)
+
+ self.margin = margin
+ self.filter = to_cli_filter(filter)
+
def get_width(self, cli, ui_content):
- if self.filter(cli):
+ if self.filter(cli):
return self.margin.get_width(cli, ui_content)
- else:
- return 0
-
- def create_margin(self, cli, window_render_info, width, height):
- if width and self.filter(cli):
- return self.margin.create_margin(cli, window_render_info, width, height)
- else:
- return []
-
-
-class ScrollbarMargin(Margin):
- """
- Margin displaying a scrollbar.
+ else:
+ return 0
+
+ def create_margin(self, cli, window_render_info, width, height):
+ if width and self.filter(cli):
+ return self.margin.create_margin(cli, window_render_info, width, height)
+ else:
+ return []
+
+
+class ScrollbarMargin(Margin):
+ """
+ Margin displaying a scrollbar.
:param display_arrows: Display scroll up/down arrows.
- """
+ """
def __init__(self, display_arrows=False):
self.display_arrows = to_cli_filter(display_arrows)
def get_width(self, cli, ui_content):
- return 1
-
- def create_margin(self, cli, window_render_info, width, height):
- total_height = window_render_info.content_height
+ return 1
+
+ def create_margin(self, cli, window_render_info, width, height):
+ total_height = window_render_info.content_height
display_arrows = self.display_arrows(cli)
-
+
window_height = window_render_info.window_height
if display_arrows:
window_height -= 2
-
+
try:
items_per_row = float(total_height) / min(total_height, window_height)
except ZeroDivisionError:
@@ -170,7 +170,7 @@ class ScrollbarMargin(Margin):
" True if we should display a button on this row. "
current_row_middle = int((row + .5) * items_per_row)
return current_row_middle in window_render_info.displayed_lines
-
+
# Up arrow.
result = []
if display_arrows:
@@ -178,7 +178,7 @@ class ScrollbarMargin(Margin):
(Token.Scrollbar.Arrow, '^'),
(Token.Scrollbar, '\n')
])
-
+
# Scrollbar body.
for i in range(window_height):
if is_scroll_button(i):
@@ -186,7 +186,7 @@ class ScrollbarMargin(Margin):
else:
result.append((Token.Scrollbar, ' '))
result.append((Token, '\n'))
-
+
# Down arrow
if display_arrows:
result.append((Token.Scrollbar.Arrow, 'v'))
@@ -246,8 +246,8 @@ class PromptMargin(Margin):
if show_numbers:
if y != last_y:
tokens.append((Token.LineNumber, ('%i ' % (y + 1)).rjust(width)))
- else:
+ else:
tokens.extend(tokens2)
last_y = y
-
+
return tokens
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py
index 01e2a8358b5..a916846e458 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/menus.py
@@ -1,496 +1,496 @@
-from __future__ import unicode_literals
-
+from __future__ import unicode_literals
+
from six.moves import zip_longest, range
from prompt_toolkit.filters import HasCompletions, IsDone, Condition, to_cli_filter
from prompt_toolkit.mouse_events import MouseEventType
from prompt_toolkit.token import Token
-from prompt_toolkit.utils import get_cwidth
-
+from prompt_toolkit.utils import get_cwidth
+
from .containers import Window, HSplit, ConditionalContainer, ScrollOffsets
from .controls import UIControl, UIContent
-from .dimension import LayoutDimension
+from .dimension import LayoutDimension
from .margins import ScrollbarMargin
from .screen import Point, Char
-
-import math
-
-__all__ = (
- 'CompletionsMenu',
- 'MultiColumnCompletionsMenu',
-)
-
-
-class CompletionsMenuControl(UIControl):
- """
- Helper for drawing the complete menu to the screen.
-
- :param scroll_offset: Number (integer) representing the preferred amount of
- completions to be displayed before and after the current one. When this
- is a very high number, the current completion will be shown in the
- middle most of the time.
- """
+
+import math
+
+__all__ = (
+ 'CompletionsMenu',
+ 'MultiColumnCompletionsMenu',
+)
+
+
+class CompletionsMenuControl(UIControl):
+ """
+ Helper for drawing the complete menu to the screen.
+
+ :param scroll_offset: Number (integer) representing the preferred amount of
+ completions to be displayed before and after the current one. When this
+ is a very high number, the current completion will be shown in the
+ middle most of the time.
+ """
# Preferred minimum size of the menu control.
# The CompletionsMenu class defines a width of 8, and there is a scrollbar
# of 1.)
MIN_WIDTH = 7
-
+
def __init__(self):
- self.token = Token.Menu.Completions
-
- def has_focus(self, cli):
- return False
-
- def preferred_width(self, cli, max_available_width):
- complete_state = cli.current_buffer.complete_state
- if complete_state:
- menu_width = self._get_menu_width(500, complete_state)
- menu_meta_width = self._get_menu_meta_width(500, complete_state)
-
+ self.token = Token.Menu.Completions
+
+ def has_focus(self, cli):
+ return False
+
+ def preferred_width(self, cli, max_available_width):
+ complete_state = cli.current_buffer.complete_state
+ if complete_state:
+ menu_width = self._get_menu_width(500, complete_state)
+ menu_meta_width = self._get_menu_meta_width(500, complete_state)
+
return menu_width + menu_meta_width
- else:
- return 0
-
+ else:
+ return 0
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
- complete_state = cli.current_buffer.complete_state
- if complete_state:
- return len(complete_state.current_completions)
- else:
- return 0
-
+ complete_state = cli.current_buffer.complete_state
+ if complete_state:
+ return len(complete_state.current_completions)
+ else:
+ return 0
+
def create_content(self, cli, width, height):
- """
+ """
Create a UIContent object for this control.
- """
- complete_state = cli.current_buffer.complete_state
- if complete_state:
- completions = complete_state.current_completions
- index = complete_state.complete_index # Can be None!
-
- # Calculate width of completions menu.
+ """
+ complete_state = cli.current_buffer.complete_state
+ if complete_state:
+ completions = complete_state.current_completions
+ index = complete_state.complete_index # Can be None!
+
+ # Calculate width of completions menu.
menu_width = self._get_menu_width(width, complete_state)
menu_meta_width = self._get_menu_meta_width(width - menu_width, complete_state)
- show_meta = self._show_meta(complete_state)
-
+ show_meta = self._show_meta(complete_state)
+
def get_line(i):
c = completions[i]
is_current_completion = (i == index)
result = self._get_menu_item_tokens(c, is_current_completion, menu_width)
-
+
if show_meta:
result += self._get_menu_item_meta_tokens(c, is_current_completion, menu_meta_width)
return result
-
+
return UIContent(get_line=get_line,
cursor_position=Point(x=0, y=index or 0),
line_count=len(completions),
default_char=Char(' ', self.token))
-
+
return UIContent()
-
- def _show_meta(self, complete_state):
- """
- Return ``True`` if we need to show a column with meta information.
- """
- return any(c.display_meta for c in complete_state.current_completions)
-
- def _get_menu_width(self, max_width, complete_state):
- """
- Return the width of the main column.
- """
+
+ def _show_meta(self, complete_state):
+ """
+ Return ``True`` if we need to show a column with meta information.
+ """
+ return any(c.display_meta for c in complete_state.current_completions)
+
+ def _get_menu_width(self, max_width, complete_state):
+ """
+ Return the width of the main column.
+ """
return min(max_width, max(self.MIN_WIDTH, max(get_cwidth(c.display)
for c in complete_state.current_completions) + 2))
-
- def _get_menu_meta_width(self, max_width, complete_state):
- """
- Return the width of the meta column.
- """
- if self._show_meta(complete_state):
- return min(max_width, max(get_cwidth(c.display_meta)
- for c in complete_state.current_completions) + 2)
- else:
- return 0
-
- def _get_menu_item_tokens(self, completion, is_current_completion, width):
- if is_current_completion:
- token = self.token.Completion.Current
- else:
- token = self.token.Completion
-
- text, tw = _trim_text(completion.display, width - 2)
- padding = ' ' * (width - 2 - tw)
- return [(token, ' %s%s ' % (text, padding))]
-
- def _get_menu_item_meta_tokens(self, completion, is_current_completion, width):
- if is_current_completion:
- token = self.token.Meta.Current
- else:
- token = self.token.Meta
-
- text, tw = _trim_text(completion.display_meta, width - 2)
- padding = ' ' * (width - 2 - tw)
- return [(token, ' %s%s ' % (text, padding))]
-
- def mouse_handler(self, cli, mouse_event):
- """
- Handle mouse events: clicking and scrolling.
- """
- b = cli.current_buffer
-
+
+ def _get_menu_meta_width(self, max_width, complete_state):
+ """
+ Return the width of the meta column.
+ """
+ if self._show_meta(complete_state):
+ return min(max_width, max(get_cwidth(c.display_meta)
+ for c in complete_state.current_completions) + 2)
+ else:
+ return 0
+
+ def _get_menu_item_tokens(self, completion, is_current_completion, width):
+ if is_current_completion:
+ token = self.token.Completion.Current
+ else:
+ token = self.token.Completion
+
+ text, tw = _trim_text(completion.display, width - 2)
+ padding = ' ' * (width - 2 - tw)
+ return [(token, ' %s%s ' % (text, padding))]
+
+ def _get_menu_item_meta_tokens(self, completion, is_current_completion, width):
+ if is_current_completion:
+ token = self.token.Meta.Current
+ else:
+ token = self.token.Meta
+
+ text, tw = _trim_text(completion.display_meta, width - 2)
+ padding = ' ' * (width - 2 - tw)
+ return [(token, ' %s%s ' % (text, padding))]
+
+ def mouse_handler(self, cli, mouse_event):
+ """
+ Handle mouse events: clicking and scrolling.
+ """
+ b = cli.current_buffer
+
if mouse_event.event_type == MouseEventType.MOUSE_UP:
- # Select completion.
+ # Select completion.
b.go_to_completion(mouse_event.position.y)
- b.complete_state = None
-
+ b.complete_state = None
+
elif mouse_event.event_type == MouseEventType.SCROLL_DOWN:
- # Scroll up.
- b.complete_next(count=3, disable_wrap_around=True)
-
+ # Scroll up.
+ b.complete_next(count=3, disable_wrap_around=True)
+
elif mouse_event.event_type == MouseEventType.SCROLL_UP:
- # Scroll down.
- b.complete_previous(count=3, disable_wrap_around=True)
-
-
-def _trim_text(text, max_width):
- """
- Trim the text to `max_width`, append dots when the text is too long.
- Returns (text, width) tuple.
- """
- width = get_cwidth(text)
-
- # When the text is too wide, trim it.
- if width > max_width:
- # When there are no double width characters, just use slice operation.
- if len(text) == width:
- trimmed_text = (text[:max(1, max_width-3)] + '...')[:max_width]
- return trimmed_text, len(trimmed_text)
-
- # Otherwise, loop until we have the desired width. (Rather
- # inefficient, but ok for now.)
- else:
- trimmed_text = ''
- for c in text:
- if get_cwidth(trimmed_text + c) <= max_width - 3:
- trimmed_text += c
- trimmed_text += '...'
-
- return (trimmed_text, get_cwidth(trimmed_text))
- else:
- return text, width
-
-
-class CompletionsMenu(ConditionalContainer):
+ # Scroll down.
+ b.complete_previous(count=3, disable_wrap_around=True)
+
+
+def _trim_text(text, max_width):
+ """
+ Trim the text to `max_width`, append dots when the text is too long.
+ Returns (text, width) tuple.
+ """
+ width = get_cwidth(text)
+
+ # When the text is too wide, trim it.
+ if width > max_width:
+ # When there are no double width characters, just use slice operation.
+ if len(text) == width:
+ trimmed_text = (text[:max(1, max_width-3)] + '...')[:max_width]
+ return trimmed_text, len(trimmed_text)
+
+ # Otherwise, loop until we have the desired width. (Rather
+ # inefficient, but ok for now.)
+ else:
+ trimmed_text = ''
+ for c in text:
+ if get_cwidth(trimmed_text + c) <= max_width - 3:
+ trimmed_text += c
+ trimmed_text += '...'
+
+ return (trimmed_text, get_cwidth(trimmed_text))
+ else:
+ return text, width
+
+
+class CompletionsMenu(ConditionalContainer):
def __init__(self, max_height=None, scroll_offset=0, extra_filter=True, display_arrows=False):
extra_filter = to_cli_filter(extra_filter)
display_arrows = to_cli_filter(display_arrows)
- super(CompletionsMenu, self).__init__(
- content=Window(
+ super(CompletionsMenu, self).__init__(
+ content=Window(
content=CompletionsMenuControl(),
- width=LayoutDimension(min=8),
+ width=LayoutDimension(min=8),
height=LayoutDimension(min=1, max=max_height),
scroll_offsets=ScrollOffsets(top=scroll_offset, bottom=scroll_offset),
right_margins=[ScrollbarMargin(display_arrows=display_arrows)],
dont_extend_width=True,
),
- # Show when there are completions but not at the point we are
- # returning the input.
- filter=HasCompletions() & ~IsDone() & extra_filter)
-
-
-class MultiColumnCompletionMenuControl(UIControl):
- """
- Completion menu that displays all the completions in several columns.
- When there are more completions than space for them to be displayed, an
- arrow is shown on the left or right side.
-
- `min_rows` indicates how many rows will be available in any possible case.
- When this is langer than one, in will try to use less columns and more
- rows until this value is reached.
- Be careful passing in a too big value, if less than the given amount of
- rows are available, more columns would have been required, but
- `preferred_width` doesn't know about that and reports a too small value.
- This results in less completions displayed and additional scrolling.
- (It's a limitation of how the layout engine currently works: first the
- widths are calculated, then the heights.)
-
- :param suggested_max_column_width: The suggested max width of a column.
- The column can still be bigger than this, but if there is place for two
- columns of this width, we will display two columns. This to avoid that
- if there is one very wide completion, that it doesn't significantly
- reduce the amount of columns.
- """
- _required_margin = 3 # One extra padding on the right + space for arrows.
-
- def __init__(self, min_rows=3, suggested_max_column_width=30):
- assert isinstance(min_rows, int) and min_rows >= 1
-
- self.min_rows = min_rows
- self.suggested_max_column_width = suggested_max_column_width
- self.token = Token.Menu.Completions
- self.scroll = 0
-
- # Info of last rendering.
- self._rendered_rows = 0
- self._rendered_columns = 0
- self._total_columns = 0
- self._render_pos_to_completion = {}
- self._render_left_arrow = False
- self._render_right_arrow = False
- self._render_width = 0
-
- def reset(self):
- self.scroll = 0
-
- def has_focus(self, cli):
- return False
-
- def preferred_width(self, cli, max_available_width):
- """
- Preferred width: prefer to use at least min_rows, but otherwise as much
- as possible horizontally.
- """
- complete_state = cli.current_buffer.complete_state
- column_width = self._get_column_width(complete_state)
- result = int(column_width * math.ceil(len(complete_state.current_completions) / float(self.min_rows)))
-
- # When the desired width is still more than the maximum available,
- # reduce by removing columns until we are less than the available
- # width.
- while result > column_width and result > max_available_width - self._required_margin:
- result -= column_width
- return result + self._required_margin
-
+ # Show when there are completions but not at the point we are
+ # returning the input.
+ filter=HasCompletions() & ~IsDone() & extra_filter)
+
+
+class MultiColumnCompletionMenuControl(UIControl):
+ """
+ Completion menu that displays all the completions in several columns.
+ When there are more completions than space for them to be displayed, an
+ arrow is shown on the left or right side.
+
+ `min_rows` indicates how many rows will be available in any possible case.
+ When this is langer than one, in will try to use less columns and more
+ rows until this value is reached.
+ Be careful passing in a too big value, if less than the given amount of
+ rows are available, more columns would have been required, but
+ `preferred_width` doesn't know about that and reports a too small value.
+ This results in less completions displayed and additional scrolling.
+ (It's a limitation of how the layout engine currently works: first the
+ widths are calculated, then the heights.)
+
+ :param suggested_max_column_width: The suggested max width of a column.
+ The column can still be bigger than this, but if there is place for two
+ columns of this width, we will display two columns. This to avoid that
+ if there is one very wide completion, that it doesn't significantly
+ reduce the amount of columns.
+ """
+ _required_margin = 3 # One extra padding on the right + space for arrows.
+
+ def __init__(self, min_rows=3, suggested_max_column_width=30):
+ assert isinstance(min_rows, int) and min_rows >= 1
+
+ self.min_rows = min_rows
+ self.suggested_max_column_width = suggested_max_column_width
+ self.token = Token.Menu.Completions
+ self.scroll = 0
+
+ # Info of last rendering.
+ self._rendered_rows = 0
+ self._rendered_columns = 0
+ self._total_columns = 0
+ self._render_pos_to_completion = {}
+ self._render_left_arrow = False
+ self._render_right_arrow = False
+ self._render_width = 0
+
+ def reset(self):
+ self.scroll = 0
+
+ def has_focus(self, cli):
+ return False
+
+ def preferred_width(self, cli, max_available_width):
+ """
+ Preferred width: prefer to use at least min_rows, but otherwise as much
+ as possible horizontally.
+ """
+ complete_state = cli.current_buffer.complete_state
+ column_width = self._get_column_width(complete_state)
+ result = int(column_width * math.ceil(len(complete_state.current_completions) / float(self.min_rows)))
+
+ # When the desired width is still more than the maximum available,
+ # reduce by removing columns until we are less than the available
+ # width.
+ while result > column_width and result > max_available_width - self._required_margin:
+ result -= column_width
+ return result + self._required_margin
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
- """
- Preferred height: as much as needed in order to display all the completions.
- """
- complete_state = cli.current_buffer.complete_state
- column_width = self._get_column_width(complete_state)
- column_count = max(1, (width - self._required_margin) // column_width)
-
- return int(math.ceil(len(complete_state.current_completions) / float(column_count)))
-
+ """
+ Preferred height: as much as needed in order to display all the completions.
+ """
+ complete_state = cli.current_buffer.complete_state
+ column_width = self._get_column_width(complete_state)
+ column_count = max(1, (width - self._required_margin) // column_width)
+
+ return int(math.ceil(len(complete_state.current_completions) / float(column_count)))
+
def create_content(self, cli, width, height):
- """
+ """
Create a UIContent object for this menu.
- """
- complete_state = cli.current_buffer.complete_state
- column_width = self._get_column_width(complete_state)
- self._render_pos_to_completion = {}
-
- def grouper(n, iterable, fillvalue=None):
- " grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx "
- args = [iter(iterable)] * n
- return zip_longest(fillvalue=fillvalue, *args)
-
- def is_current_completion(completion):
- " Returns True when this completion is the currently selected one. "
- return complete_state.complete_index is not None and c == complete_state.current_completion
-
- # Space required outside of the regular columns, for displaying the
- # left and right arrow.
- HORIZONTAL_MARGIN_REQUIRED = 3
-
- if complete_state:
- # There should be at least one column, but it cannot be wider than
- # the available width.
- column_width = min(width - HORIZONTAL_MARGIN_REQUIRED, column_width)
-
- # However, when the columns tend to be very wide, because there are
- # some very wide entries, shrink it anyway.
- if column_width > self.suggested_max_column_width:
- # `column_width` can still be bigger that `suggested_max_column_width`,
- # but if there is place for two columns, we divide by two.
- column_width //= (column_width // self.suggested_max_column_width)
-
- visible_columns = max(1, (width - self._required_margin) // column_width)
-
- columns_ = list(grouper(height, complete_state.current_completions))
- rows_ = list(zip(*columns_))
-
- # Make sure the current completion is always visible: update scroll offset.
- selected_column = (complete_state.complete_index or 0) // height
- self.scroll = min(selected_column, max(self.scroll, selected_column - visible_columns + 1))
-
- render_left_arrow = self.scroll > 0
- render_right_arrow = self.scroll < len(rows_[0]) - visible_columns
-
- # Write completions to screen.
+ """
+ complete_state = cli.current_buffer.complete_state
+ column_width = self._get_column_width(complete_state)
+ self._render_pos_to_completion = {}
+
+ def grouper(n, iterable, fillvalue=None):
+ " grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx "
+ args = [iter(iterable)] * n
+ return zip_longest(fillvalue=fillvalue, *args)
+
+ def is_current_completion(completion):
+ " Returns True when this completion is the currently selected one. "
+ return complete_state.complete_index is not None and c == complete_state.current_completion
+
+ # Space required outside of the regular columns, for displaying the
+ # left and right arrow.
+ HORIZONTAL_MARGIN_REQUIRED = 3
+
+ if complete_state:
+ # There should be at least one column, but it cannot be wider than
+ # the available width.
+ column_width = min(width - HORIZONTAL_MARGIN_REQUIRED, column_width)
+
+ # However, when the columns tend to be very wide, because there are
+ # some very wide entries, shrink it anyway.
+ if column_width > self.suggested_max_column_width:
+ # `column_width` can still be bigger that `suggested_max_column_width`,
+ # but if there is place for two columns, we divide by two.
+ column_width //= (column_width // self.suggested_max_column_width)
+
+ visible_columns = max(1, (width - self._required_margin) // column_width)
+
+ columns_ = list(grouper(height, complete_state.current_completions))
+ rows_ = list(zip(*columns_))
+
+ # Make sure the current completion is always visible: update scroll offset.
+ selected_column = (complete_state.complete_index or 0) // height
+ self.scroll = min(selected_column, max(self.scroll, selected_column - visible_columns + 1))
+
+ render_left_arrow = self.scroll > 0
+ render_right_arrow = self.scroll < len(rows_[0]) - visible_columns
+
+ # Write completions to screen.
tokens_for_line = []
-
- for row_index, row in enumerate(rows_):
+
+ for row_index, row in enumerate(rows_):
tokens = []
- middle_row = row_index == len(rows_) // 2
-
- # Draw left arrow if we have hidden completions on the left.
- if render_left_arrow:
+ middle_row = row_index == len(rows_) // 2
+
+ # Draw left arrow if we have hidden completions on the left.
+ if render_left_arrow:
tokens += [(Token.Scrollbar, '<' if middle_row else ' ')]
-
- # Draw row content.
- for column_index, c in enumerate(row[self.scroll:][:visible_columns]):
- if c is not None:
- tokens += self._get_menu_item_tokens(c, is_current_completion(c), column_width)
-
- # Remember render position for mouse click handler.
- for x in range(column_width):
- self._render_pos_to_completion[(column_index * column_width + x, row_index)] = c
- else:
- tokens += [(self.token.Completion, ' ' * column_width)]
-
- # Draw trailing padding. (_get_menu_item_tokens only returns padding on the left.)
- tokens += [(self.token.Completion, ' ')]
-
- # Draw right arrow if we have hidden completions on the right.
- if render_right_arrow:
+
+ # Draw row content.
+ for column_index, c in enumerate(row[self.scroll:][:visible_columns]):
+ if c is not None:
+ tokens += self._get_menu_item_tokens(c, is_current_completion(c), column_width)
+
+ # Remember render position for mouse click handler.
+ for x in range(column_width):
+ self._render_pos_to_completion[(column_index * column_width + x, row_index)] = c
+ else:
+ tokens += [(self.token.Completion, ' ' * column_width)]
+
+ # Draw trailing padding. (_get_menu_item_tokens only returns padding on the left.)
+ tokens += [(self.token.Completion, ' ')]
+
+ # Draw right arrow if we have hidden completions on the right.
+ if render_right_arrow:
tokens += [(Token.Scrollbar, '>' if middle_row else ' ')]
-
- # Newline.
+
+ # Newline.
tokens_for_line.append(tokens)
-
+
else:
tokens = []
-
- self._rendered_rows = height
- self._rendered_columns = visible_columns
- self._total_columns = len(columns_)
- self._render_left_arrow = render_left_arrow
- self._render_right_arrow = render_right_arrow
- self._render_width = column_width * visible_columns + render_left_arrow + render_right_arrow + 1
-
+
+ self._rendered_rows = height
+ self._rendered_columns = visible_columns
+ self._total_columns = len(columns_)
+ self._render_left_arrow = render_left_arrow
+ self._render_right_arrow = render_right_arrow
+ self._render_width = column_width * visible_columns + render_left_arrow + render_right_arrow + 1
+
def get_line(i):
return tokens_for_line[i]
-
+
return UIContent(get_line=get_line, line_count=len(rows_))
- def _get_column_width(self, complete_state):
- """
- Return the width of each column.
- """
- return max(get_cwidth(c.display) for c in complete_state.current_completions) + 1
-
- def _get_menu_item_tokens(self, completion, is_current_completion, width):
- if is_current_completion:
- token = self.token.Completion.Current
- else:
- token = self.token.Completion
-
- text, tw = _trim_text(completion.display, width)
- padding = ' ' * (width - tw - 1)
-
- return [(token, ' %s%s' % (text, padding))]
-
- def mouse_handler(self, cli, mouse_event):
- """
- Handle scoll and click events.
- """
- b = cli.current_buffer
-
- def scroll_left():
- b.complete_previous(count=self._rendered_rows, disable_wrap_around=True)
- self.scroll = max(0, self.scroll - 1)
-
- def scroll_right():
- b.complete_next(count=self._rendered_rows, disable_wrap_around=True)
- self.scroll = min(self._total_columns - self._rendered_columns, self.scroll + 1)
-
+ def _get_column_width(self, complete_state):
+ """
+ Return the width of each column.
+ """
+ return max(get_cwidth(c.display) for c in complete_state.current_completions) + 1
+
+ def _get_menu_item_tokens(self, completion, is_current_completion, width):
+ if is_current_completion:
+ token = self.token.Completion.Current
+ else:
+ token = self.token.Completion
+
+ text, tw = _trim_text(completion.display, width)
+ padding = ' ' * (width - tw - 1)
+
+ return [(token, ' %s%s' % (text, padding))]
+
+ def mouse_handler(self, cli, mouse_event):
+ """
+ Handle scoll and click events.
+ """
+ b = cli.current_buffer
+
+ def scroll_left():
+ b.complete_previous(count=self._rendered_rows, disable_wrap_around=True)
+ self.scroll = max(0, self.scroll - 1)
+
+ def scroll_right():
+ b.complete_next(count=self._rendered_rows, disable_wrap_around=True)
+ self.scroll = min(self._total_columns - self._rendered_columns, self.scroll + 1)
+
if mouse_event.event_type == MouseEventType.SCROLL_DOWN:
- scroll_right()
-
+ scroll_right()
+
elif mouse_event.event_type == MouseEventType.SCROLL_UP:
- scroll_left()
-
+ scroll_left()
+
elif mouse_event.event_type == MouseEventType.MOUSE_UP:
- x = mouse_event.position.x
- y = mouse_event.position.y
-
- # Mouse click on left arrow.
- if x == 0:
- if self._render_left_arrow:
- scroll_left()
-
- # Mouse click on right arrow.
- elif x == self._render_width - 1:
- if self._render_right_arrow:
- scroll_right()
-
- # Mouse click on completion.
- else:
- completion = self._render_pos_to_completion.get((x, y))
- if completion:
- b.apply_completion(completion)
-
-
-class MultiColumnCompletionsMenu(HSplit):
- """
- Container that displays the completions in several columns.
- When `show_meta` (a :class:`~prompt_toolkit.filters.CLIFilter`) evaluates
- to True, it shows the meta information at the bottom.
- """
- def __init__(self, min_rows=3, suggested_max_column_width=30, show_meta=True, extra_filter=True):
- show_meta = to_cli_filter(show_meta)
- extra_filter = to_cli_filter(extra_filter)
-
- # Display filter: show when there are completions but not at the point
- # we are returning the input.
- full_filter = HasCompletions() & ~IsDone() & extra_filter
-
- any_completion_has_meta = Condition(lambda cli:
- any(c.display_meta for c in cli.current_buffer.complete_state.current_completions))
-
- # Create child windows.
- completions_window = ConditionalContainer(
- content=Window(
- content=MultiColumnCompletionMenuControl(
- min_rows=min_rows, suggested_max_column_width=suggested_max_column_width),
- width=LayoutDimension(min=8),
- height=LayoutDimension(min=1)),
- filter=full_filter)
-
- meta_window = ConditionalContainer(
- content=Window(content=_SelectedCompletionMetaControl()),
- filter=show_meta & full_filter & any_completion_has_meta)
-
- # Initialise split.
- super(MultiColumnCompletionsMenu, self).__init__([
- completions_window,
- meta_window
- ])
-
-
-class _SelectedCompletionMetaControl(UIControl):
- """
- Control that shows the meta information of the selected token.
- """
- def preferred_width(self, cli, max_available_width):
- """
- Report the width of the longest meta text as the preferred width of this control.
-
- It could be that we use less width, but this way, we're sure that the
- layout doesn't change when we select another completion (E.g. that
- completions are suddenly shown in more or fewer columns.)
- """
- if cli.current_buffer.complete_state:
- state = cli.current_buffer.complete_state
- return 2 + max(get_cwidth(c.display_meta) for c in state.current_completions)
- else:
- return 0
-
+ x = mouse_event.position.x
+ y = mouse_event.position.y
+
+ # Mouse click on left arrow.
+ if x == 0:
+ if self._render_left_arrow:
+ scroll_left()
+
+ # Mouse click on right arrow.
+ elif x == self._render_width - 1:
+ if self._render_right_arrow:
+ scroll_right()
+
+ # Mouse click on completion.
+ else:
+ completion = self._render_pos_to_completion.get((x, y))
+ if completion:
+ b.apply_completion(completion)
+
+
+class MultiColumnCompletionsMenu(HSplit):
+ """
+ Container that displays the completions in several columns.
+ When `show_meta` (a :class:`~prompt_toolkit.filters.CLIFilter`) evaluates
+ to True, it shows the meta information at the bottom.
+ """
+ def __init__(self, min_rows=3, suggested_max_column_width=30, show_meta=True, extra_filter=True):
+ show_meta = to_cli_filter(show_meta)
+ extra_filter = to_cli_filter(extra_filter)
+
+ # Display filter: show when there are completions but not at the point
+ # we are returning the input.
+ full_filter = HasCompletions() & ~IsDone() & extra_filter
+
+ any_completion_has_meta = Condition(lambda cli:
+ any(c.display_meta for c in cli.current_buffer.complete_state.current_completions))
+
+ # Create child windows.
+ completions_window = ConditionalContainer(
+ content=Window(
+ content=MultiColumnCompletionMenuControl(
+ min_rows=min_rows, suggested_max_column_width=suggested_max_column_width),
+ width=LayoutDimension(min=8),
+ height=LayoutDimension(min=1)),
+ filter=full_filter)
+
+ meta_window = ConditionalContainer(
+ content=Window(content=_SelectedCompletionMetaControl()),
+ filter=show_meta & full_filter & any_completion_has_meta)
+
+ # Initialise split.
+ super(MultiColumnCompletionsMenu, self).__init__([
+ completions_window,
+ meta_window
+ ])
+
+
+class _SelectedCompletionMetaControl(UIControl):
+ """
+ Control that shows the meta information of the selected token.
+ """
+ def preferred_width(self, cli, max_available_width):
+ """
+ Report the width of the longest meta text as the preferred width of this control.
+
+ It could be that we use less width, but this way, we're sure that the
+ layout doesn't change when we select another completion (E.g. that
+ completions are suddenly shown in more or fewer columns.)
+ """
+ if cli.current_buffer.complete_state:
+ state = cli.current_buffer.complete_state
+ return 2 + max(get_cwidth(c.display_meta) for c in state.current_completions)
+ else:
+ return 0
+
def preferred_height(self, cli, width, max_available_height, wrap_lines):
- return 1
-
+ return 1
+
def create_content(self, cli, width, height):
tokens = self._get_tokens(cli)
-
+
def get_line(i):
return tokens
return UIContent(get_line=get_line, line_count=1 if tokens else 0)
- def _get_tokens(self, cli):
- token = Token.Menu.Completions.MultiColumnMeta
- state = cli.current_buffer.complete_state
-
- if state and state.current_completion and state.current_completion.display_meta:
- return [(token, ' %s ' % state.current_completion.display_meta)]
-
- return []
+ def _get_tokens(self, cli):
+ token = Token.Menu.Completions.MultiColumnMeta
+ state = cli.current_buffer.complete_state
+
+ if state and state.current_completion and state.current_completion.display_meta:
+ return [(token, ' %s ' % state.current_completion.display_meta)]
+
+ return []
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py
index 57e4125b6d7..d443bf8315e 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/mouse_handlers.py
@@ -1,29 +1,29 @@
-from __future__ import unicode_literals
-
-from itertools import product
-from collections import defaultdict
-
-__all__ = (
- 'MouseHandlers',
-)
-
-
-class MouseHandlers(object):
- """
- Two dimentional raster of callbacks for mouse events.
- """
- def __init__(self):
- def dummy_callback(cli, mouse_event):
- """
- :param mouse_event: `MouseEvent` instance.
- """
-
- # Map (x,y) tuples to handlers.
- self.mouse_handlers = defaultdict(lambda: dummy_callback)
-
- def set_mouse_handler_for_range(self, x_min, x_max, y_min, y_max, handler=None):
- """
- Set mouse handler for a region.
- """
- for x, y in product(range(x_min, x_max), range(y_min, y_max)):
- self.mouse_handlers[x,y] = handler
+from __future__ import unicode_literals
+
+from itertools import product
+from collections import defaultdict
+
+__all__ = (
+ 'MouseHandlers',
+)
+
+
+class MouseHandlers(object):
+ """
+ Two dimentional raster of callbacks for mouse events.
+ """
+ def __init__(self):
+ def dummy_callback(cli, mouse_event):
+ """
+ :param mouse_event: `MouseEvent` instance.
+ """
+
+ # Map (x,y) tuples to handlers.
+ self.mouse_handlers = defaultdict(lambda: dummy_callback)
+
+ def set_mouse_handler_for_range(self, x_min, x_max, y_min, y_max, handler=None):
+ """
+ Set mouse handler for a region.
+ """
+ for x, y in product(range(x_min, x_max), range(y_min, y_max)):
+ self.mouse_handlers[x,y] = handler
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py
index 6054fc3cafd..0b8bc9c223d 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/processors.py
@@ -1,55 +1,55 @@
-"""
-Processors are little transformation blocks that transform the token list from
-a buffer before the BufferControl will render it to the screen.
-
-They can insert tokens before or after, or highlight fragments by replacing the
-token types.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
+"""
+Processors are little transformation blocks that transform the token list from
+a buffer before the BufferControl will render it to the screen.
+
+They can insert tokens before or after, or highlight fragments by replacing the
+token types.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
from six.moves import range
-
+
from prompt_toolkit.cache import SimpleCache
-from prompt_toolkit.document import Document
-from prompt_toolkit.enums import SEARCH_BUFFER
+from prompt_toolkit.document import Document
+from prompt_toolkit.enums import SEARCH_BUFFER
from prompt_toolkit.filters import to_cli_filter, ViInsertMultipleMode
-from prompt_toolkit.layout.utils import token_list_to_text
+from prompt_toolkit.layout.utils import token_list_to_text
from prompt_toolkit.reactive import Integer
from prompt_toolkit.token import Token
-
+
from .utils import token_list_len, explode_tokens
-
+
import re
-__all__ = (
- 'Processor',
- 'Transformation',
-
- 'HighlightSearchProcessor',
- 'HighlightSelectionProcessor',
- 'PasswordProcessor',
+__all__ = (
+ 'Processor',
+ 'Transformation',
+
+ 'HighlightSearchProcessor',
+ 'HighlightSelectionProcessor',
+ 'PasswordProcessor',
'HighlightMatchingBracketProcessor',
'DisplayMultipleCursors',
- 'BeforeInput',
- 'AfterInput',
- 'AppendAutoSuggestion',
- 'ConditionalProcessor',
- 'ShowLeadingWhiteSpaceProcessor',
- 'ShowTrailingWhiteSpaceProcessor',
+ 'BeforeInput',
+ 'AfterInput',
+ 'AppendAutoSuggestion',
+ 'ConditionalProcessor',
+ 'ShowLeadingWhiteSpaceProcessor',
+ 'ShowTrailingWhiteSpaceProcessor',
'TabsProcessor',
-)
-
-
-class Processor(with_metaclass(ABCMeta, object)):
- """
+)
+
+
+class Processor(with_metaclass(ABCMeta, object)):
+ """
Manipulate the tokens for a given line in a
- :class:`~prompt_toolkit.layout.controls.BufferControl`.
- """
- @abstractmethod
+ :class:`~prompt_toolkit.layout.controls.BufferControl`.
+ """
+ @abstractmethod
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
- """
- Apply transformation. Returns a :class:`.Transformation` instance.
+ """
+ Apply transformation. Returns a :class:`.Transformation` instance.
:param cli: :class:`.CommandLineInterface` instance.
:param lineno: The number of the line to which we apply the processor.
@@ -58,114 +58,114 @@ class Processor(with_metaclass(ABCMeta, object)):
previous processors into account.)
:param tokens: List of tokens that we can transform. (Received from the
previous processor.)
- """
+ """
return Transformation(tokens)
-
- def has_focus(self, cli):
- """
- Processors can override the focus.
- (Used for the reverse-i-search prefix in DefaultPrompt.)
- """
- return False
-
-
-class Transformation(object):
- """
- Transformation result, as returned by :meth:`.Processor.apply_transformation`.
-
- Important: Always make sure that the length of `document.text` is equal to
- the length of all the text in `tokens`!
-
- :param tokens: The transformed tokens. To be displayed, or to pass to the
- next processor.
- :param source_to_display: Cursor position transformation from original string to
- transformed string.
- :param display_to_source: Cursor position transformed from source string to
- original string.
- """
+
+ def has_focus(self, cli):
+ """
+ Processors can override the focus.
+ (Used for the reverse-i-search prefix in DefaultPrompt.)
+ """
+ return False
+
+
+class Transformation(object):
+ """
+ Transformation result, as returned by :meth:`.Processor.apply_transformation`.
+
+ Important: Always make sure that the length of `document.text` is equal to
+ the length of all the text in `tokens`!
+
+ :param tokens: The transformed tokens. To be displayed, or to pass to the
+ next processor.
+ :param source_to_display: Cursor position transformation from original string to
+ transformed string.
+ :param display_to_source: Cursor position transformed from source string to
+ original string.
+ """
def __init__(self, tokens, source_to_display=None, display_to_source=None):
- self.tokens = tokens
- self.source_to_display = source_to_display or (lambda i: i)
- self.display_to_source = display_to_source or (lambda i: i)
-
-
+ self.tokens = tokens
+ self.source_to_display = source_to_display or (lambda i: i)
+ self.display_to_source = display_to_source or (lambda i: i)
+
+
class HighlightSearchProcessor(Processor):
- """
- Processor that highlights search matches in the document.
+ """
+ Processor that highlights search matches in the document.
Note that this doesn't support multiline search matches yet.
-
- :param preview_search: A Filter; when active it indicates that we take
- the search text in real time while the user is typing, instead of the
- last active search state.
- """
+
+ :param preview_search: A Filter; when active it indicates that we take
+ the search text in real time while the user is typing, instead of the
+ last active search state.
+ """
def __init__(self, preview_search=False, search_buffer_name=SEARCH_BUFFER,
get_search_state=None):
- self.preview_search = to_cli_filter(preview_search)
- self.search_buffer_name = search_buffer_name
+ self.preview_search = to_cli_filter(preview_search)
+ self.search_buffer_name = search_buffer_name
self.get_search_state = get_search_state or (lambda cli: cli.search_state)
-
- def _get_search_text(self, cli):
- """
- The text we are searching for.
- """
- # When the search buffer has focus, take that text.
- if self.preview_search(cli) and cli.buffers[self.search_buffer_name].text:
- return cli.buffers[self.search_buffer_name].text
- # Otherwise, take the text of the last active search.
- else:
+
+ def _get_search_text(self, cli):
+ """
+ The text we are searching for.
+ """
+ # When the search buffer has focus, take that text.
+ if self.preview_search(cli) and cli.buffers[self.search_buffer_name].text:
+ return cli.buffers[self.search_buffer_name].text
+ # Otherwise, take the text of the last active search.
+ else:
return self.get_search_state(cli).text
-
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
- search_text = self._get_search_text(cli)
+ search_text = self._get_search_text(cli)
searchmatch_current_token = (':', ) + Token.SearchMatch.Current
searchmatch_token = (':', ) + Token.SearchMatch
-
- if search_text and not cli.is_returning:
- # For each search match, replace the Token.
+
+ if search_text and not cli.is_returning:
+ # For each search match, replace the Token.
line_text = token_list_to_text(tokens)
tokens = explode_tokens(tokens)
-
+
flags = re.IGNORECASE if cli.is_ignoring_case else 0
-
+
# Get cursor column.
if document.cursor_position_row == lineno:
cursor_column = source_to_display(document.cursor_position_col)
else:
cursor_column = None
-
+
for match in re.finditer(re.escape(search_text), line_text, flags=flags):
if cursor_column is not None:
on_cursor = match.start() <= cursor_column < match.end()
else:
on_cursor = False
-
+
for i in range(match.start(), match.end()):
old_token, text = tokens[i]
if on_cursor:
tokens[i] = (old_token + searchmatch_current_token, tokens[i][1])
else:
tokens[i] = (old_token + searchmatch_token, tokens[i][1])
-
+
return Transformation(tokens)
-
-
+
+
class HighlightSelectionProcessor(Processor):
- """
- Processor that highlights the selection in the document.
- """
+ """
+ Processor that highlights the selection in the document.
+ """
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
selected_token = (':', ) + Token.SelectedText
- # In case of selection, highlight all matches.
+ # In case of selection, highlight all matches.
selection_at_line = document.selection_range_at_line(lineno)
-
+
if selection_at_line:
from_, to = selection_at_line
from_ = source_to_display(from_)
to = source_to_display(to)
-
+
tokens = explode_tokens(tokens)
-
+
if from_ == 0 and to == 0 and len(tokens) == 0:
# When this is an empty line, insert a space in order to
# visualiase the selection.
@@ -175,43 +175,43 @@ class HighlightSelectionProcessor(Processor):
if i < len(tokens):
old_token, old_text = tokens[i]
tokens[i] = (old_token + selected_token, old_text)
-
+
return Transformation(tokens)
-
-
-class PasswordProcessor(Processor):
- """
- Processor that turns masks the input. (For passwords.)
-
- :param char: (string) Character to be used. "*" by default.
- """
- def __init__(self, char='*'):
- self.char = char
-
+
+
+class PasswordProcessor(Processor):
+ """
+ Processor that turns masks the input. (For passwords.)
+
+ :param char: (string) Character to be used. "*" by default.
+ """
+ def __init__(self, char='*'):
+ self.char = char
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
tokens = [(token, self.char * len(text)) for token, text in tokens]
return Transformation(tokens)
-
-
+
+
class HighlightMatchingBracketProcessor(Processor):
- """
- When the cursor is on or right after a bracket, it highlights the matching
- bracket.
+ """
+ When the cursor is on or right after a bracket, it highlights the matching
+ bracket.
:param max_cursor_distance: Only highlight matching brackets when the
cursor is within this distance. (From inside a `Processor`, we can't
know which lines will be visible on the screen. But we also don't want
to scan the whole document for matching brackets on each key press, so
we limit to this value.)
- """
- _closing_braces = '])}>'
-
+ """
+ _closing_braces = '])}>'
+
def __init__(self, chars='[](){}<>', max_cursor_distance=1000):
- self.chars = chars
+ self.chars = chars
self.max_cursor_distance = max_cursor_distance
-
+
self._positions_cache = SimpleCache(maxsize=8)
-
+
def _get_positions_to_highlight(self, document):
"""
Return a list of (row, col) tuples that need to be highlighted.
@@ -221,18 +221,18 @@ class HighlightMatchingBracketProcessor(Processor):
pos = document.find_matching_bracket_position(
start_pos=document.cursor_position - self.max_cursor_distance,
end_pos=document.cursor_position + self.max_cursor_distance)
-
+
# Try for the character before the cursor.
elif (document.char_before_cursor and document.char_before_cursor in
self._closing_braces and document.char_before_cursor in self.chars):
document = Document(document.text, document.cursor_position - 1)
-
+
pos = document.find_matching_bracket_position(
start_pos=document.cursor_position - self.max_cursor_distance,
end_pos=document.cursor_position + self.max_cursor_distance)
else:
pos = None
-
+
# Return a list of (row, col) tuples that need to be highlighted.
if pos:
pos += document.cursor_position # pos is relative.
@@ -240,13 +240,13 @@ class HighlightMatchingBracketProcessor(Processor):
return [(row, col), (document.cursor_position_row, document.cursor_position_col)]
else:
return []
-
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
# Get the highlight positions.
key = (cli.render_counter, document.text, document.cursor_position)
positions = self._positions_cache.get(
key, lambda: self._get_positions_to_highlight(document))
-
+
# Apply if positions were found at this line.
if positions:
for row, col in positions:
@@ -254,172 +254,172 @@ class HighlightMatchingBracketProcessor(Processor):
col = source_to_display(col)
tokens = explode_tokens(tokens)
token, text = tokens[col]
-
+
if col == document.cursor_position_col:
token += (':', ) + Token.MatchingBracket.Cursor
else:
token += (':', ) + Token.MatchingBracket.Other
-
+
tokens[col] = (token, text)
-
+
return Transformation(tokens)
class DisplayMultipleCursors(Processor):
- """
+ """
When we're in Vi block insert mode, display all the cursors.
- """
+ """
_insert_multiple = ViInsertMultipleMode()
-
+
def __init__(self, buffer_name):
self.buffer_name = buffer_name
-
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
buff = cli.buffers[self.buffer_name]
-
+
if self._insert_multiple(cli):
positions = buff.multiple_cursor_positions
tokens = explode_tokens(tokens)
-
+
# If any cursor appears on the current line, highlight that.
start_pos = document.translate_row_col_to_index(lineno, 0)
end_pos = start_pos + len(document.lines[lineno])
-
+
token_suffix = (':', ) + Token.MultipleCursors.Cursor
-
+
for p in positions:
if start_pos <= p < end_pos:
column = source_to_display(p - start_pos)
-
+
# Replace token.
token, text = tokens[column]
token += token_suffix
tokens[column] = (token, text)
elif p == end_pos:
tokens.append((token_suffix, ' '))
-
+
return Transformation(tokens)
else:
return Transformation(tokens)
-class BeforeInput(Processor):
- """
- Insert tokens before the input.
-
- :param get_tokens: Callable that takes a
- :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the
- list of tokens to be inserted.
- """
- def __init__(self, get_tokens):
- assert callable(get_tokens)
- self.get_tokens = get_tokens
-
+class BeforeInput(Processor):
+ """
+ Insert tokens before the input.
+
+ :param get_tokens: Callable that takes a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the
+ list of tokens to be inserted.
+ """
+ def __init__(self, get_tokens):
+ assert callable(get_tokens)
+ self.get_tokens = get_tokens
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
if lineno == 0:
tokens_before = self.get_tokens(cli)
tokens = tokens_before + tokens
-
+
shift_position = token_list_len(tokens_before)
source_to_display = lambda i: i + shift_position
display_to_source = lambda i: i - shift_position
else:
source_to_display = None
display_to_source = None
-
+
return Transformation(tokens, source_to_display=source_to_display,
display_to_source=display_to_source)
- @classmethod
- def static(cls, text, token=Token):
- """
- Create a :class:`.BeforeInput` instance that always inserts the same
- text.
- """
- def get_static_tokens(cli):
- return [(token, text)]
- return cls(get_static_tokens)
-
- def __repr__(self):
- return '%s(get_tokens=%r)' % (
- self.__class__.__name__, self.get_tokens)
-
-
-class AfterInput(Processor):
- """
- Insert tokens after the input.
-
- :param get_tokens: Callable that takes a
- :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the
- list of tokens to be appended.
- """
- def __init__(self, get_tokens):
- assert callable(get_tokens)
- self.get_tokens = get_tokens
-
+ @classmethod
+ def static(cls, text, token=Token):
+ """
+ Create a :class:`.BeforeInput` instance that always inserts the same
+ text.
+ """
+ def get_static_tokens(cli):
+ return [(token, text)]
+ return cls(get_static_tokens)
+
+ def __repr__(self):
+ return '%s(get_tokens=%r)' % (
+ self.__class__.__name__, self.get_tokens)
+
+
+class AfterInput(Processor):
+ """
+ Insert tokens after the input.
+
+ :param get_tokens: Callable that takes a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` and returns the
+ list of tokens to be appended.
+ """
+ def __init__(self, get_tokens):
+ assert callable(get_tokens)
+ self.get_tokens = get_tokens
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
# Insert tokens after the last line.
if lineno == document.line_count - 1:
return Transformation(tokens=tokens + self.get_tokens(cli))
else:
return Transformation(tokens=tokens)
-
- @classmethod
- def static(cls, text, token=Token):
- """
- Create a :class:`.AfterInput` instance that always inserts the same
- text.
- """
- def get_static_tokens(cli):
- return [(token, text)]
- return cls(get_static_tokens)
-
- def __repr__(self):
- return '%s(get_tokens=%r)' % (
- self.__class__.__name__, self.get_tokens)
-
-
-class AppendAutoSuggestion(Processor):
- """
- Append the auto suggestion to the input.
- (The user can then press the right arrow the insert the suggestion.)
-
- :param buffer_name: The name of the buffer from where we should take the
- auto suggestion. If not given, we take the current buffer.
- """
- def __init__(self, buffer_name=None, token=Token.AutoSuggestion):
- self.buffer_name = buffer_name
- self.token = token
-
- def _get_buffer(self, cli):
- if self.buffer_name:
- return cli.buffers[self.buffer_name]
- else:
- return cli.current_buffer
-
+
+ @classmethod
+ def static(cls, text, token=Token):
+ """
+ Create a :class:`.AfterInput` instance that always inserts the same
+ text.
+ """
+ def get_static_tokens(cli):
+ return [(token, text)]
+ return cls(get_static_tokens)
+
+ def __repr__(self):
+ return '%s(get_tokens=%r)' % (
+ self.__class__.__name__, self.get_tokens)
+
+
+class AppendAutoSuggestion(Processor):
+ """
+ Append the auto suggestion to the input.
+ (The user can then press the right arrow the insert the suggestion.)
+
+ :param buffer_name: The name of the buffer from where we should take the
+ auto suggestion. If not given, we take the current buffer.
+ """
+ def __init__(self, buffer_name=None, token=Token.AutoSuggestion):
+ self.buffer_name = buffer_name
+ self.token = token
+
+ def _get_buffer(self, cli):
+ if self.buffer_name:
+ return cli.buffers[self.buffer_name]
+ else:
+ return cli.current_buffer
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
# Insert tokens after the last line.
if lineno == document.line_count - 1:
buffer = self._get_buffer(cli)
-
+
if buffer.suggestion and buffer.document.is_cursor_at_the_end:
suggestion = buffer.suggestion.text
else:
suggestion = ''
return Transformation(tokens=tokens + [(self.token, suggestion)])
- else:
+ else:
return Transformation(tokens=tokens)
-
-
-class ShowLeadingWhiteSpaceProcessor(Processor):
- """
- Make leading whitespace visible.
+
+
+class ShowLeadingWhiteSpaceProcessor(Processor):
+ """
+ Make leading whitespace visible.
:param get_char: Callable that takes a :class:`CommandLineInterface`
instance and returns one character.
:param token: Token to be used.
- """
+ """
def __init__(self, get_char=None, token=Token.LeadingWhiteSpace):
assert get_char is None or callable(get_char)
@@ -430,32 +430,32 @@ class ShowLeadingWhiteSpaceProcessor(Processor):
else:
return '\xb7'
- self.token = token
+ self.token = token
self.get_char = get_char
-
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
- # Walk through all te tokens.
+ # Walk through all te tokens.
if tokens and token_list_to_text(tokens).startswith(' '):
t = (self.token, self.get_char(cli))
tokens = explode_tokens(tokens)
-
+
for i in range(len(tokens)):
if tokens[i][1] == ' ':
tokens[i] = t
else:
break
-
+
return Transformation(tokens)
-
-
-class ShowTrailingWhiteSpaceProcessor(Processor):
- """
- Make trailing whitespace visible.
+
+
+class ShowTrailingWhiteSpaceProcessor(Processor):
+ """
+ Make trailing whitespace visible.
:param get_char: Callable that takes a :class:`CommandLineInterface`
instance and returns one character.
:param token: Token to be used.
- """
+ """
def __init__(self, get_char=None, token=Token.TrailingWhiteSpace):
assert get_char is None or callable(get_char)
@@ -466,10 +466,10 @@ class ShowTrailingWhiteSpaceProcessor(Processor):
else:
return '\xb7'
- self.token = token
+ self.token = token
self.get_char = get_char
-
-
+
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
if tokens and tokens[-1][1].endswith(' '):
t = (self.token, self.get_char(cli))
@@ -535,16 +535,16 @@ class TabsProcessor(Processor):
result_tokens.append((token, separator1))
result_tokens.append((token, separator2 * (count - 1)))
pos += count
- else:
+ else:
result_tokens.append(token_and_text)
pos += 1
-
+
position_mappings[len(tokens)] = pos
-
+
def source_to_display(from_position):
" Maps original cursor position to the new one. "
return position_mappings[from_position]
-
+
def display_to_source(display_pos):
" Maps display cursor position to the original one. "
position_mappings_reversed = dict((v, k) for k, v in position_mappings.items())
@@ -562,44 +562,44 @@ class TabsProcessor(Processor):
display_to_source=display_to_source)
-class ConditionalProcessor(Processor):
- """
- Processor that applies another processor, according to a certain condition.
- Example::
-
- # Create a function that returns whether or not the processor should
- # currently be applied.
- def highlight_enabled(cli):
- return true_or_false
-
- # Wrapt it in a `ConditionalProcessor` for usage in a `BufferControl`.
- BufferControl(input_processors=[
- ConditionalProcessor(HighlightSearchProcessor(),
- Condition(highlight_enabled))])
-
- :param processor: :class:`.Processor` instance.
- :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance.
- """
- def __init__(self, processor, filter):
- assert isinstance(processor, Processor)
-
- self.processor = processor
- self.filter = to_cli_filter(filter)
-
+class ConditionalProcessor(Processor):
+ """
+ Processor that applies another processor, according to a certain condition.
+ Example::
+
+ # Create a function that returns whether or not the processor should
+ # currently be applied.
+ def highlight_enabled(cli):
+ return true_or_false
+
+ # Wrapt it in a `ConditionalProcessor` for usage in a `BufferControl`.
+ BufferControl(input_processors=[
+ ConditionalProcessor(HighlightSearchProcessor(),
+ Condition(highlight_enabled))])
+
+ :param processor: :class:`.Processor` instance.
+ :param filter: :class:`~prompt_toolkit.filters.CLIFilter` instance.
+ """
+ def __init__(self, processor, filter):
+ assert isinstance(processor, Processor)
+
+ self.processor = processor
+ self.filter = to_cli_filter(filter)
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
- # Run processor when enabled.
- if self.filter(cli):
+ # Run processor when enabled.
+ if self.filter(cli):
return self.processor.apply_transformation(
cli, document, lineno, source_to_display, tokens)
- else:
+ else:
return Transformation(tokens)
-
- def has_focus(self, cli):
- if self.filter(cli):
- return self.processor.has_focus(cli)
- else:
- return False
-
- def __repr__(self):
- return '%s(processor=%r, filter=%r)' % (
- self.__class__.__name__, self.processor, self.filter)
+
+ def has_focus(self, cli):
+ if self.filter(cli):
+ return self.processor.has_focus(cli)
+ else:
+ return False
+
+ def __repr__(self):
+ return '%s(processor=%r, filter=%r)' % (
+ self.__class__.__name__, self.processor, self.filter)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py
index d6c6a3c838d..7d00ec513e8 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/prompt.py
@@ -1,111 +1,111 @@
-from __future__ import unicode_literals
-
-from six import text_type
-
-from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER
+from __future__ import unicode_literals
+
+from six import text_type
+
+from prompt_toolkit.enums import IncrementalSearchDirection, SEARCH_BUFFER
from prompt_toolkit.token import Token
-
-from .utils import token_list_len
-from .processors import Processor, Transformation
-
-__all__ = (
- 'DefaultPrompt',
-)
-
-
-class DefaultPrompt(Processor):
- """
- Default prompt. This one shows the 'arg' and reverse search like
- Bash/readline normally do.
-
- There are two ways to instantiate a ``DefaultPrompt``. For a prompt
- with a static message, do for instance::
-
- prompt = DefaultPrompt.from_message('prompt> ')
-
- For a dynamic prompt, generated from a token list function::
-
- def get_tokens(cli):
- return [(Token.A, 'text'), (Token.B, 'text2')]
-
- prompt = DefaultPrompt(get_tokens)
- """
- def __init__(self, get_tokens):
- assert callable(get_tokens)
- self.get_tokens = get_tokens
-
- @classmethod
- def from_message(cls, message='> '):
- """
- Create a default prompt with a static message text.
- """
- assert isinstance(message, text_type)
-
- def get_message_tokens(cli):
- return [(Token.Prompt, message)]
- return cls(get_message_tokens)
-
+
+from .utils import token_list_len
+from .processors import Processor, Transformation
+
+__all__ = (
+ 'DefaultPrompt',
+)
+
+
+class DefaultPrompt(Processor):
+ """
+ Default prompt. This one shows the 'arg' and reverse search like
+ Bash/readline normally do.
+
+ There are two ways to instantiate a ``DefaultPrompt``. For a prompt
+ with a static message, do for instance::
+
+ prompt = DefaultPrompt.from_message('prompt> ')
+
+ For a dynamic prompt, generated from a token list function::
+
+ def get_tokens(cli):
+ return [(Token.A, 'text'), (Token.B, 'text2')]
+
+ prompt = DefaultPrompt(get_tokens)
+ """
+ def __init__(self, get_tokens):
+ assert callable(get_tokens)
+ self.get_tokens = get_tokens
+
+ @classmethod
+ def from_message(cls, message='> '):
+ """
+ Create a default prompt with a static message text.
+ """
+ assert isinstance(message, text_type)
+
+ def get_message_tokens(cli):
+ return [(Token.Prompt, message)]
+ return cls(get_message_tokens)
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
- # Get text before cursor.
- if cli.is_searching:
- before = _get_isearch_tokens(cli)
-
- elif cli.input_processor.arg is not None:
- before = _get_arg_tokens(cli)
-
- else:
- before = self.get_tokens(cli)
-
- # Insert before buffer text.
- shift_position = token_list_len(before)
-
+ # Get text before cursor.
+ if cli.is_searching:
+ before = _get_isearch_tokens(cli)
+
+ elif cli.input_processor.arg is not None:
+ before = _get_arg_tokens(cli)
+
+ else:
+ before = self.get_tokens(cli)
+
+ # Insert before buffer text.
+ shift_position = token_list_len(before)
+
# Only show the prompt before the first line. For the following lines,
# only indent using spaces.
if lineno != 0:
before = [(Token.Prompt, ' ' * shift_position)]
- return Transformation(
- tokens=before + tokens,
- source_to_display=lambda i: i + shift_position,
- display_to_source=lambda i: i - shift_position)
-
- def has_focus(self, cli):
- # Obtain focus when the CLI is searching.
-
- # Usually, when using this `DefaultPrompt`, we don't have a
- # `BufferControl` instance that displays the content of the search
- # buffer. Instead the search text is displayed before the current text.
- # So, we can still show the cursor here, while it's actually not this
- # buffer that's focussed.
- return cli.is_searching
-
-
-def _get_isearch_tokens(cli):
- def before():
- if cli.search_state.direction == IncrementalSearchDirection.BACKWARD:
- text = 'reverse-i-search'
- else:
- text = 'i-search'
-
- return [(Token.Prompt.Search, '(%s)`' % text)]
-
- def text():
- return [(Token.Prompt.Search.Text, cli.buffers[SEARCH_BUFFER].text)]
-
- def after():
- return [(Token.Prompt.Search, '`: ')]
-
- return before() + text() + after()
-
-
-def _get_arg_tokens(cli):
- """
- Tokens for the arg-prompt.
- """
- arg = cli.input_processor.arg
-
- return [
- (Token.Prompt.Arg, '(arg: '),
- (Token.Prompt.Arg.Text, str(arg)),
- (Token.Prompt.Arg, ') '),
- ]
+ return Transformation(
+ tokens=before + tokens,
+ source_to_display=lambda i: i + shift_position,
+ display_to_source=lambda i: i - shift_position)
+
+ def has_focus(self, cli):
+ # Obtain focus when the CLI is searching.
+
+ # Usually, when using this `DefaultPrompt`, we don't have a
+ # `BufferControl` instance that displays the content of the search
+ # buffer. Instead the search text is displayed before the current text.
+ # So, we can still show the cursor here, while it's actually not this
+ # buffer that's focussed.
+ return cli.is_searching
+
+
+def _get_isearch_tokens(cli):
+ def before():
+ if cli.search_state.direction == IncrementalSearchDirection.BACKWARD:
+ text = 'reverse-i-search'
+ else:
+ text = 'i-search'
+
+ return [(Token.Prompt.Search, '(%s)`' % text)]
+
+ def text():
+ return [(Token.Prompt.Search.Text, cli.buffers[SEARCH_BUFFER].text)]
+
+ def after():
+ return [(Token.Prompt.Search, '`: ')]
+
+ return before() + text() + after()
+
+
+def _get_arg_tokens(cli):
+ """
+ Tokens for the arg-prompt.
+ """
+ arg = cli.input_processor.arg
+
+ return [
+ (Token.Prompt.Arg, '(arg: '),
+ (Token.Prompt.Arg.Text, str(arg)),
+ (Token.Prompt.Arg, ') '),
+ ]
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py
index 8926f66d9b3..95561f5de76 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/screen.py
@@ -1,151 +1,151 @@
-from __future__ import unicode_literals
-
+from __future__ import unicode_literals
+
from prompt_toolkit.cache import FastDictCache
from prompt_toolkit.token import Token
-from prompt_toolkit.utils import get_cwidth
-
-from collections import defaultdict, namedtuple
-
-__all__ = (
- 'Point',
- 'Size',
- 'Screen',
- 'Char',
-)
-
-
-Point = namedtuple('Point', 'y x')
-Size = namedtuple('Size', 'rows columns')
-
-
-class Char(object):
- """
- Represent a single character in a :class:`.Screen`.
-
- This should be considered immutable.
- """
- __slots__ = ('char', 'token', 'width')
-
- # If we end up having one of these special control sequences in the input string,
- # we should display them as follows:
- # Usually this happens after a "quoted insert".
- display_mappings = {
- '\x00': '^@', # Control space
- '\x01': '^A',
- '\x02': '^B',
- '\x03': '^C',
- '\x04': '^D',
- '\x05': '^E',
- '\x06': '^F',
- '\x07': '^G',
- '\x08': '^H',
- '\x09': '^I',
- '\x0a': '^J',
- '\x0b': '^K',
- '\x0c': '^L',
- '\x0d': '^M',
- '\x0e': '^N',
- '\x0f': '^O',
- '\x10': '^P',
- '\x11': '^Q',
- '\x12': '^R',
- '\x13': '^S',
- '\x14': '^T',
- '\x15': '^U',
- '\x16': '^V',
- '\x17': '^W',
- '\x18': '^X',
- '\x19': '^Y',
- '\x1a': '^Z',
- '\x1b': '^[', # Escape
- '\x1c': '^\\',
- '\x1d': '^]',
- '\x1f': '^_',
+from prompt_toolkit.utils import get_cwidth
+
+from collections import defaultdict, namedtuple
+
+__all__ = (
+ 'Point',
+ 'Size',
+ 'Screen',
+ 'Char',
+)
+
+
+Point = namedtuple('Point', 'y x')
+Size = namedtuple('Size', 'rows columns')
+
+
+class Char(object):
+ """
+ Represent a single character in a :class:`.Screen`.
+
+ This should be considered immutable.
+ """
+ __slots__ = ('char', 'token', 'width')
+
+ # If we end up having one of these special control sequences in the input string,
+ # we should display them as follows:
+ # Usually this happens after a "quoted insert".
+ display_mappings = {
+ '\x00': '^@', # Control space
+ '\x01': '^A',
+ '\x02': '^B',
+ '\x03': '^C',
+ '\x04': '^D',
+ '\x05': '^E',
+ '\x06': '^F',
+ '\x07': '^G',
+ '\x08': '^H',
+ '\x09': '^I',
+ '\x0a': '^J',
+ '\x0b': '^K',
+ '\x0c': '^L',
+ '\x0d': '^M',
+ '\x0e': '^N',
+ '\x0f': '^O',
+ '\x10': '^P',
+ '\x11': '^Q',
+ '\x12': '^R',
+ '\x13': '^S',
+ '\x14': '^T',
+ '\x15': '^U',
+ '\x16': '^V',
+ '\x17': '^W',
+ '\x18': '^X',
+ '\x19': '^Y',
+ '\x1a': '^Z',
+ '\x1b': '^[', # Escape
+ '\x1c': '^\\',
+ '\x1d': '^]',
+ '\x1f': '^_',
'\x7f': '^?', # Backspace
- }
-
- def __init__(self, char=' ', token=Token):
- # If this character has to be displayed otherwise, take that one.
- char = self.display_mappings.get(char, char)
-
- self.char = char
- self.token = token
-
- # Calculate width. (We always need this, so better to store it directly
- # as a member for performance.)
- self.width = get_cwidth(char)
-
- def __eq__(self, other):
- return self.char == other.char and self.token == other.token
-
- def __ne__(self, other):
- # Not equal: We don't do `not char.__eq__` here, because of the
- # performance of calling yet another function.
- return self.char != other.char or self.token != other.token
-
- def __repr__(self):
- return '%s(%r, %r)' % (self.__class__.__name__, self.char, self.token)
-
-
+ }
+
+ def __init__(self, char=' ', token=Token):
+ # If this character has to be displayed otherwise, take that one.
+ char = self.display_mappings.get(char, char)
+
+ self.char = char
+ self.token = token
+
+ # Calculate width. (We always need this, so better to store it directly
+ # as a member for performance.)
+ self.width = get_cwidth(char)
+
+ def __eq__(self, other):
+ return self.char == other.char and self.token == other.token
+
+ def __ne__(self, other):
+ # Not equal: We don't do `not char.__eq__` here, because of the
+ # performance of calling yet another function.
+ return self.char != other.char or self.token != other.token
+
+ def __repr__(self):
+ return '%s(%r, %r)' % (self.__class__.__name__, self.char, self.token)
+
+
_CHAR_CACHE = FastDictCache(Char, size=1000 * 1000)
-Transparent = Token.Transparent
-
-
-class Screen(object):
- """
- Two dimentional buffer of :class:`.Char` instances.
- """
- def __init__(self, default_char=None, initial_width=0, initial_height=0):
- if default_char is None:
+Transparent = Token.Transparent
+
+
+class Screen(object):
+ """
+ Two dimentional buffer of :class:`.Char` instances.
+ """
+ def __init__(self, default_char=None, initial_width=0, initial_height=0):
+ if default_char is None:
default_char = _CHAR_CACHE[' ', Transparent]
-
- self.data_buffer = defaultdict(lambda: defaultdict(lambda: default_char))
-
+
+ self.data_buffer = defaultdict(lambda: defaultdict(lambda: default_char))
+
#: Escape sequences to be injected.
self.zero_width_escapes = defaultdict(lambda: defaultdict(lambda: ''))
- #: Position of the cursor.
- self.cursor_position = Point(y=0, x=0)
-
- #: Visibility of the cursor.
- self.show_cursor = True
-
- #: (Optional) Where to position the menu. E.g. at the start of a completion.
- #: (We can't use the cursor position, because we don't want the
- #: completion menu to change its position when we browse through all the
- #: completions.)
- self.menu_position = None
-
- #: Currently used width/height of the screen. This will increase when
- #: data is written to the screen.
- self.width = initial_width or 0
- self.height = initial_height or 0
-
- def replace_all_tokens(self, token):
- """
- For all the characters in the screen. Set the token to the given `token`.
- """
- b = self.data_buffer
-
- for y, row in b.items():
- for x, char in row.items():
- b[y][x] = _CHAR_CACHE[char.char, token]
-
-
-class WritePosition(object):
- def __init__(self, xpos, ypos, width, height, extended_height=None):
- assert height >= 0
- assert extended_height is None or extended_height >= 0
- assert width >= 0
- # xpos and ypos can be negative. (A float can be partially visible.)
-
- self.xpos = xpos
- self.ypos = ypos
- self.width = width
- self.height = height
- self.extended_height = extended_height or height
-
- def __repr__(self):
- return '%s(%r, %r, %r, %r, %r)' % (
- self.__class__.__name__,
- self.xpos, self.ypos, self.width, self.height, self.extended_height)
+ #: Position of the cursor.
+ self.cursor_position = Point(y=0, x=0)
+
+ #: Visibility of the cursor.
+ self.show_cursor = True
+
+ #: (Optional) Where to position the menu. E.g. at the start of a completion.
+ #: (We can't use the cursor position, because we don't want the
+ #: completion menu to change its position when we browse through all the
+ #: completions.)
+ self.menu_position = None
+
+ #: Currently used width/height of the screen. This will increase when
+ #: data is written to the screen.
+ self.width = initial_width or 0
+ self.height = initial_height or 0
+
+ def replace_all_tokens(self, token):
+ """
+ For all the characters in the screen. Set the token to the given `token`.
+ """
+ b = self.data_buffer
+
+ for y, row in b.items():
+ for x, char in row.items():
+ b[y][x] = _CHAR_CACHE[char.char, token]
+
+
+class WritePosition(object):
+ def __init__(self, xpos, ypos, width, height, extended_height=None):
+ assert height >= 0
+ assert extended_height is None or extended_height >= 0
+ assert width >= 0
+ # xpos and ypos can be negative. (A float can be partially visible.)
+
+ self.xpos = xpos
+ self.ypos = ypos
+ self.width = width
+ self.height = height
+ self.extended_height = extended_height or height
+
+ def __repr__(self):
+ return '%s(%r, %r, %r, %r, %r)' % (
+ self.__class__.__name__,
+ self.xpos, self.ypos, self.width, self.height, self.extended_height)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py
index aafa2e62458..2e77c2fa160 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/toolbars.py
@@ -1,209 +1,209 @@
-from __future__ import unicode_literals
-
-from ..enums import IncrementalSearchDirection
-
-from .processors import BeforeInput
-
+from __future__ import unicode_literals
+
+from ..enums import IncrementalSearchDirection
+
+from .processors import BeforeInput
+
from .lexers import SimpleLexer
-from .dimension import LayoutDimension
+from .dimension import LayoutDimension
from .controls import BufferControl, TokenListControl, UIControl, UIContent
-from .containers import Window, ConditionalContainer
+from .containers import Window, ConditionalContainer
from .screen import Char
-from .utils import token_list_len
+from .utils import token_list_len
from prompt_toolkit.enums import SEARCH_BUFFER, SYSTEM_BUFFER
-from prompt_toolkit.filters import HasFocus, HasArg, HasCompletions, HasValidationError, HasSearch, Always, IsDone
+from prompt_toolkit.filters import HasFocus, HasArg, HasCompletions, HasValidationError, HasSearch, Always, IsDone
from prompt_toolkit.token import Token
-
-__all__ = (
- 'TokenListToolbar',
- 'ArgToolbar',
- 'CompletionsToolbar',
- 'SearchToolbar',
- 'SystemToolbar',
- 'ValidationToolbar',
-)
-
-
-class TokenListToolbar(ConditionalContainer):
- def __init__(self, get_tokens, filter=Always(), **kw):
- super(TokenListToolbar, self).__init__(
- content=Window(
- TokenListControl(get_tokens, **kw),
- height=LayoutDimension.exact(1)),
- filter=filter)
-
-
-class SystemToolbarControl(BufferControl):
- def __init__(self):
+
+__all__ = (
+ 'TokenListToolbar',
+ 'ArgToolbar',
+ 'CompletionsToolbar',
+ 'SearchToolbar',
+ 'SystemToolbar',
+ 'ValidationToolbar',
+)
+
+
+class TokenListToolbar(ConditionalContainer):
+ def __init__(self, get_tokens, filter=Always(), **kw):
+ super(TokenListToolbar, self).__init__(
+ content=Window(
+ TokenListControl(get_tokens, **kw),
+ height=LayoutDimension.exact(1)),
+ filter=filter)
+
+
+class SystemToolbarControl(BufferControl):
+ def __init__(self):
token = Token.Toolbar.System
- super(SystemToolbarControl, self).__init__(
- buffer_name=SYSTEM_BUFFER,
+ super(SystemToolbarControl, self).__init__(
+ buffer_name=SYSTEM_BUFFER,
default_char=Char(token=token),
lexer=SimpleLexer(token=token.Text),
input_processors=[BeforeInput.static('Shell command: ', token)],)
-
-
-class SystemToolbar(ConditionalContainer):
- def __init__(self):
- super(SystemToolbar, self).__init__(
- content=Window(
- SystemToolbarControl(),
- height=LayoutDimension.exact(1)),
- filter=HasFocus(SYSTEM_BUFFER) & ~IsDone())
-
-
-class ArgToolbarControl(TokenListControl):
- def __init__(self):
- def get_tokens(cli):
+
+
+class SystemToolbar(ConditionalContainer):
+ def __init__(self):
+ super(SystemToolbar, self).__init__(
+ content=Window(
+ SystemToolbarControl(),
+ height=LayoutDimension.exact(1)),
+ filter=HasFocus(SYSTEM_BUFFER) & ~IsDone())
+
+
+class ArgToolbarControl(TokenListControl):
+ def __init__(self):
+ def get_tokens(cli):
arg = cli.input_processor.arg
if arg == '-':
arg = '-1'
- return [
- (Token.Toolbar.Arg, 'Repeat: '),
+ return [
+ (Token.Toolbar.Arg, 'Repeat: '),
(Token.Toolbar.Arg.Text, arg),
- ]
-
- super(ArgToolbarControl, self).__init__(get_tokens)
-
-
-class ArgToolbar(ConditionalContainer):
- def __init__(self):
- super(ArgToolbar, self).__init__(
- content=Window(
- ArgToolbarControl(),
- height=LayoutDimension.exact(1)),
- filter=HasArg())
-
-
-class SearchToolbarControl(BufferControl):
- """
- :param vi_mode: Display '/' and '?' instead of I-search.
- """
- def __init__(self, vi_mode=False):
- token = Token.Toolbar.Search
-
- def get_before_input(cli):
- if not cli.is_searching:
- text = ''
- elif cli.search_state.direction == IncrementalSearchDirection.BACKWARD:
- text = ('?' if vi_mode else 'I-search backward: ')
- else:
- text = ('/' if vi_mode else 'I-search: ')
-
- return [(token, text)]
-
- super(SearchToolbarControl, self).__init__(
- buffer_name=SEARCH_BUFFER,
- input_processors=[BeforeInput(get_before_input)],
+ ]
+
+ super(ArgToolbarControl, self).__init__(get_tokens)
+
+
+class ArgToolbar(ConditionalContainer):
+ def __init__(self):
+ super(ArgToolbar, self).__init__(
+ content=Window(
+ ArgToolbarControl(),
+ height=LayoutDimension.exact(1)),
+ filter=HasArg())
+
+
+class SearchToolbarControl(BufferControl):
+ """
+ :param vi_mode: Display '/' and '?' instead of I-search.
+ """
+ def __init__(self, vi_mode=False):
+ token = Token.Toolbar.Search
+
+ def get_before_input(cli):
+ if not cli.is_searching:
+ text = ''
+ elif cli.search_state.direction == IncrementalSearchDirection.BACKWARD:
+ text = ('?' if vi_mode else 'I-search backward: ')
+ else:
+ text = ('/' if vi_mode else 'I-search: ')
+
+ return [(token, text)]
+
+ super(SearchToolbarControl, self).__init__(
+ buffer_name=SEARCH_BUFFER,
+ input_processors=[BeforeInput(get_before_input)],
default_char=Char(token=token),
lexer=SimpleLexer(token=token.Text))
-
-
-class SearchToolbar(ConditionalContainer):
- def __init__(self, vi_mode=False):
- super(SearchToolbar, self).__init__(
- content=Window(
- SearchToolbarControl(vi_mode=vi_mode),
- height=LayoutDimension.exact(1)),
- filter=HasSearch() & ~IsDone())
-
-
-class CompletionsToolbarControl(UIControl):
- token = Token.Toolbar.Completions
-
+
+
+class SearchToolbar(ConditionalContainer):
+ def __init__(self, vi_mode=False):
+ super(SearchToolbar, self).__init__(
+ content=Window(
+ SearchToolbarControl(vi_mode=vi_mode),
+ height=LayoutDimension.exact(1)),
+ filter=HasSearch() & ~IsDone())
+
+
+class CompletionsToolbarControl(UIControl):
+ token = Token.Toolbar.Completions
+
def create_content(self, cli, width, height):
- complete_state = cli.current_buffer.complete_state
- if complete_state:
- completions = complete_state.current_completions
- index = complete_state.complete_index # Can be None!
-
- # Width of the completions without the left/right arrows in the margins.
- content_width = width - 6
-
- # Booleans indicating whether we stripped from the left/right
- cut_left = False
- cut_right = False
-
- # Create Menu content.
- tokens = []
-
- for i, c in enumerate(completions):
- # When there is no more place for the next completion
- if token_list_len(tokens) + len(c.display) >= content_width:
- # If the current one was not yet displayed, page to the next sequence.
- if i <= (index or 0):
- tokens = []
- cut_left = True
- # If the current one is visible, stop here.
- else:
- cut_right = True
- break
-
- tokens.append((self.token.Completion.Current if i == index else self.token.Completion, c.display))
- tokens.append((self.token, ' '))
-
- # Extend/strip until the content width.
- tokens.append((self.token, ' ' * (content_width - token_list_len(tokens))))
- tokens = tokens[:content_width]
-
- # Return tokens
- all_tokens = [
- (self.token, ' '),
- (self.token.Arrow, '<' if cut_left else ' '),
- (self.token, ' '),
- ] + tokens + [
- (self.token, ' '),
- (self.token.Arrow, '>' if cut_right else ' '),
- (self.token, ' '),
- ]
- else:
- all_tokens = []
-
+ complete_state = cli.current_buffer.complete_state
+ if complete_state:
+ completions = complete_state.current_completions
+ index = complete_state.complete_index # Can be None!
+
+ # Width of the completions without the left/right arrows in the margins.
+ content_width = width - 6
+
+ # Booleans indicating whether we stripped from the left/right
+ cut_left = False
+ cut_right = False
+
+ # Create Menu content.
+ tokens = []
+
+ for i, c in enumerate(completions):
+ # When there is no more place for the next completion
+ if token_list_len(tokens) + len(c.display) >= content_width:
+ # If the current one was not yet displayed, page to the next sequence.
+ if i <= (index or 0):
+ tokens = []
+ cut_left = True
+ # If the current one is visible, stop here.
+ else:
+ cut_right = True
+ break
+
+ tokens.append((self.token.Completion.Current if i == index else self.token.Completion, c.display))
+ tokens.append((self.token, ' '))
+
+ # Extend/strip until the content width.
+ tokens.append((self.token, ' ' * (content_width - token_list_len(tokens))))
+ tokens = tokens[:content_width]
+
+ # Return tokens
+ all_tokens = [
+ (self.token, ' '),
+ (self.token.Arrow, '<' if cut_left else ' '),
+ (self.token, ' '),
+ ] + tokens + [
+ (self.token, ' '),
+ (self.token.Arrow, '>' if cut_right else ' '),
+ (self.token, ' '),
+ ]
+ else:
+ all_tokens = []
+
def get_line(i):
return all_tokens
-
+
return UIContent(get_line=get_line, line_count=1)
-
-
-class CompletionsToolbar(ConditionalContainer):
- def __init__(self, extra_filter=Always()):
- super(CompletionsToolbar, self).__init__(
- content=Window(
- CompletionsToolbarControl(),
- height=LayoutDimension.exact(1)),
- filter=HasCompletions() & ~IsDone() & extra_filter)
-
-
-class ValidationToolbarControl(TokenListControl):
- def __init__(self, show_position=False):
- token = Token.Toolbar.Validation
-
- def get_tokens(cli):
- buffer = cli.current_buffer
-
- if buffer.validation_error:
- row, column = buffer.document.translate_index_to_position(
- buffer.validation_error.cursor_position)
-
- if show_position:
- text = '%s (line=%s column=%s)' % (
- buffer.validation_error.message, row + 1, column + 1)
- else:
- text = buffer.validation_error.message
-
- return [(token, text)]
- else:
- return []
-
- super(ValidationToolbarControl, self).__init__(get_tokens)
-
-
-class ValidationToolbar(ConditionalContainer):
- def __init__(self, show_position=False):
- super(ValidationToolbar, self).__init__(
- content=Window(
- ValidationToolbarControl(show_position=show_position),
- height=LayoutDimension.exact(1)),
- filter=HasValidationError() & ~IsDone())
+
+
+class CompletionsToolbar(ConditionalContainer):
+ def __init__(self, extra_filter=Always()):
+ super(CompletionsToolbar, self).__init__(
+ content=Window(
+ CompletionsToolbarControl(),
+ height=LayoutDimension.exact(1)),
+ filter=HasCompletions() & ~IsDone() & extra_filter)
+
+
+class ValidationToolbarControl(TokenListControl):
+ def __init__(self, show_position=False):
+ token = Token.Toolbar.Validation
+
+ def get_tokens(cli):
+ buffer = cli.current_buffer
+
+ if buffer.validation_error:
+ row, column = buffer.document.translate_index_to_position(
+ buffer.validation_error.cursor_position)
+
+ if show_position:
+ text = '%s (line=%s column=%s)' % (
+ buffer.validation_error.message, row + 1, column + 1)
+ else:
+ text = buffer.validation_error.message
+
+ return [(token, text)]
+ else:
+ return []
+
+ super(ValidationToolbarControl, self).__init__(get_tokens)
+
+
+class ValidationToolbar(ConditionalContainer):
+ def __init__(self, show_position=False):
+ super(ValidationToolbar, self).__init__(
+ content=Window(
+ ValidationToolbarControl(show_position=show_position),
+ height=LayoutDimension.exact(1)),
+ filter=HasValidationError() & ~IsDone())
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py
index 5fdfe4eb436..a4fb7ed0f5b 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/utils.py
@@ -1,112 +1,112 @@
-from __future__ import unicode_literals
-
-from prompt_toolkit.utils import get_cwidth
+from __future__ import unicode_literals
+
+from prompt_toolkit.utils import get_cwidth
from prompt_toolkit.token import Token
-
-__all__ = (
- 'token_list_len',
- 'token_list_width',
- 'token_list_to_text',
- 'explode_tokens',
+
+__all__ = (
+ 'token_list_len',
+ 'token_list_width',
+ 'token_list_to_text',
+ 'explode_tokens',
'split_lines',
- 'find_window_for_buffer_name',
-)
-
-
-def token_list_len(tokenlist):
- """
- Return the amount of characters in this token list.
-
- :param tokenlist: List of (token, text) or (token, text, mouse_handler)
- tuples.
- """
+ 'find_window_for_buffer_name',
+)
+
+
+def token_list_len(tokenlist):
+ """
+ Return the amount of characters in this token list.
+
+ :param tokenlist: List of (token, text) or (token, text, mouse_handler)
+ tuples.
+ """
ZeroWidthEscape = Token.ZeroWidthEscape
return sum(len(item[1]) for item in tokenlist if item[0] != ZeroWidthEscape)
-
-
-def token_list_width(tokenlist):
- """
- Return the character width of this token list.
- (Take double width characters into account.)
-
- :param tokenlist: List of (token, text) or (token, text, mouse_handler)
- tuples.
- """
+
+
+def token_list_width(tokenlist):
+ """
+ Return the character width of this token list.
+ (Take double width characters into account.)
+
+ :param tokenlist: List of (token, text) or (token, text, mouse_handler)
+ tuples.
+ """
ZeroWidthEscape = Token.ZeroWidthEscape
return sum(get_cwidth(c) for item in tokenlist for c in item[1] if item[0] != ZeroWidthEscape)
-
-
-def token_list_to_text(tokenlist):
- """
- Concatenate all the text parts again.
- """
+
+
+def token_list_to_text(tokenlist):
+ """
+ Concatenate all the text parts again.
+ """
ZeroWidthEscape = Token.ZeroWidthEscape
return ''.join(item[1] for item in tokenlist if item[0] != ZeroWidthEscape)
-
-
-def iter_token_lines(tokenlist):
- """
- Iterator that yields tokenlists for each line.
- """
- line = []
- for token, c in explode_tokens(tokenlist):
- line.append((token, c))
-
- if c == '\n':
- yield line
- line = []
-
- yield line
-
-
-def split_lines(tokenlist):
- """
- Take a single list of (Token, text) tuples and yield one such list for each
+
+
+def iter_token_lines(tokenlist):
+ """
+ Iterator that yields tokenlists for each line.
+ """
+ line = []
+ for token, c in explode_tokens(tokenlist):
+ line.append((token, c))
+
+ if c == '\n':
+ yield line
+ line = []
+
+ yield line
+
+
+def split_lines(tokenlist):
+ """
+ Take a single list of (Token, text) tuples and yield one such list for each
line. Just like str.split, this will yield at least one item.
-
- :param tokenlist: List of (token, text) or (token, text, mouse_handler)
- tuples.
- """
- line = []
-
- for item in tokenlist:
- # For (token, text) tuples.
- if len(item) == 2:
- token, string = item
- parts = string.split('\n')
-
- for part in parts[:-1]:
- if part:
- line.append((token, part))
- yield line
- line = []
-
- line.append((token, parts[-1]))
+
+ :param tokenlist: List of (token, text) or (token, text, mouse_handler)
+ tuples.
+ """
+ line = []
+
+ for item in tokenlist:
+ # For (token, text) tuples.
+ if len(item) == 2:
+ token, string = item
+ parts = string.split('\n')
+
+ for part in parts[:-1]:
+ if part:
+ line.append((token, part))
+ yield line
+ line = []
+
+ line.append((token, parts[-1]))
# Note that parts[-1] can be empty, and that's fine. It happens
# in the case of [(Token.SetCursorPosition, '')].
-
- # For (token, text, mouse_handler) tuples.
- # I know, partly copy/paste, but understandable and more efficient
- # than many tests.
- else:
- token, string, mouse_handler = item
- parts = string.split('\n')
-
- for part in parts[:-1]:
- if part:
- line.append((token, part, mouse_handler))
- yield line
- line = []
-
- line.append((token, parts[-1], mouse_handler))
-
+
+ # For (token, text, mouse_handler) tuples.
+ # I know, partly copy/paste, but understandable and more efficient
+ # than many tests.
+ else:
+ token, string, mouse_handler = item
+ parts = string.split('\n')
+
+ for part in parts[:-1]:
+ if part:
+ line.append((token, part, mouse_handler))
+ yield line
+ line = []
+
+ line.append((token, parts[-1], mouse_handler))
+
# Always yield the last line, even when this is an empty line. This ensures
# that when `tokenlist` ends with a newline character, an additional empty
# line is yielded. (Otherwise, there's no way to differentiate between the
# cases where `tokenlist` does and doesn't end with a newline.)
yield line
-
-
+
+
class _ExplodedList(list):
"""
Wrapper around a list, that marks it as 'exploded'.
@@ -140,42 +140,42 @@ class _ExplodedList(list):
super(_ExplodedList, self).__setitem__(index, value)
-def explode_tokens(tokenlist):
- """
- Turn a list of (token, text) tuples into another list where each string is
- exactly one character.
-
+def explode_tokens(tokenlist):
+ """
+ Turn a list of (token, text) tuples into another list where each string is
+ exactly one character.
+
It should be fine to call this function several times. Calling this on a
list that is already exploded, is a null operation.
- :param tokenlist: List of (token, text) tuples.
- """
+ :param tokenlist: List of (token, text) tuples.
+ """
# When the tokenlist is already exploded, don't explode again.
if getattr(tokenlist, 'exploded', False):
return tokenlist
- result = []
-
- for token, string in tokenlist:
- for c in string:
- result.append((token, c))
-
+ result = []
+
+ for token, string in tokenlist:
+ for c in string:
+ result.append((token, c))
+
return _ExplodedList(result)
-
-
-def find_window_for_buffer_name(cli, buffer_name):
- """
- Look for a :class:`~prompt_toolkit.layout.containers.Window` in the Layout
- that contains the :class:`~prompt_toolkit.layout.controls.BufferControl`
- for the given buffer and return it. If no such Window is found, return None.
- """
- from prompt_toolkit.interface import CommandLineInterface
- assert isinstance(cli, CommandLineInterface)
-
- from .containers import Window
- from .controls import BufferControl
-
- for l in cli.layout.walk(cli):
- if isinstance(l, Window) and isinstance(l.content, BufferControl):
- if l.content.buffer_name == buffer_name:
- return l
+
+
+def find_window_for_buffer_name(cli, buffer_name):
+ """
+ Look for a :class:`~prompt_toolkit.layout.containers.Window` in the Layout
+ that contains the :class:`~prompt_toolkit.layout.controls.BufferControl`
+ for the given buffer and return it. If no such Window is found, return None.
+ """
+ from prompt_toolkit.interface import CommandLineInterface
+ assert isinstance(cli, CommandLineInterface)
+
+ from .containers import Window
+ from .controls import BufferControl
+
+ for l in cli.layout.walk(cli):
+ if isinstance(l, Window) and isinstance(l.content, BufferControl):
+ if l.content.buffer_name == buffer_name:
+ return l
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py
index d827470be27..f42276ce9fb 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/mouse_events.py
@@ -1,48 +1,48 @@
-"""
-Mouse events.
-
-
-How it works
-------------
-
-The renderer has a 2 dimensional grid of mouse event handlers.
-(`prompt_toolkit.layout.MouseHandlers`.) When the layout is rendered, the
-`Window` class will make sure that this grid will also be filled with
-callbacks. For vt100 terminals, mouse events are received through stdin, just
-like any other key press. There is a handler among the key bindings that
-catches these events and forwards them to such a mouse event handler. It passes
-through the `Window` class where the coordinates are translated from absolute
-coordinates to coordinates relative to the user control, and there
-`UIControl.mouse_handler` is called.
-"""
-from __future__ import unicode_literals
-
-__all__ = (
+"""
+Mouse events.
+
+
+How it works
+------------
+
+The renderer has a 2 dimensional grid of mouse event handlers.
+(`prompt_toolkit.layout.MouseHandlers`.) When the layout is rendered, the
+`Window` class will make sure that this grid will also be filled with
+callbacks. For vt100 terminals, mouse events are received through stdin, just
+like any other key press. There is a handler among the key bindings that
+catches these events and forwards them to such a mouse event handler. It passes
+through the `Window` class where the coordinates are translated from absolute
+coordinates to coordinates relative to the user control, and there
+`UIControl.mouse_handler` is called.
+"""
+from __future__ import unicode_literals
+
+__all__ = (
'MouseEventType',
- 'MouseEvent'
-)
-
-
+ 'MouseEvent'
+)
+
+
class MouseEventType:
- MOUSE_UP = 'MOUSE_UP'
- MOUSE_DOWN = 'MOUSE_DOWN'
- SCROLL_UP = 'SCROLL_UP'
- SCROLL_DOWN = 'SCROLL_DOWN'
-
-
+ MOUSE_UP = 'MOUSE_UP'
+ MOUSE_DOWN = 'MOUSE_DOWN'
+ SCROLL_UP = 'SCROLL_UP'
+ SCROLL_DOWN = 'SCROLL_DOWN'
+
+
MouseEventTypes = MouseEventType # Deprecated: plural for backwards compatibility.
-class MouseEvent(object):
- """
- Mouse event, sent to `UIControl.mouse_handler`.
-
- :param position: `Point` instance.
- :param event_type: `MouseEventType`.
- """
- def __init__(self, position, event_type):
- self.position = position
- self.event_type = event_type
-
- def __repr__(self):
- return 'MouseEvent(%r, %r)' % (self.position, self.event_type)
+class MouseEvent(object):
+ """
+ Mouse event, sent to `UIControl.mouse_handler`.
+
+ :param position: `Point` instance.
+ :param event_type: `MouseEventType`.
+ """
+ def __init__(self, position, event_type):
+ self.position = position
+ self.event_type = event_type
+
+ def __repr__(self):
+ return 'MouseEvent(%r, %r)' % (self.position, self.event_type)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py
index 0b06acac470..072fb0677fd 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/output.py
@@ -1,26 +1,26 @@
-"""
-Interface for an output.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
+"""
+Interface for an output.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
from prompt_toolkit.layout.screen import Size
-
-__all__ = (
- 'Output',
-)
-
-
-class Output(with_metaclass(ABCMeta, object)):
- """
- Base class defining the output interface for a
- :class:`~prompt_toolkit.renderer.Renderer`.
-
- Actual implementations are
- :class:`~prompt_toolkit.terminal.vt100_output.Vt100_Output` and
- :class:`~prompt_toolkit.terminal.win32_output.Win32Output`.
- """
- @abstractmethod
+
+__all__ = (
+ 'Output',
+)
+
+
+class Output(with_metaclass(ABCMeta, object)):
+ """
+ Base class defining the output interface for a
+ :class:`~prompt_toolkit.renderer.Renderer`.
+
+ Actual implementations are
+ :class:`~prompt_toolkit.terminal.vt100_output.Vt100_Output` and
+ :class:`~prompt_toolkit.terminal.win32_output.Win32Output`.
+ """
+ @abstractmethod
def fileno(self):
" Return the file descriptor to which we can write for the output. "
@@ -34,119 +34,119 @@ class Output(with_metaclass(ABCMeta, object)):
"""
@abstractmethod
- def write(self, data):
- " Write text (Terminal escape sequences will be removed/escaped.) "
-
- @abstractmethod
- def write_raw(self, data):
- " Write text. "
-
- @abstractmethod
- def set_title(self, title):
- " Set terminal title. "
-
- @abstractmethod
- def clear_title(self):
- " Clear title again. (or restore previous title.) "
-
- @abstractmethod
- def flush(self):
- " Write to output stream and flush. "
-
- @abstractmethod
- def erase_screen(self):
- """
- Erases the screen with the background colour and moves the cursor to
- home.
- """
-
- @abstractmethod
- def enter_alternate_screen(self):
- " Go to the alternate screen buffer. (For full screen applications). "
-
- @abstractmethod
- def quit_alternate_screen(self):
- " Leave the alternate screen buffer. "
-
- @abstractmethod
- def enable_mouse_support(self):
- " Enable mouse. "
-
- @abstractmethod
- def disable_mouse_support(self):
- " Disable mouse. "
-
- @abstractmethod
- def erase_end_of_line(self):
- """
- Erases from the current cursor position to the end of the current line.
- """
-
- @abstractmethod
- def erase_down(self):
- """
- Erases the screen from the current line down to the bottom of the
- screen.
- """
-
- @abstractmethod
- def reset_attributes(self):
- " Reset color and styling attributes. "
-
- @abstractmethod
- def set_attributes(self, attrs):
- " Set new color and styling attributes. "
-
- @abstractmethod
- def disable_autowrap(self):
- " Disable auto line wrapping. "
-
- @abstractmethod
- def enable_autowrap(self):
- " Enable auto line wrapping. "
-
- @abstractmethod
- def cursor_goto(self, row=0, column=0):
- " Move cursor position. "
-
- @abstractmethod
- def cursor_up(self, amount):
- " Move cursor `amount` place up. "
-
- @abstractmethod
- def cursor_down(self, amount):
- " Move cursor `amount` place down. "
-
- @abstractmethod
- def cursor_forward(self, amount):
- " Move cursor `amount` place forward. "
-
- @abstractmethod
- def cursor_backward(self, amount):
- " Move cursor `amount` place backward. "
-
- @abstractmethod
- def hide_cursor(self):
- " Hide cursor. "
-
- @abstractmethod
- def show_cursor(self):
- " Show cursor. "
-
- def ask_for_cpr(self):
- """
- Asks for a cursor position report (CPR).
- (VT100 only.)
- """
-
- def bell(self):
- " Sound bell. "
-
- def enable_bracketed_paste(self):
- " For vt100 only. "
-
- def disable_bracketed_paste(self):
- " For vt100 only. "
+ def write(self, data):
+ " Write text (Terminal escape sequences will be removed/escaped.) "
+
+ @abstractmethod
+ def write_raw(self, data):
+ " Write text. "
+
+ @abstractmethod
+ def set_title(self, title):
+ " Set terminal title. "
+
+ @abstractmethod
+ def clear_title(self):
+ " Clear title again. (or restore previous title.) "
+
+ @abstractmethod
+ def flush(self):
+ " Write to output stream and flush. "
+
+ @abstractmethod
+ def erase_screen(self):
+ """
+ Erases the screen with the background colour and moves the cursor to
+ home.
+ """
+
+ @abstractmethod
+ def enter_alternate_screen(self):
+ " Go to the alternate screen buffer. (For full screen applications). "
+
+ @abstractmethod
+ def quit_alternate_screen(self):
+ " Leave the alternate screen buffer. "
+
+ @abstractmethod
+ def enable_mouse_support(self):
+ " Enable mouse. "
+
+ @abstractmethod
+ def disable_mouse_support(self):
+ " Disable mouse. "
+
+ @abstractmethod
+ def erase_end_of_line(self):
+ """
+ Erases from the current cursor position to the end of the current line.
+ """
+
+ @abstractmethod
+ def erase_down(self):
+ """
+ Erases the screen from the current line down to the bottom of the
+ screen.
+ """
+
+ @abstractmethod
+ def reset_attributes(self):
+ " Reset color and styling attributes. "
+
+ @abstractmethod
+ def set_attributes(self, attrs):
+ " Set new color and styling attributes. "
+
+ @abstractmethod
+ def disable_autowrap(self):
+ " Disable auto line wrapping. "
+
+ @abstractmethod
+ def enable_autowrap(self):
+ " Enable auto line wrapping. "
+
+ @abstractmethod
+ def cursor_goto(self, row=0, column=0):
+ " Move cursor position. "
+
+ @abstractmethod
+ def cursor_up(self, amount):
+ " Move cursor `amount` place up. "
+
+ @abstractmethod
+ def cursor_down(self, amount):
+ " Move cursor `amount` place down. "
+
+ @abstractmethod
+ def cursor_forward(self, amount):
+ " Move cursor `amount` place forward. "
+
+ @abstractmethod
+ def cursor_backward(self, amount):
+ " Move cursor `amount` place backward. "
+
+ @abstractmethod
+ def hide_cursor(self):
+ " Hide cursor. "
+
+ @abstractmethod
+ def show_cursor(self):
+ " Show cursor. "
+
+ def ask_for_cpr(self):
+ """
+ Asks for a cursor position report (CPR).
+ (VT100 only.)
+ """
+
+ def bell(self):
+ " Sound bell. "
+
+ def enable_bracketed_paste(self):
+ " For vt100 only. "
+
+ def disable_bracketed_paste(self):
+ " For vt100 only. "
class DummyOutput(Output):
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py
index 142b3e0b14b..ec3aa06712e 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/reactive.py
@@ -1,56 +1,56 @@
-"""
-Prompt_toolkit is designed a way that the amount of changing state is reduced
-to a minimum. Where possible, code is written in a pure functional way. In
-general, this results in code where the flow is very easy to follow: the value
-of a variable can be deducted from its first assignment.
-
-However, often, practicality and performance beat purity and some classes still
-have a changing state. In order to not having to care too much about
-transferring states between several components we use some reactive
-programming. Actually some kind of data binding.
-
-We introduce two types:
-
-- Filter: for binding a boolean state. They can be chained using & and |
- operators. Have a look in the ``filters`` module. Resolving the actual value
- of a filter happens by calling it.
-
-- Integer: for binding integer values. Reactive operations (like addition and
- substraction) are not suppported. Resolving the actual value happens by
- casting it to int, like ``int(integer)``. This way, it is possible to use
- normal integers as well for static values.
-"""
-from __future__ import unicode_literals
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-
-class Integer(with_metaclass(ABCMeta, object)):
- """
- Reactive integer -- anything that can be resolved to an ``int``.
- """
- @abstractmethod
- def __int__(self):
- return 0
-
- @classmethod
- def from_callable(cls, func):
- """
- Create an Integer-like object that calls the given function when it is
- resolved to an int.
- """
- return _IntegerFromCallable(func)
-
-
-Integer.register(int)
-
-
-class _IntegerFromCallable(Integer):
- def __init__(self, func=0):
- self.func = func
-
- def __repr__(self):
- return 'Integer.from_callable(%r)' % self.func
-
- def __int__(self):
- return int(self.func())
+"""
+Prompt_toolkit is designed a way that the amount of changing state is reduced
+to a minimum. Where possible, code is written in a pure functional way. In
+general, this results in code where the flow is very easy to follow: the value
+of a variable can be deducted from its first assignment.
+
+However, often, practicality and performance beat purity and some classes still
+have a changing state. In order to not having to care too much about
+transferring states between several components we use some reactive
+programming. Actually some kind of data binding.
+
+We introduce two types:
+
+- Filter: for binding a boolean state. They can be chained using & and |
+ operators. Have a look in the ``filters`` module. Resolving the actual value
+ of a filter happens by calling it.
+
+- Integer: for binding integer values. Reactive operations (like addition and
+ substraction) are not suppported. Resolving the actual value happens by
+ casting it to int, like ``int(integer)``. This way, it is possible to use
+ normal integers as well for static values.
+"""
+from __future__ import unicode_literals
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+
+class Integer(with_metaclass(ABCMeta, object)):
+ """
+ Reactive integer -- anything that can be resolved to an ``int``.
+ """
+ @abstractmethod
+ def __int__(self):
+ return 0
+
+ @classmethod
+ def from_callable(cls, func):
+ """
+ Create an Integer-like object that calls the given function when it is
+ resolved to an int.
+ """
+ return _IntegerFromCallable(func)
+
+
+Integer.register(int)
+
+
+class _IntegerFromCallable(Integer):
+ def __init__(self, func=0):
+ self.func = func
+
+ def __repr__(self):
+ return 'Integer.from_callable(%r)' % self.func
+
+ def __int__(self):
+ return int(self.func())
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py
index 5c8b2b18d14..7a8fde55b30 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/renderer.py
@@ -1,118 +1,118 @@
-"""
-Renders the command line on the console.
-(Redraws parts of the input line that were changed.)
-"""
-from __future__ import unicode_literals
-
+"""
+Renders the command line on the console.
+(Redraws parts of the input line that were changed.)
+"""
+from __future__ import unicode_literals
+
from prompt_toolkit.filters import to_cli_filter
from prompt_toolkit.layout.mouse_handlers import MouseHandlers
-from prompt_toolkit.layout.screen import Point, Screen, WritePosition
-from prompt_toolkit.output import Output
+from prompt_toolkit.layout.screen import Point, Screen, WritePosition
+from prompt_toolkit.output import Output
from prompt_toolkit.styles import Style
from prompt_toolkit.token import Token
-from prompt_toolkit.utils import is_windows
-
+from prompt_toolkit.utils import is_windows
+
from six.moves import range
-__all__ = (
- 'Renderer',
- 'print_tokens',
-)
-
-
+__all__ = (
+ 'Renderer',
+ 'print_tokens',
+)
+
+
def _output_screen_diff(output, screen, current_pos, previous_screen=None, last_token=None,
is_done=False, use_alternate_screen=False, attrs_for_token=None, size=None,
previous_width=0): # XXX: drop is_done
- """
- Render the diff between this screen and the previous screen.
-
- This takes two `Screen` instances. The one that represents the output like
- it was during the last rendering and one that represents the current
- output raster. Looking at these two `Screen` instances, this function will
- render the difference by calling the appropriate methods of the `Output`
- object that only paint the changes to the terminal.
-
- This is some performance-critical code which is heavily optimized.
- Don't change things without profiling first.
-
- :param current_pos: Current cursor position.
+ """
+ Render the diff between this screen and the previous screen.
+
+ This takes two `Screen` instances. The one that represents the output like
+ it was during the last rendering and one that represents the current
+ output raster. Looking at these two `Screen` instances, this function will
+ render the difference by calling the appropriate methods of the `Output`
+ object that only paint the changes to the terminal.
+
+ This is some performance-critical code which is heavily optimized.
+ Don't change things without profiling first.
+
+ :param current_pos: Current cursor position.
:param last_token: `Token` instance that represents the output attributes of
- the last drawn character. (Color/attributes.)
- :param attrs_for_token: :class:`._TokenToAttrsCache` instance.
- :param width: The width of the terminal.
- :param prevous_width: The width of the terminal during the last rendering.
- """
- width, height = size.columns, size.rows
-
- #: Remember the last printed character.
+ the last drawn character. (Color/attributes.)
+ :param attrs_for_token: :class:`._TokenToAttrsCache` instance.
+ :param width: The width of the terminal.
+ :param prevous_width: The width of the terminal during the last rendering.
+ """
+ width, height = size.columns, size.rows
+
+ #: Remember the last printed character.
last_token = [last_token] # nonlocal
-
- #: Variable for capturing the output.
- write = output.write
+
+ #: Variable for capturing the output.
+ write = output.write
write_raw = output.write_raw
-
- # Create locals for the most used output methods.
- # (Save expensive attribute lookups.)
- _output_set_attributes = output.set_attributes
- _output_reset_attributes = output.reset_attributes
- _output_cursor_forward = output.cursor_forward
- _output_cursor_up = output.cursor_up
- _output_cursor_backward = output.cursor_backward
-
- # Hide cursor before rendering. (Avoid flickering.)
- output.hide_cursor()
-
- def reset_attributes():
- " Wrapper around Output.reset_attributes. "
- _output_reset_attributes()
+
+ # Create locals for the most used output methods.
+ # (Save expensive attribute lookups.)
+ _output_set_attributes = output.set_attributes
+ _output_reset_attributes = output.reset_attributes
+ _output_cursor_forward = output.cursor_forward
+ _output_cursor_up = output.cursor_up
+ _output_cursor_backward = output.cursor_backward
+
+ # Hide cursor before rendering. (Avoid flickering.)
+ output.hide_cursor()
+
+ def reset_attributes():
+ " Wrapper around Output.reset_attributes. "
+ _output_reset_attributes()
last_token[0] = None # Forget last char after resetting attributes.
-
- def move_cursor(new):
- " Move cursor to this `new` point. Returns the given Point. "
- current_x, current_y = current_pos.x, current_pos.y
-
- if new.y > current_y:
- # Use newlines instead of CURSOR_DOWN, because this meight add new lines.
- # CURSOR_DOWN will never create new lines at the bottom.
- # Also reset attributes, otherwise the newline could draw a
- # background color.
- reset_attributes()
- write('\r\n' * (new.y - current_y))
- current_x = 0
- _output_cursor_forward(new.x)
- return new
- elif new.y < current_y:
- _output_cursor_up(current_y - new.y)
-
- if current_x >= width - 1:
- write('\r')
- _output_cursor_forward(new.x)
- elif new.x < current_x or current_x >= width - 1:
- _output_cursor_backward(current_x - new.x)
- elif new.x > current_x:
- _output_cursor_forward(new.x - current_x)
-
- return new
-
- def output_char(char):
- """
- Write the output of this character.
- """
- # If the last printed character has the same token, it also has the
- # same style, so we don't output it.
+
+ def move_cursor(new):
+ " Move cursor to this `new` point. Returns the given Point. "
+ current_x, current_y = current_pos.x, current_pos.y
+
+ if new.y > current_y:
+ # Use newlines instead of CURSOR_DOWN, because this meight add new lines.
+ # CURSOR_DOWN will never create new lines at the bottom.
+ # Also reset attributes, otherwise the newline could draw a
+ # background color.
+ reset_attributes()
+ write('\r\n' * (new.y - current_y))
+ current_x = 0
+ _output_cursor_forward(new.x)
+ return new
+ elif new.y < current_y:
+ _output_cursor_up(current_y - new.y)
+
+ if current_x >= width - 1:
+ write('\r')
+ _output_cursor_forward(new.x)
+ elif new.x < current_x or current_x >= width - 1:
+ _output_cursor_backward(current_x - new.x)
+ elif new.x > current_x:
+ _output_cursor_forward(new.x - current_x)
+
+ return new
+
+ def output_char(char):
+ """
+ Write the output of this character.
+ """
+ # If the last printed character has the same token, it also has the
+ # same style, so we don't output it.
the_last_token = last_token[0]
if the_last_token and the_last_token == char.token:
- write(char.char)
- else:
+ write(char.char)
+ else:
_output_set_attributes(attrs_for_token[char.token])
- write(char.char)
+ write(char.char)
last_token[0] = char.token
-
+
# Render for the first time: reset styling.
- if not previous_screen:
- reset_attributes()
-
+ if not previous_screen:
+ reset_attributes()
+
# Disable autowrap. (When entering a the alternate screen, or anytime when
# we have a prompt. - In the case of a REPL, like IPython, people can have
# background threads, and it's hard for debugging if their output is not
@@ -120,416 +120,416 @@ def _output_screen_diff(output, screen, current_pos, previous_screen=None, last_
if not previous_screen or not use_alternate_screen:
output.disable_autowrap()
- # When the previous screen has a different size, redraw everything anyway.
- # Also when we are done. (We meight take up less rows, so clearing is important.)
- if is_done or not previous_screen or previous_width != width: # XXX: also consider height??
- current_pos = move_cursor(Point(0, 0))
- reset_attributes()
- output.erase_down()
-
- previous_screen = Screen()
-
- # Get height of the screen.
- # (height changes as we loop over data_buffer, so remember the current value.)
- # (Also make sure to clip the height to the size of the output.)
- current_height = min(screen.height, height)
-
- # Loop over the rows.
- row_count = min(max(screen.height, previous_screen.height), height)
- c = 0 # Column counter.
-
+ # When the previous screen has a different size, redraw everything anyway.
+ # Also when we are done. (We meight take up less rows, so clearing is important.)
+ if is_done or not previous_screen or previous_width != width: # XXX: also consider height??
+ current_pos = move_cursor(Point(0, 0))
+ reset_attributes()
+ output.erase_down()
+
+ previous_screen = Screen()
+
+ # Get height of the screen.
+ # (height changes as we loop over data_buffer, so remember the current value.)
+ # (Also make sure to clip the height to the size of the output.)
+ current_height = min(screen.height, height)
+
+ # Loop over the rows.
+ row_count = min(max(screen.height, previous_screen.height), height)
+ c = 0 # Column counter.
+
for y in range(row_count):
new_row = screen.data_buffer[y]
previous_row = previous_screen.data_buffer[y]
zero_width_escapes_row = screen.zero_width_escapes[y]
-
- new_max_line_len = min(width - 1, max(new_row.keys()) if new_row else 0)
- previous_max_line_len = min(width - 1, max(previous_row.keys()) if previous_row else 0)
-
- # Loop over the columns.
- c = 0
- while c < new_max_line_len + 1:
- new_char = new_row[c]
- old_char = previous_row[c]
- char_width = (new_char.width or 1)
-
- # When the old and new character at this position are different,
- # draw the output. (Because of the performance, we don't call
- # `Char.__ne__`, but inline the same expression.)
- if new_char.char != old_char.char or new_char.token != old_char.token:
- current_pos = move_cursor(Point(y=y, x=c))
+
+ new_max_line_len = min(width - 1, max(new_row.keys()) if new_row else 0)
+ previous_max_line_len = min(width - 1, max(previous_row.keys()) if previous_row else 0)
+
+ # Loop over the columns.
+ c = 0
+ while c < new_max_line_len + 1:
+ new_char = new_row[c]
+ old_char = previous_row[c]
+ char_width = (new_char.width or 1)
+
+ # When the old and new character at this position are different,
+ # draw the output. (Because of the performance, we don't call
+ # `Char.__ne__`, but inline the same expression.)
+ if new_char.char != old_char.char or new_char.token != old_char.token:
+ current_pos = move_cursor(Point(y=y, x=c))
# Send injected escape sequences to output.
if c in zero_width_escapes_row:
write_raw(zero_width_escapes_row[c])
- output_char(new_char)
- current_pos = current_pos._replace(x=current_pos.x + char_width)
-
- c += char_width
-
- # If the new line is shorter, trim it.
- if previous_screen and new_max_line_len < previous_max_line_len:
- current_pos = move_cursor(Point(y=y, x=new_max_line_len+1))
- reset_attributes()
- output.erase_end_of_line()
-
- # Correctly reserve vertical space as required by the layout.
- # When this is a new screen (drawn for the first time), or for some reason
- # higher than the previous one. Move the cursor once to the bottom of the
- # output. That way, we're sure that the terminal scrolls up, even when the
- # lower lines of the canvas just contain whitespace.
-
- # The most obvious reason that we actually want this behaviour is the avoid
- # the artifact of the input scrolling when the completion menu is shown.
- # (If the scrolling is actually wanted, the layout can still be build in a
- # way to behave that way by setting a dynamic height.)
- if current_height > previous_screen.height:
- current_pos = move_cursor(Point(y=current_height - 1, x=0))
-
- # Move cursor:
- if is_done:
- current_pos = move_cursor(Point(y=current_height, x=0))
- output.erase_down()
- else:
- current_pos = move_cursor(screen.cursor_position)
-
+ output_char(new_char)
+ current_pos = current_pos._replace(x=current_pos.x + char_width)
+
+ c += char_width
+
+ # If the new line is shorter, trim it.
+ if previous_screen and new_max_line_len < previous_max_line_len:
+ current_pos = move_cursor(Point(y=y, x=new_max_line_len+1))
+ reset_attributes()
+ output.erase_end_of_line()
+
+ # Correctly reserve vertical space as required by the layout.
+ # When this is a new screen (drawn for the first time), or for some reason
+ # higher than the previous one. Move the cursor once to the bottom of the
+ # output. That way, we're sure that the terminal scrolls up, even when the
+ # lower lines of the canvas just contain whitespace.
+
+ # The most obvious reason that we actually want this behaviour is the avoid
+ # the artifact of the input scrolling when the completion menu is shown.
+ # (If the scrolling is actually wanted, the layout can still be build in a
+ # way to behave that way by setting a dynamic height.)
+ if current_height > previous_screen.height:
+ current_pos = move_cursor(Point(y=current_height - 1, x=0))
+
+ # Move cursor:
+ if is_done:
+ current_pos = move_cursor(Point(y=current_height, x=0))
+ output.erase_down()
+ else:
+ current_pos = move_cursor(screen.cursor_position)
+
if is_done or not use_alternate_screen:
- output.enable_autowrap()
-
+ output.enable_autowrap()
+
# Always reset the color attributes. This is important because a background
# thread could print data to stdout and we want that to be displayed in the
# default colors. (Also, if a background color has been set, many terminals
# give weird artifacs on resize events.)
reset_attributes()
-
- if screen.show_cursor or is_done:
- output.show_cursor()
-
+
+ if screen.show_cursor or is_done:
+ output.show_cursor()
+
return current_pos, last_token[0]
-
-
-class HeightIsUnknownError(Exception):
- " Information unavailable. Did not yet receive the CPR response. "
-
-
-class _TokenToAttrsCache(dict):
- """
- A cache structure that maps Pygments Tokens to :class:`.Attr`.
- (This is an important speed up.)
- """
- def __init__(self, get_style_for_token):
- self.get_style_for_token = get_style_for_token
-
- def __missing__(self, token):
- try:
- result = self.get_style_for_token(token)
- except KeyError:
- result = None
-
- self[token] = result
- return result
-
-
-class Renderer(object):
- """
- Typical usage:
-
- ::
-
- output = Vt100_Output.from_pty(sys.stdout)
- r = Renderer(style, output)
- r.render(cli, layout=...)
- """
- def __init__(self, style, output, use_alternate_screen=False, mouse_support=False):
- assert isinstance(style, Style)
- assert isinstance(output, Output)
-
- self.style = style
- self.output = output
- self.use_alternate_screen = use_alternate_screen
- self.mouse_support = to_cli_filter(mouse_support)
-
- self._in_alternate_screen = False
- self._mouse_support_enabled = False
- self._bracketed_paste_enabled = False
-
+
+
+class HeightIsUnknownError(Exception):
+ " Information unavailable. Did not yet receive the CPR response. "
+
+
+class _TokenToAttrsCache(dict):
+ """
+ A cache structure that maps Pygments Tokens to :class:`.Attr`.
+ (This is an important speed up.)
+ """
+ def __init__(self, get_style_for_token):
+ self.get_style_for_token = get_style_for_token
+
+ def __missing__(self, token):
+ try:
+ result = self.get_style_for_token(token)
+ except KeyError:
+ result = None
+
+ self[token] = result
+ return result
+
+
+class Renderer(object):
+ """
+ Typical usage:
+
+ ::
+
+ output = Vt100_Output.from_pty(sys.stdout)
+ r = Renderer(style, output)
+ r.render(cli, layout=...)
+ """
+ def __init__(self, style, output, use_alternate_screen=False, mouse_support=False):
+ assert isinstance(style, Style)
+ assert isinstance(output, Output)
+
+ self.style = style
+ self.output = output
+ self.use_alternate_screen = use_alternate_screen
+ self.mouse_support = to_cli_filter(mouse_support)
+
+ self._in_alternate_screen = False
+ self._mouse_support_enabled = False
+ self._bracketed_paste_enabled = False
+
# Waiting for CPR flag. True when we send the request, but didn't got a
# response.
self.waiting_for_cpr = False
- self.reset(_scroll=True)
-
+ self.reset(_scroll=True)
+
def reset(self, _scroll=False, leave_alternate_screen=True):
- # Reset position
- self._cursor_pos = Point(x=0, y=0)
-
- # Remember the last screen instance between renderers. This way,
- # we can create a `diff` between two screens and only output the
- # difference. It's also to remember the last height. (To show for
- # instance a toolbar at the bottom position.)
- self._last_screen = None
- self._last_size = None
+ # Reset position
+ self._cursor_pos = Point(x=0, y=0)
+
+ # Remember the last screen instance between renderers. This way,
+ # we can create a `diff` between two screens and only output the
+ # difference. It's also to remember the last height. (To show for
+ # instance a toolbar at the bottom position.)
+ self._last_screen = None
+ self._last_size = None
self._last_token = None
-
- # When the style hash changes, we have to do a full redraw as well as
- # clear the `_attrs_for_token` dictionary.
- self._last_style_hash = None
- self._attrs_for_token = None
-
- # Default MouseHandlers. (Just empty.)
- self.mouse_handlers = MouseHandlers()
-
- # Remember the last title. Only set the title when it changes.
- self._last_title = None
-
- #: Space from the top of the layout, until the bottom of the terminal.
- #: We don't know this until a `report_absolute_cursor_row` call.
- self._min_available_height = 0
-
- # In case of Windown, also make sure to scroll to the current cursor
- # position. (Only when rendering the first time.)
- if is_windows() and _scroll:
- self.output.scroll_buffer_to_prompt()
-
- # Quit alternate screen.
+
+ # When the style hash changes, we have to do a full redraw as well as
+ # clear the `_attrs_for_token` dictionary.
+ self._last_style_hash = None
+ self._attrs_for_token = None
+
+ # Default MouseHandlers. (Just empty.)
+ self.mouse_handlers = MouseHandlers()
+
+ # Remember the last title. Only set the title when it changes.
+ self._last_title = None
+
+ #: Space from the top of the layout, until the bottom of the terminal.
+ #: We don't know this until a `report_absolute_cursor_row` call.
+ self._min_available_height = 0
+
+ # In case of Windown, also make sure to scroll to the current cursor
+ # position. (Only when rendering the first time.)
+ if is_windows() and _scroll:
+ self.output.scroll_buffer_to_prompt()
+
+ # Quit alternate screen.
if self._in_alternate_screen and leave_alternate_screen:
- self.output.quit_alternate_screen()
- self._in_alternate_screen = False
-
- # Disable mouse support.
- if self._mouse_support_enabled:
- self.output.disable_mouse_support()
- self._mouse_support_enabled = False
-
- # Disable bracketed paste.
- if self._bracketed_paste_enabled:
- self.output.disable_bracketed_paste()
- self._bracketed_paste_enabled = False
-
- # Flush output. `disable_mouse_support` needs to write to stdout.
- self.output.flush()
-
- @property
- def height_is_known(self):
- """
- True when the height from the cursor until the bottom of the terminal
- is known. (It's often nicer to draw bottom toolbars only if the height
- is known, in order to avoid flickering when the CPR response arrives.)
- """
- return self.use_alternate_screen or self._min_available_height > 0 or \
- is_windows() # On Windows, we don't have to wait for a CPR.
-
- @property
- def rows_above_layout(self):
- """
- Return the number of rows visible in the terminal above the layout.
- """
- if self._in_alternate_screen:
- return 0
- elif self._min_available_height > 0:
- total_rows = self.output.get_size().rows
- last_screen_height = self._last_screen.height if self._last_screen else 0
- return total_rows - max(self._min_available_height, last_screen_height)
- else:
- raise HeightIsUnknownError('Rows above layout is unknown.')
-
- def request_absolute_cursor_position(self):
- """
- Get current cursor position.
- For vt100: Do CPR request. (answer will arrive later.)
- For win32: Do API call. (Answer comes immediately.)
- """
- # Only do this request when the cursor is at the top row. (after a
- # clear or reset). We will rely on that in `report_absolute_cursor_row`.
- assert self._cursor_pos.y == 0
-
- # For Win32, we have an API call to get the number of rows below the
- # cursor.
- if is_windows():
- self._min_available_height = self.output.get_rows_below_cursor_position()
- else:
- if self.use_alternate_screen:
- self._min_available_height = self.output.get_size().rows
- else:
- # Asks for a cursor position report (CPR).
+ self.output.quit_alternate_screen()
+ self._in_alternate_screen = False
+
+ # Disable mouse support.
+ if self._mouse_support_enabled:
+ self.output.disable_mouse_support()
+ self._mouse_support_enabled = False
+
+ # Disable bracketed paste.
+ if self._bracketed_paste_enabled:
+ self.output.disable_bracketed_paste()
+ self._bracketed_paste_enabled = False
+
+ # Flush output. `disable_mouse_support` needs to write to stdout.
+ self.output.flush()
+
+ @property
+ def height_is_known(self):
+ """
+ True when the height from the cursor until the bottom of the terminal
+ is known. (It's often nicer to draw bottom toolbars only if the height
+ is known, in order to avoid flickering when the CPR response arrives.)
+ """
+ return self.use_alternate_screen or self._min_available_height > 0 or \
+ is_windows() # On Windows, we don't have to wait for a CPR.
+
+ @property
+ def rows_above_layout(self):
+ """
+ Return the number of rows visible in the terminal above the layout.
+ """
+ if self._in_alternate_screen:
+ return 0
+ elif self._min_available_height > 0:
+ total_rows = self.output.get_size().rows
+ last_screen_height = self._last_screen.height if self._last_screen else 0
+ return total_rows - max(self._min_available_height, last_screen_height)
+ else:
+ raise HeightIsUnknownError('Rows above layout is unknown.')
+
+ def request_absolute_cursor_position(self):
+ """
+ Get current cursor position.
+ For vt100: Do CPR request. (answer will arrive later.)
+ For win32: Do API call. (Answer comes immediately.)
+ """
+ # Only do this request when the cursor is at the top row. (after a
+ # clear or reset). We will rely on that in `report_absolute_cursor_row`.
+ assert self._cursor_pos.y == 0
+
+ # For Win32, we have an API call to get the number of rows below the
+ # cursor.
+ if is_windows():
+ self._min_available_height = self.output.get_rows_below_cursor_position()
+ else:
+ if self.use_alternate_screen:
+ self._min_available_height = self.output.get_size().rows
+ else:
+ # Asks for a cursor position report (CPR).
self.waiting_for_cpr = True
- self.output.ask_for_cpr()
-
- def report_absolute_cursor_row(self, row):
- """
- To be called when we know the absolute cursor position.
- (As an answer of a "Cursor Position Request" response.)
- """
- # Calculate the amount of rows from the cursor position until the
- # bottom of the terminal.
- total_rows = self.output.get_size().rows
- rows_below_cursor = total_rows - row + 1
-
- # Set the
- self._min_available_height = rows_below_cursor
-
+ self.output.ask_for_cpr()
+
+ def report_absolute_cursor_row(self, row):
+ """
+ To be called when we know the absolute cursor position.
+ (As an answer of a "Cursor Position Request" response.)
+ """
+ # Calculate the amount of rows from the cursor position until the
+ # bottom of the terminal.
+ total_rows = self.output.get_size().rows
+ rows_below_cursor = total_rows - row + 1
+
+ # Set the
+ self._min_available_height = rows_below_cursor
+
self.waiting_for_cpr = False
- def render(self, cli, layout, is_done=False):
- """
- Render the current interface to the output.
-
- :param is_done: When True, put the cursor at the end of the interface. We
- won't print any changes to this part.
- """
- output = self.output
-
- # Enter alternate screen.
- if self.use_alternate_screen and not self._in_alternate_screen:
- self._in_alternate_screen = True
- output.enter_alternate_screen()
-
- # Enable bracketed paste.
- if not self._bracketed_paste_enabled:
- self.output.enable_bracketed_paste()
- self._bracketed_paste_enabled = True
-
- # Enable/disable mouse support.
- needs_mouse_support = self.mouse_support(cli)
-
- if needs_mouse_support and not self._mouse_support_enabled:
- output.enable_mouse_support()
- self._mouse_support_enabled = True
-
- elif not needs_mouse_support and self._mouse_support_enabled:
- output.disable_mouse_support()
- self._mouse_support_enabled = False
-
- # Create screen and write layout to it.
- size = output.get_size()
- screen = Screen()
- screen.show_cursor = False # Hide cursor by default, unless one of the
- # containers decides to display it.
- mouse_handlers = MouseHandlers()
-
- if is_done:
- height = 0 # When we are done, we don't necessary want to fill up until the bottom.
- else:
- height = self._last_screen.height if self._last_screen else 0
- height = max(self._min_available_height, height)
-
- # When te size changes, don't consider the previous screen.
- if self._last_size != size:
- self._last_screen = None
-
- # When we render using another style, do a full repaint. (Forget about
- # the previous rendered screen.)
- # (But note that we still use _last_screen to calculate the height.)
- if self.style.invalidation_hash() != self._last_style_hash:
- self._last_screen = None
- self._attrs_for_token = None
- if self._attrs_for_token is None:
- self._attrs_for_token = _TokenToAttrsCache(self.style.get_attrs_for_token)
- self._last_style_hash = self.style.invalidation_hash()
-
- layout.write_to_screen(cli, screen, mouse_handlers, WritePosition(
- xpos=0,
- ypos=0,
- width=size.columns,
- height=(size.rows if self.use_alternate_screen else height),
- extended_height=size.rows,
- ))
-
- # When grayed. Replace all tokens in the new screen.
- if cli.is_aborting or cli.is_exiting:
- screen.replace_all_tokens(Token.Aborted)
-
- # Process diff and write to output.
+ def render(self, cli, layout, is_done=False):
+ """
+ Render the current interface to the output.
+
+ :param is_done: When True, put the cursor at the end of the interface. We
+ won't print any changes to this part.
+ """
+ output = self.output
+
+ # Enter alternate screen.
+ if self.use_alternate_screen and not self._in_alternate_screen:
+ self._in_alternate_screen = True
+ output.enter_alternate_screen()
+
+ # Enable bracketed paste.
+ if not self._bracketed_paste_enabled:
+ self.output.enable_bracketed_paste()
+ self._bracketed_paste_enabled = True
+
+ # Enable/disable mouse support.
+ needs_mouse_support = self.mouse_support(cli)
+
+ if needs_mouse_support and not self._mouse_support_enabled:
+ output.enable_mouse_support()
+ self._mouse_support_enabled = True
+
+ elif not needs_mouse_support and self._mouse_support_enabled:
+ output.disable_mouse_support()
+ self._mouse_support_enabled = False
+
+ # Create screen and write layout to it.
+ size = output.get_size()
+ screen = Screen()
+ screen.show_cursor = False # Hide cursor by default, unless one of the
+ # containers decides to display it.
+ mouse_handlers = MouseHandlers()
+
+ if is_done:
+ height = 0 # When we are done, we don't necessary want to fill up until the bottom.
+ else:
+ height = self._last_screen.height if self._last_screen else 0
+ height = max(self._min_available_height, height)
+
+ # When te size changes, don't consider the previous screen.
+ if self._last_size != size:
+ self._last_screen = None
+
+ # When we render using another style, do a full repaint. (Forget about
+ # the previous rendered screen.)
+ # (But note that we still use _last_screen to calculate the height.)
+ if self.style.invalidation_hash() != self._last_style_hash:
+ self._last_screen = None
+ self._attrs_for_token = None
+ if self._attrs_for_token is None:
+ self._attrs_for_token = _TokenToAttrsCache(self.style.get_attrs_for_token)
+ self._last_style_hash = self.style.invalidation_hash()
+
+ layout.write_to_screen(cli, screen, mouse_handlers, WritePosition(
+ xpos=0,
+ ypos=0,
+ width=size.columns,
+ height=(size.rows if self.use_alternate_screen else height),
+ extended_height=size.rows,
+ ))
+
+ # When grayed. Replace all tokens in the new screen.
+ if cli.is_aborting or cli.is_exiting:
+ screen.replace_all_tokens(Token.Aborted)
+
+ # Process diff and write to output.
self._cursor_pos, self._last_token = _output_screen_diff(
- output, screen, self._cursor_pos,
+ output, screen, self._cursor_pos,
self._last_screen, self._last_token, is_done,
use_alternate_screen=self.use_alternate_screen,
- attrs_for_token=self._attrs_for_token,
- size=size,
- previous_width=(self._last_size.columns if self._last_size else 0))
- self._last_screen = screen
- self._last_size = size
- self.mouse_handlers = mouse_handlers
-
- # Write title if it changed.
- new_title = cli.terminal_title
-
- if new_title != self._last_title:
- if new_title is None:
- self.output.clear_title()
- else:
- self.output.set_title(new_title)
- self._last_title = new_title
-
- output.flush()
-
+ attrs_for_token=self._attrs_for_token,
+ size=size,
+ previous_width=(self._last_size.columns if self._last_size else 0))
+ self._last_screen = screen
+ self._last_size = size
+ self.mouse_handlers = mouse_handlers
+
+ # Write title if it changed.
+ new_title = cli.terminal_title
+
+ if new_title != self._last_title:
+ if new_title is None:
+ self.output.clear_title()
+ else:
+ self.output.set_title(new_title)
+ self._last_title = new_title
+
+ output.flush()
+
def erase(self, leave_alternate_screen=True, erase_title=True):
- """
- Hide all output and put the cursor back at the first line. This is for
- instance used for running a system command (while hiding the CLI) and
- later resuming the same CLI.)
+ """
+ Hide all output and put the cursor back at the first line. This is for
+ instance used for running a system command (while hiding the CLI) and
+ later resuming the same CLI.)
:param leave_alternate_screen: When True, and when inside an alternate
screen buffer, quit the alternate screen.
:param erase_title: When True, clear the title from the title bar.
- """
- output = self.output
-
- output.cursor_backward(self._cursor_pos.x)
- output.cursor_up(self._cursor_pos.y)
- output.erase_down()
- output.reset_attributes()
+ """
+ output = self.output
+
+ output.cursor_backward(self._cursor_pos.x)
+ output.cursor_up(self._cursor_pos.y)
+ output.erase_down()
+ output.reset_attributes()
output.enable_autowrap()
- output.flush()
-
- # Erase title.
+ output.flush()
+
+ # Erase title.
if self._last_title and erase_title:
- output.clear_title()
-
+ output.clear_title()
+
self.reset(leave_alternate_screen=leave_alternate_screen)
-
- def clear(self):
- """
- Clear screen and go to 0,0
- """
- # Erase current output first.
- self.erase()
-
- # Send "Erase Screen" command and go to (0, 0).
- output = self.output
-
- output.erase_screen()
- output.cursor_goto(0, 0)
- output.flush()
-
- self.request_absolute_cursor_position()
-
-
-def print_tokens(output, tokens, style):
- """
- Print a list of (Token, text) tuples in the given style to the output.
- """
- assert isinstance(output, Output)
- assert isinstance(style, Style)
-
- # Reset first.
- output.reset_attributes()
- output.enable_autowrap()
-
- # Print all (token, text) tuples.
- attrs_for_token = _TokenToAttrsCache(style.get_attrs_for_token)
-
- for token, text in tokens:
- attrs = attrs_for_token[token]
-
- if attrs:
- output.set_attributes(attrs)
- else:
- output.reset_attributes()
-
- output.write(text)
-
- # Reset again.
- output.reset_attributes()
- output.flush()
+
+ def clear(self):
+ """
+ Clear screen and go to 0,0
+ """
+ # Erase current output first.
+ self.erase()
+
+ # Send "Erase Screen" command and go to (0, 0).
+ output = self.output
+
+ output.erase_screen()
+ output.cursor_goto(0, 0)
+ output.flush()
+
+ self.request_absolute_cursor_position()
+
+
+def print_tokens(output, tokens, style):
+ """
+ Print a list of (Token, text) tuples in the given style to the output.
+ """
+ assert isinstance(output, Output)
+ assert isinstance(style, Style)
+
+ # Reset first.
+ output.reset_attributes()
+ output.enable_autowrap()
+
+ # Print all (token, text) tuples.
+ attrs_for_token = _TokenToAttrsCache(style.get_attrs_for_token)
+
+ for token, text in tokens:
+ attrs = attrs_for_token[token]
+
+ if attrs:
+ output.set_attributes(attrs)
+ else:
+ output.reset_attributes()
+
+ output.write(text)
+
+ # Reset again.
+ output.reset_attributes()
+ output.flush()
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py
index 3d429215315..3c494ea1a94 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/search_state.py
@@ -1,36 +1,36 @@
-from .enums import IncrementalSearchDirection
-from .filters import to_simple_filter
-
-__all__ = (
- 'SearchState',
-)
-
-
-class SearchState(object):
- """
- A search 'query'.
- """
- __slots__ = ('text', 'direction', 'ignore_case')
-
- def __init__(self, text='', direction=IncrementalSearchDirection.FORWARD, ignore_case=False):
- ignore_case = to_simple_filter(ignore_case)
-
- self.text = text
- self.direction = direction
- self.ignore_case = ignore_case
-
- def __repr__(self):
- return '%s(%r, direction=%r, ignore_case=%r)' % (
- self.__class__.__name__, self.text, self.direction, self.ignore_case)
-
- def __invert__(self):
- """
- Create a new SearchState where backwards becomes forwards and the other
- way around.
- """
- if self.direction == IncrementalSearchDirection.BACKWARD:
- direction = IncrementalSearchDirection.FORWARD
- else:
- direction = IncrementalSearchDirection.BACKWARD
-
- return SearchState(text=self.text, direction=direction, ignore_case=self.ignore_case)
+from .enums import IncrementalSearchDirection
+from .filters import to_simple_filter
+
+__all__ = (
+ 'SearchState',
+)
+
+
+class SearchState(object):
+ """
+ A search 'query'.
+ """
+ __slots__ = ('text', 'direction', 'ignore_case')
+
+ def __init__(self, text='', direction=IncrementalSearchDirection.FORWARD, ignore_case=False):
+ ignore_case = to_simple_filter(ignore_case)
+
+ self.text = text
+ self.direction = direction
+ self.ignore_case = ignore_case
+
+ def __repr__(self):
+ return '%s(%r, direction=%r, ignore_case=%r)' % (
+ self.__class__.__name__, self.text, self.direction, self.ignore_case)
+
+ def __invert__(self):
+ """
+ Create a new SearchState where backwards becomes forwards and the other
+ way around.
+ """
+ if self.direction == IncrementalSearchDirection.BACKWARD:
+ direction = IncrementalSearchDirection.FORWARD
+ else:
+ direction = IncrementalSearchDirection.BACKWARD
+
+ return SearchState(text=self.text, direction=direction, ignore_case=self.ignore_case)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py
index a71211bff83..65829212225 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/selection.py
@@ -1,47 +1,47 @@
-"""
-Data structures for the selection.
-"""
-from __future__ import unicode_literals
-
-__all__ = (
- 'SelectionType',
+"""
+Data structures for the selection.
+"""
+from __future__ import unicode_literals
+
+__all__ = (
+ 'SelectionType',
'PasteMode',
- 'SelectionState',
-)
-
-
-class SelectionType(object):
- """
- Type of selection.
- """
- #: Characters. (Visual in Vi.)
+ 'SelectionState',
+)
+
+
+class SelectionType(object):
+ """
+ Type of selection.
+ """
+ #: Characters. (Visual in Vi.)
CHARACTERS = 'CHARACTERS'
-
- #: Whole lines. (Visual-Line in Vi.)
+
+ #: Whole lines. (Visual-Line in Vi.)
LINES = 'LINES'
-
- #: A block selection. (Visual-Block in Vi.)
+
+ #: A block selection. (Visual-Block in Vi.)
BLOCK = 'BLOCK'
-
-
+
+
class PasteMode(object):
EMACS = 'EMACS' # Yank like emacs.
VI_AFTER = 'VI_AFTER' # When pressing 'p' in Vi.
VI_BEFORE = 'VI_BEFORE' # When pressing 'P' in Vi.
-class SelectionState(object):
- """
- State of the current selection.
-
- :param original_cursor_position: int
- :param type: :class:`~.SelectionType`
- """
- def __init__(self, original_cursor_position=0, type=SelectionType.CHARACTERS):
- self.original_cursor_position = original_cursor_position
- self.type = type
-
- def __repr__(self):
- return '%s(original_cursor_position=%r, type=%r)' % (
- self.__class__.__name__,
- self.original_cursor_position, self.type)
+class SelectionState(object):
+ """
+ State of the current selection.
+
+ :param original_cursor_position: int
+ :param type: :class:`~.SelectionType`
+ """
+ def __init__(self, original_cursor_position=0, type=SelectionType.CHARACTERS):
+ self.original_cursor_position = original_cursor_position
+ self.type = type
+
+ def __repr__(self):
+ return '%s(original_cursor_position=%r, type=%r)' % (
+ self.__class__.__name__,
+ self.original_cursor_position, self.type)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py
index 79002b5c103..9893624c6e8 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/shortcuts.py
@@ -1,60 +1,60 @@
-"""
-Shortcuts for retrieving input from the user.
-
-If you are using this library for retrieving some input from the user (as a
-pure Python replacement for GNU readline), probably for 90% of the use cases,
-the :func:`.prompt` function is all you need. It's the easiest shortcut which
-does a lot of the underlying work like creating a
-:class:`~prompt_toolkit.interface.CommandLineInterface` instance for you.
-
-When is this not sufficient:
- - When you want to have more complicated layouts (maybe with sidebars or
- multiple toolbars. Or visibility of certain user interface controls
- according to some conditions.)
- - When you wish to have multiple input buffers. (If you would create an
- editor like a Vi clone.)
- - Something else that requires more customization than what is possible
- with the parameters of `prompt`.
-
-In that case, study the code in this file and build your own
-`CommandLineInterface` instance. It's not too complicated.
-"""
-from __future__ import unicode_literals
-
-from .buffer import Buffer, AcceptAction
-from .document import Document
+"""
+Shortcuts for retrieving input from the user.
+
+If you are using this library for retrieving some input from the user (as a
+pure Python replacement for GNU readline), probably for 90% of the use cases,
+the :func:`.prompt` function is all you need. It's the easiest shortcut which
+does a lot of the underlying work like creating a
+:class:`~prompt_toolkit.interface.CommandLineInterface` instance for you.
+
+When is this not sufficient:
+ - When you want to have more complicated layouts (maybe with sidebars or
+ multiple toolbars. Or visibility of certain user interface controls
+ according to some conditions.)
+ - When you wish to have multiple input buffers. (If you would create an
+ editor like a Vi clone.)
+ - Something else that requires more customization than what is possible
+ with the parameters of `prompt`.
+
+In that case, study the code in this file and build your own
+`CommandLineInterface` instance. It's not too complicated.
+"""
+from __future__ import unicode_literals
+
+from .buffer import Buffer, AcceptAction
+from .document import Document
from .enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
-from .filters import IsDone, HasFocus, RendererHeightIsKnown, to_simple_filter, to_cli_filter, Condition
-from .history import InMemoryHistory
-from .interface import CommandLineInterface, Application, AbortAction
+from .filters import IsDone, HasFocus, RendererHeightIsKnown, to_simple_filter, to_cli_filter, Condition
+from .history import InMemoryHistory
+from .interface import CommandLineInterface, Application, AbortAction
from .key_binding.defaults import load_key_bindings_for_prompt
from .key_binding.registry import Registry
from .keys import Keys
from .layout import Window, HSplit, FloatContainer, Float
-from .layout.containers import ConditionalContainer
-from .layout.controls import BufferControl, TokenListControl
-from .layout.dimension import LayoutDimension
-from .layout.lexers import PygmentsLexer
+from .layout.containers import ConditionalContainer
+from .layout.controls import BufferControl, TokenListControl
+from .layout.dimension import LayoutDimension
+from .layout.lexers import PygmentsLexer
from .layout.margins import PromptMargin, ConditionalMargin
-from .layout.menus import CompletionsMenu, MultiColumnCompletionsMenu
+from .layout.menus import CompletionsMenu, MultiColumnCompletionsMenu
from .layout.processors import PasswordProcessor, ConditionalProcessor, AppendAutoSuggestion, HighlightSearchProcessor, HighlightSelectionProcessor, DisplayMultipleCursors
-from .layout.prompt import DefaultPrompt
-from .layout.screen import Char
-from .layout.toolbars import ValidationToolbar, SystemToolbar, ArgToolbar, SearchToolbar
-from .layout.utils import explode_tokens
+from .layout.prompt import DefaultPrompt
+from .layout.screen import Char
+from .layout.toolbars import ValidationToolbar, SystemToolbar, ArgToolbar, SearchToolbar
+from .layout.utils import explode_tokens
from .renderer import print_tokens as renderer_print_tokens
from .styles import DEFAULT_STYLE, Style, style_from_dict
from .token import Token
-from .utils import is_conemu_ansi, is_windows, DummyContext
-
+from .utils import is_conemu_ansi, is_windows, DummyContext
+
from six import text_type, exec_, PY2
-
+
import os
-import sys
-import textwrap
+import sys
+import textwrap
import threading
import time
-
+
try:
from pygments.lexer import Lexer as pygments_Lexer
from pygments.style import Style as pygments_Style
@@ -62,124 +62,124 @@ except ImportError:
pygments_Lexer = None
pygments_Style = None
-if is_windows():
- from .terminal.win32_output import Win32Output
- from .terminal.conemu_output import ConEmuOutput
-else:
- from .terminal.vt100_output import Vt100_Output
-
-
-__all__ = (
- 'create_eventloop',
- 'create_output',
- 'create_prompt_layout',
- 'create_prompt_application',
- 'prompt',
- 'prompt_async',
+if is_windows():
+ from .terminal.win32_output import Win32Output
+ from .terminal.conemu_output import ConEmuOutput
+else:
+ from .terminal.vt100_output import Vt100_Output
+
+
+__all__ = (
+ 'create_eventloop',
+ 'create_output',
+ 'create_prompt_layout',
+ 'create_prompt_application',
+ 'prompt',
+ 'prompt_async',
'create_confirm_application',
'run_application',
'confirm',
'print_tokens',
'clear',
-)
-
-
+)
+
+
def create_eventloop(inputhook=None, recognize_win32_paste=True):
- """
- Create and return an
- :class:`~prompt_toolkit.eventloop.base.EventLoop` instance for a
- :class:`~prompt_toolkit.interface.CommandLineInterface`.
- """
- if is_windows():
- from prompt_toolkit.eventloop.win32 import Win32EventLoop as Loop
+ """
+ Create and return an
+ :class:`~prompt_toolkit.eventloop.base.EventLoop` instance for a
+ :class:`~prompt_toolkit.interface.CommandLineInterface`.
+ """
+ if is_windows():
+ from prompt_toolkit.eventloop.win32 import Win32EventLoop as Loop
return Loop(inputhook=inputhook, recognize_paste=recognize_win32_paste)
- else:
- from prompt_toolkit.eventloop.posix import PosixEventLoop as Loop
+ else:
+ from prompt_toolkit.eventloop.posix import PosixEventLoop as Loop
return Loop(inputhook=inputhook)
-
-
+
+
def create_output(stdout=None, true_color=False, ansi_colors_only=None):
- """
- Return an :class:`~prompt_toolkit.output.Output` instance for the command
- line.
-
- :param true_color: When True, use 24bit colors instead of 256 colors.
- (`bool` or :class:`~prompt_toolkit.filters.SimpleFilter`.)
+ """
+ Return an :class:`~prompt_toolkit.output.Output` instance for the command
+ line.
+
+ :param true_color: When True, use 24bit colors instead of 256 colors.
+ (`bool` or :class:`~prompt_toolkit.filters.SimpleFilter`.)
:param ansi_colors_only: When True, restrict to 16 ANSI colors only.
(`bool` or :class:`~prompt_toolkit.filters.SimpleFilter`.)
- """
- stdout = stdout or sys.__stdout__
- true_color = to_simple_filter(true_color)
-
- if is_windows():
- if is_conemu_ansi():
- return ConEmuOutput(stdout)
- else:
- return Win32Output(stdout)
- else:
+ """
+ stdout = stdout or sys.__stdout__
+ true_color = to_simple_filter(true_color)
+
+ if is_windows():
+ if is_conemu_ansi():
+ return ConEmuOutput(stdout)
+ else:
+ return Win32Output(stdout)
+ else:
term = os.environ.get('TERM', '')
if PY2:
term = term.decode('utf-8')
-
+
return Vt100_Output.from_pty(
stdout, true_color=true_color,
ansi_colors_only=ansi_colors_only, term=term)
-
-
-def create_asyncio_eventloop(loop=None):
- """
- Returns an asyncio :class:`~prompt_toolkit.eventloop.EventLoop` instance
- for usage in a :class:`~prompt_toolkit.interface.CommandLineInterface`. It
- is a wrapper around an asyncio loop.
-
- :param loop: The asyncio eventloop (or `None` if the default asyncioloop
- should be used.)
- """
- # Inline import, to make sure the rest doesn't break on Python 2. (Where
- # asyncio is not available.)
- if is_windows():
- from prompt_toolkit.eventloop.asyncio_win32 import Win32AsyncioEventLoop as AsyncioEventLoop
- else:
- from prompt_toolkit.eventloop.asyncio_posix import PosixAsyncioEventLoop as AsyncioEventLoop
-
- return AsyncioEventLoop(loop)
-
-
-def _split_multiline_prompt(get_prompt_tokens):
- """
+
+
+def create_asyncio_eventloop(loop=None):
+ """
+ Returns an asyncio :class:`~prompt_toolkit.eventloop.EventLoop` instance
+ for usage in a :class:`~prompt_toolkit.interface.CommandLineInterface`. It
+ is a wrapper around an asyncio loop.
+
+ :param loop: The asyncio eventloop (or `None` if the default asyncioloop
+ should be used.)
+ """
+ # Inline import, to make sure the rest doesn't break on Python 2. (Where
+ # asyncio is not available.)
+ if is_windows():
+ from prompt_toolkit.eventloop.asyncio_win32 import Win32AsyncioEventLoop as AsyncioEventLoop
+ else:
+ from prompt_toolkit.eventloop.asyncio_posix import PosixAsyncioEventLoop as AsyncioEventLoop
+
+ return AsyncioEventLoop(loop)
+
+
+def _split_multiline_prompt(get_prompt_tokens):
+ """
Take a `get_prompt_tokens` function and return three new functions instead.
One that tells whether this prompt consists of multiple lines; one that
returns the tokens to be shown on the lines above the input; and another
one with the tokens to be shown at the first line of the input.
- """
+ """
def has_before_tokens(cli):
for token, char in get_prompt_tokens(cli):
if '\n' in char:
return True
return False
- def before(cli):
- result = []
- found_nl = False
- for token, char in reversed(explode_tokens(get_prompt_tokens(cli))):
+ def before(cli):
+ result = []
+ found_nl = False
+ for token, char in reversed(explode_tokens(get_prompt_tokens(cli))):
if found_nl:
result.insert(0, (token, char))
elif char == '\n':
- found_nl = True
- return result
-
- def first_input_line(cli):
- result = []
- for token, char in reversed(explode_tokens(get_prompt_tokens(cli))):
- if char == '\n':
- break
- else:
- result.insert(0, (token, char))
- return result
-
+ found_nl = True
+ return result
+
+ def first_input_line(cli):
+ result = []
+ for token, char in reversed(explode_tokens(get_prompt_tokens(cli))):
+ if char == '\n':
+ break
+ else:
+ result.insert(0, (token, char))
+ return result
+
return has_before_tokens, before, first_input_line
-
-
+
+
class _RPrompt(Window):
" The prompt that is displayed on the right side of the Window. "
def __init__(self, get_tokens=None):
@@ -189,109 +189,109 @@ class _RPrompt(Window):
TokenListControl(get_tokens, align_right=True))
-def create_prompt_layout(message='', lexer=None, is_password=False,
- reserve_space_for_menu=8,
+def create_prompt_layout(message='', lexer=None, is_password=False,
+ reserve_space_for_menu=8,
get_prompt_tokens=None, get_continuation_tokens=None,
get_rprompt_tokens=None,
get_bottom_toolbar_tokens=None,
- display_completions_in_columns=False,
- extra_input_processors=None, multiline=False,
- wrap_lines=True):
- """
- Create a :class:`.Container` instance for a prompt.
-
- :param message: Text to be used as prompt.
- :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for
- the highlighting.
- :param is_password: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
- When True, display input as '*'.
- :param reserve_space_for_menu: Space to be reserved for the menu. When >0,
- make sure that a minimal height is allocated in the terminal, in order
- to display the completion menu.
- :param get_prompt_tokens: An optional callable that returns the tokens to be
- shown in the menu. (To be used instead of a `message`.)
+ display_completions_in_columns=False,
+ extra_input_processors=None, multiline=False,
+ wrap_lines=True):
+ """
+ Create a :class:`.Container` instance for a prompt.
+
+ :param message: Text to be used as prompt.
+ :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for
+ the highlighting.
+ :param is_password: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
+ When True, display input as '*'.
+ :param reserve_space_for_menu: Space to be reserved for the menu. When >0,
+ make sure that a minimal height is allocated in the terminal, in order
+ to display the completion menu.
+ :param get_prompt_tokens: An optional callable that returns the tokens to be
+ shown in the menu. (To be used instead of a `message`.)
:param get_continuation_tokens: An optional callable that takes a
CommandLineInterface and width as input and returns a list of (Token,
text) tuples to be used for the continuation.
- :param get_bottom_toolbar_tokens: An optional callable that returns the
- tokens for a toolbar at the bottom.
- :param display_completions_in_columns: `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
- multiple columns.
- :param multiline: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
- When True, prefer a layout that is more adapted for multiline input.
- Text after newlines is automatically indented, and search/arg input is
- shown below the input, instead of replacing the prompt.
- :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
- When True (the default), automatically wrap long lines instead of
- scrolling horizontally.
- """
+ :param get_bottom_toolbar_tokens: An optional callable that returns the
+ tokens for a toolbar at the bottom.
+ :param display_completions_in_columns: `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
+ multiple columns.
+ :param multiline: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
+ When True, prefer a layout that is more adapted for multiline input.
+ Text after newlines is automatically indented, and search/arg input is
+ shown below the input, instead of replacing the prompt.
+ :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
+ When True (the default), automatically wrap long lines instead of
+ scrolling horizontally.
+ """
assert isinstance(message, text_type), 'Please provide a unicode string.'
- assert get_bottom_toolbar_tokens is None or callable(get_bottom_toolbar_tokens)
- assert get_prompt_tokens is None or callable(get_prompt_tokens)
+ assert get_bottom_toolbar_tokens is None or callable(get_bottom_toolbar_tokens)
+ assert get_prompt_tokens is None or callable(get_prompt_tokens)
assert get_rprompt_tokens is None or callable(get_rprompt_tokens)
- assert not (message and get_prompt_tokens)
-
- display_completions_in_columns = to_cli_filter(display_completions_in_columns)
- multiline = to_cli_filter(multiline)
-
- if get_prompt_tokens is None:
- get_prompt_tokens = lambda _: [(Token.Prompt, message)]
-
+ assert not (message and get_prompt_tokens)
+
+ display_completions_in_columns = to_cli_filter(display_completions_in_columns)
+ multiline = to_cli_filter(multiline)
+
+ if get_prompt_tokens is None:
+ get_prompt_tokens = lambda _: [(Token.Prompt, message)]
+
has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = \
_split_multiline_prompt(get_prompt_tokens)
-
- # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
- # class is given, turn it into a PygmentsLexer. (Important for
- # backwards-compatibility.)
- try:
+
+ # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
+ # class is given, turn it into a PygmentsLexer. (Important for
+ # backwards-compatibility.)
+ try:
if pygments_Lexer and issubclass(lexer, pygments_Lexer):
lexer = PygmentsLexer(lexer, sync_from_start=True)
- except TypeError: # Happens when lexer is `None` or an instance of something else.
- pass
-
+ except TypeError: # Happens when lexer is `None` or an instance of something else.
+ pass
+
# Create processors list.
input_processors = [
ConditionalProcessor(
- # By default, only highlight search when the search
- # input has the focus. (Note that this doesn't mean
- # there is no search: the Vi 'n' binding for instance
- # still allows to jump to the next match in
- # navigation mode.)
+ # By default, only highlight search when the search
+ # input has the focus. (Note that this doesn't mean
+ # there is no search: the Vi 'n' binding for instance
+ # still allows to jump to the next match in
+ # navigation mode.)
HighlightSearchProcessor(preview_search=True),
HasFocus(SEARCH_BUFFER)),
HighlightSelectionProcessor(),
- ConditionalProcessor(AppendAutoSuggestion(), HasFocus(DEFAULT_BUFFER) & ~IsDone()),
+ ConditionalProcessor(AppendAutoSuggestion(), HasFocus(DEFAULT_BUFFER) & ~IsDone()),
ConditionalProcessor(PasswordProcessor(), is_password),
DisplayMultipleCursors(DEFAULT_BUFFER),
]
-
- if extra_input_processors:
- input_processors.extend(extra_input_processors)
-
- # Show the prompt before the input (using the DefaultPrompt processor.
- # This also replaces it with reverse-i-search and 'arg' when required.
- # (Only for single line mode.)
- # (DefaultPrompt should always be at the end of the processors.)
- input_processors.append(ConditionalProcessor(
+
+ if extra_input_processors:
+ input_processors.extend(extra_input_processors)
+
+ # Show the prompt before the input (using the DefaultPrompt processor.
+ # This also replaces it with reverse-i-search and 'arg' when required.
+ # (Only for single line mode.)
+ # (DefaultPrompt should always be at the end of the processors.)
+ input_processors.append(ConditionalProcessor(
DefaultPrompt(get_prompt_tokens_2), ~multiline))
-
- # Create bottom toolbar.
- if get_bottom_toolbar_tokens:
- toolbars = [ConditionalContainer(
- Window(TokenListControl(get_bottom_toolbar_tokens,
- default_char=Char(' ', Token.Toolbar)),
- height=LayoutDimension.exact(1)),
- filter=~IsDone() & RendererHeightIsKnown())]
- else:
- toolbars = []
-
- def get_height(cli):
- # If there is an autocompletion menu to be shown, make sure that our
- # layout has at least a minimal height in order to display it.
- if reserve_space_for_menu and not cli.is_done:
+
+ # Create bottom toolbar.
+ if get_bottom_toolbar_tokens:
+ toolbars = [ConditionalContainer(
+ Window(TokenListControl(get_bottom_toolbar_tokens,
+ default_char=Char(' ', Token.Toolbar)),
+ height=LayoutDimension.exact(1)),
+ filter=~IsDone() & RendererHeightIsKnown())]
+ else:
+ toolbars = []
+
+ def get_height(cli):
+ # If there is an autocompletion menu to be shown, make sure that our
+ # layout has at least a minimal height in order to display it.
+ if reserve_space_for_menu and not cli.is_done:
buff = cli.current_buffer
-
+
# Reserve the space, either when there are completions, or when
# `complete_while_typing` is true and we expect completions very
# soon.
@@ -300,8 +300,8 @@ def create_prompt_layout(message='', lexer=None, is_password=False,
return LayoutDimension()
- # Create and return Container instance.
- return HSplit([
+ # Create and return Container instance.
+ return HSplit([
# The main input, with completion menus floating on top of it.
FloatContainer(
HSplit([
@@ -310,15 +310,15 @@ def create_prompt_layout(message='', lexer=None, is_password=False,
TokenListControl(get_prompt_tokens_1),
dont_extend_height=True),
Condition(has_before_tokens)
- ),
- Window(
- BufferControl(
- input_processors=input_processors,
- lexer=lexer,
- # Enable preview_search, we want to have immediate feedback
- # in reverse-i-search mode.
- preview_search=True),
- get_height=get_height,
+ ),
+ Window(
+ BufferControl(
+ input_processors=input_processors,
+ lexer=lexer,
+ # Enable preview_search, we want to have immediate feedback
+ # in reverse-i-search mode.
+ preview_search=True),
+ get_height=get_height,
left_margins=[
# In multiline mode, use the window margin to display
# the prompt and continuation tokens.
@@ -328,7 +328,7 @@ def create_prompt_layout(message='', lexer=None, is_password=False,
)
],
wrap_lines=wrap_lines,
- ),
+ ),
]),
[
# Completion menus.
@@ -351,193 +351,193 @@ def create_prompt_layout(message='', lexer=None, is_password=False,
content=_RPrompt(get_rprompt_tokens)),
]
),
- ValidationToolbar(),
- SystemToolbar(),
-
- # In multiline mode, we use two toolbars for 'arg' and 'search'.
- ConditionalContainer(ArgToolbar(), multiline),
- ConditionalContainer(SearchToolbar(), multiline),
- ] + toolbars)
-
-
-def create_prompt_application(
- message='',
- multiline=False,
- wrap_lines=True,
- is_password=False,
- vi_mode=False,
+ ValidationToolbar(),
+ SystemToolbar(),
+
+ # In multiline mode, we use two toolbars for 'arg' and 'search'.
+ ConditionalContainer(ArgToolbar(), multiline),
+ ConditionalContainer(SearchToolbar(), multiline),
+ ] + toolbars)
+
+
+def create_prompt_application(
+ message='',
+ multiline=False,
+ wrap_lines=True,
+ is_password=False,
+ vi_mode=False,
editing_mode=EditingMode.EMACS,
- complete_while_typing=True,
- enable_history_search=False,
- lexer=None,
- enable_system_bindings=False,
- enable_open_in_editor=False,
- validator=None,
- completer=None,
- reserve_space_for_menu=8,
- auto_suggest=None,
- style=None,
- history=None,
- clipboard=None,
- get_prompt_tokens=None,
+ complete_while_typing=True,
+ enable_history_search=False,
+ lexer=None,
+ enable_system_bindings=False,
+ enable_open_in_editor=False,
+ validator=None,
+ completer=None,
+ reserve_space_for_menu=8,
+ auto_suggest=None,
+ style=None,
+ history=None,
+ clipboard=None,
+ get_prompt_tokens=None,
get_continuation_tokens=None,
get_rprompt_tokens=None,
- get_bottom_toolbar_tokens=None,
- display_completions_in_columns=False,
- get_title=None,
- mouse_support=False,
- extra_input_processors=None,
- key_bindings_registry=None,
- on_abort=AbortAction.RAISE_EXCEPTION,
- on_exit=AbortAction.RAISE_EXCEPTION,
- accept_action=AcceptAction.RETURN_DOCUMENT,
+ get_bottom_toolbar_tokens=None,
+ display_completions_in_columns=False,
+ get_title=None,
+ mouse_support=False,
+ extra_input_processors=None,
+ key_bindings_registry=None,
+ on_abort=AbortAction.RAISE_EXCEPTION,
+ on_exit=AbortAction.RAISE_EXCEPTION,
+ accept_action=AcceptAction.RETURN_DOCUMENT,
erase_when_done=False,
- default=''):
- """
- Create an :class:`~Application` instance for a prompt.
-
- (It is meant to cover 90% of the prompt use cases, where no extreme
- customization is required. For more complex input, it is required to create
- a custom :class:`~Application` instance.)
-
- :param message: Text to be shown before the prompt.
- :param mulitiline: Allow multiline input. Pressing enter will insert a
- newline. (This requires Meta+Enter to accept the input.)
- :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
- When True (the default), automatically wrap long lines instead of
- scrolling horizontally.
- :param is_password: Show asterisks instead of the actual typed characters.
+ default=''):
+ """
+ Create an :class:`~Application` instance for a prompt.
+
+ (It is meant to cover 90% of the prompt use cases, where no extreme
+ customization is required. For more complex input, it is required to create
+ a custom :class:`~Application` instance.)
+
+ :param message: Text to be shown before the prompt.
+ :param mulitiline: Allow multiline input. Pressing enter will insert a
+ newline. (This requires Meta+Enter to accept the input.)
+ :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`.
+ When True (the default), automatically wrap long lines instead of
+ scrolling horizontally.
+ :param is_password: Show asterisks instead of the actual typed characters.
:param editing_mode: ``EditingMode.VI`` or ``EditingMode.EMACS``.
:param vi_mode: `bool`, if True, Identical to ``editing_mode=EditingMode.VI``.
- :param complete_while_typing: `bool` or
+ :param complete_while_typing: `bool` or
:class:`~prompt_toolkit.filters.SimpleFilter`. Enable autocompletion
while typing.
- :param enable_history_search: `bool` or
+ :param enable_history_search: `bool` or
:class:`~prompt_toolkit.filters.SimpleFilter`. Enable up-arrow parting
- string matching.
- :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for
- the syntax highlighting.
- :param validator: :class:`~prompt_toolkit.validation.Validator` instance
- for input validation.
- :param completer: :class:`~prompt_toolkit.completion.Completer` instance
- for input completion.
- :param reserve_space_for_menu: Space to be reserved for displaying the menu.
- (0 means that no space needs to be reserved.)
- :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest`
- instance for input suggestions.
+ string matching.
+ :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for
+ the syntax highlighting.
+ :param validator: :class:`~prompt_toolkit.validation.Validator` instance
+ for input validation.
+ :param completer: :class:`~prompt_toolkit.completion.Completer` instance
+ for input completion.
+ :param reserve_space_for_menu: Space to be reserved for displaying the menu.
+ (0 means that no space needs to be reserved.)
+ :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest`
+ instance for input suggestions.
:param style: :class:`.Style` instance for the color scheme.
- :param enable_system_bindings: `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter`. Pressing Meta+'!' will show
- a system prompt.
- :param enable_open_in_editor: `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter`. Pressing 'v' in Vi mode or
- C-X C-E in emacs mode will open an external editor.
- :param history: :class:`~prompt_toolkit.history.History` instance.
- :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` instance.
- (e.g. :class:`~prompt_toolkit.clipboard.in_memory.InMemoryClipboard`)
- :param get_bottom_toolbar_tokens: Optional callable which takes a
- :class:`~prompt_toolkit.interface.CommandLineInterface` and returns a
- list of tokens for the bottom toolbar.
- :param display_completions_in_columns: `bool` or
- :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
- multiple columns.
- :param get_title: Callable that returns the title to be displayed in the
- terminal.
- :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`
- to enable mouse support.
- :param default: The default text to be shown in the input buffer. (This can
- be edited by the user.)
- """
- if key_bindings_registry is None:
+ :param enable_system_bindings: `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter`. Pressing Meta+'!' will show
+ a system prompt.
+ :param enable_open_in_editor: `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter`. Pressing 'v' in Vi mode or
+ C-X C-E in emacs mode will open an external editor.
+ :param history: :class:`~prompt_toolkit.history.History` instance.
+ :param clipboard: :class:`~prompt_toolkit.clipboard.base.Clipboard` instance.
+ (e.g. :class:`~prompt_toolkit.clipboard.in_memory.InMemoryClipboard`)
+ :param get_bottom_toolbar_tokens: Optional callable which takes a
+ :class:`~prompt_toolkit.interface.CommandLineInterface` and returns a
+ list of tokens for the bottom toolbar.
+ :param display_completions_in_columns: `bool` or
+ :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in
+ multiple columns.
+ :param get_title: Callable that returns the title to be displayed in the
+ terminal.
+ :param mouse_support: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`
+ to enable mouse support.
+ :param default: The default text to be shown in the input buffer. (This can
+ be edited by the user.)
+ """
+ if key_bindings_registry is None:
key_bindings_registry = load_key_bindings_for_prompt(
- enable_system_bindings=enable_system_bindings,
+ enable_system_bindings=enable_system_bindings,
enable_open_in_editor=enable_open_in_editor)
-
+
# Ensure backwards-compatibility, when `vi_mode` is passed.
if vi_mode:
editing_mode = EditingMode.VI
- # Make sure that complete_while_typing is disabled when enable_history_search
- # is enabled. (First convert to SimpleFilter, to avoid doing bitwise operations
- # on bool objects.)
- complete_while_typing = to_simple_filter(complete_while_typing)
- enable_history_search = to_simple_filter(enable_history_search)
- multiline = to_simple_filter(multiline)
-
- complete_while_typing = complete_while_typing & ~enable_history_search
-
- # Accept Pygments styles as well for backwards compatibility.
- try:
+ # Make sure that complete_while_typing is disabled when enable_history_search
+ # is enabled. (First convert to SimpleFilter, to avoid doing bitwise operations
+ # on bool objects.)
+ complete_while_typing = to_simple_filter(complete_while_typing)
+ enable_history_search = to_simple_filter(enable_history_search)
+ multiline = to_simple_filter(multiline)
+
+ complete_while_typing = complete_while_typing & ~enable_history_search
+
+ # Accept Pygments styles as well for backwards compatibility.
+ try:
if pygments_Style and issubclass(style, pygments_Style):
style = style_from_dict(style.styles)
except TypeError: # Happens when style is `None` or an instance of something else.
- pass
-
- # Create application
- return Application(
- layout=create_prompt_layout(
- message=message,
- lexer=lexer,
- is_password=is_password,
- reserve_space_for_menu=(reserve_space_for_menu if completer is not None else 0),
- multiline=Condition(lambda cli: multiline()),
- get_prompt_tokens=get_prompt_tokens,
+ pass
+
+ # Create application
+ return Application(
+ layout=create_prompt_layout(
+ message=message,
+ lexer=lexer,
+ is_password=is_password,
+ reserve_space_for_menu=(reserve_space_for_menu if completer is not None else 0),
+ multiline=Condition(lambda cli: multiline()),
+ get_prompt_tokens=get_prompt_tokens,
get_continuation_tokens=get_continuation_tokens,
get_rprompt_tokens=get_rprompt_tokens,
- get_bottom_toolbar_tokens=get_bottom_toolbar_tokens,
- display_completions_in_columns=display_completions_in_columns,
- extra_input_processors=extra_input_processors,
- wrap_lines=wrap_lines),
- buffer=Buffer(
- enable_history_search=enable_history_search,
- complete_while_typing=complete_while_typing,
- is_multiline=multiline,
- history=(history or InMemoryHistory()),
- validator=validator,
- completer=completer,
- auto_suggest=auto_suggest,
- accept_action=accept_action,
- initial_document=Document(default),
- ),
- style=style or DEFAULT_STYLE,
- clipboard=clipboard,
- key_bindings_registry=key_bindings_registry,
- get_title=get_title,
- mouse_support=mouse_support,
+ get_bottom_toolbar_tokens=get_bottom_toolbar_tokens,
+ display_completions_in_columns=display_completions_in_columns,
+ extra_input_processors=extra_input_processors,
+ wrap_lines=wrap_lines),
+ buffer=Buffer(
+ enable_history_search=enable_history_search,
+ complete_while_typing=complete_while_typing,
+ is_multiline=multiline,
+ history=(history or InMemoryHistory()),
+ validator=validator,
+ completer=completer,
+ auto_suggest=auto_suggest,
+ accept_action=accept_action,
+ initial_document=Document(default),
+ ),
+ style=style or DEFAULT_STYLE,
+ clipboard=clipboard,
+ key_bindings_registry=key_bindings_registry,
+ get_title=get_title,
+ mouse_support=mouse_support,
editing_mode=editing_mode,
erase_when_done=erase_when_done,
reverse_vi_search_direction=True,
- on_abort=on_abort,
- on_exit=on_exit)
-
-
-def prompt(message='', **kwargs):
- """
- Get input from the user and return it.
-
- This is a wrapper around a lot of ``prompt_toolkit`` functionality and can
- be a replacement for `raw_input`. (or GNU readline.)
-
- If you want to keep your history across several calls, create one
- :class:`~prompt_toolkit.history.History` instance and pass it every time.
-
- This function accepts many keyword arguments. Except for the following,
- they are a proxy to the arguments of :func:`.create_prompt_application`.
-
- :param patch_stdout: Replace ``sys.stdout`` by a proxy that ensures that
- print statements from other threads won't destroy the prompt. (They
- will be printed above the prompt instead.)
- :param return_asyncio_coroutine: When True, return a asyncio coroutine. (Python >3.3)
- :param true_color: When True, use 24bit colors instead of 256 colors.
+ on_abort=on_abort,
+ on_exit=on_exit)
+
+
+def prompt(message='', **kwargs):
+ """
+ Get input from the user and return it.
+
+ This is a wrapper around a lot of ``prompt_toolkit`` functionality and can
+ be a replacement for `raw_input`. (or GNU readline.)
+
+ If you want to keep your history across several calls, create one
+ :class:`~prompt_toolkit.history.History` instance and pass it every time.
+
+ This function accepts many keyword arguments. Except for the following,
+ they are a proxy to the arguments of :func:`.create_prompt_application`.
+
+ :param patch_stdout: Replace ``sys.stdout`` by a proxy that ensures that
+ print statements from other threads won't destroy the prompt. (They
+ will be printed above the prompt instead.)
+ :param return_asyncio_coroutine: When True, return a asyncio coroutine. (Python >3.3)
+ :param true_color: When True, use 24bit colors instead of 256 colors.
:param refresh_interval: (number; in seconds) When given, refresh the UI
every so many seconds.
- """
- patch_stdout = kwargs.pop('patch_stdout', False)
- return_asyncio_coroutine = kwargs.pop('return_asyncio_coroutine', False)
- true_color = kwargs.pop('true_color', False)
+ """
+ patch_stdout = kwargs.pop('patch_stdout', False)
+ return_asyncio_coroutine = kwargs.pop('return_asyncio_coroutine', False)
+ true_color = kwargs.pop('true_color', False)
refresh_interval = kwargs.pop('refresh_interval', 0)
eventloop = kwargs.pop('eventloop', None)
-
+
application = create_prompt_application(message, **kwargs)
return run_application(application,
@@ -564,17 +564,17 @@ def run_application(
"""
assert isinstance(application, Application)
- if return_asyncio_coroutine:
- eventloop = create_asyncio_eventloop()
- else:
+ if return_asyncio_coroutine:
+ eventloop = create_asyncio_eventloop()
+ else:
eventloop = eventloop or create_eventloop()
-
- # Create CommandLineInterface.
- cli = CommandLineInterface(
+
+ # Create CommandLineInterface.
+ cli = CommandLineInterface(
application=application,
- eventloop=eventloop,
- output=create_output(true_color=true_color))
-
+ eventloop=eventloop,
+ output=create_output(true_color=true_color))
+
# Set up refresh interval.
if refresh_interval:
done = [False]
@@ -593,20 +593,20 @@ def run_application(
cli.on_start += start_refresh_loop
cli.on_stop += stop_refresh_loop
- # Replace stdout.
+ # Replace stdout.
patch_context = cli.patch_stdout_context(raw=True) if patch_stdout else DummyContext()
-
- # Read input and return it.
- if return_asyncio_coroutine:
- # Create an asyncio coroutine and call it.
+
+ # Read input and return it.
+ if return_asyncio_coroutine:
+ # Create an asyncio coroutine and call it.
exec_context = {'patch_context': patch_context, 'cli': cli,
'Document': Document}
- exec_(textwrap.dedent('''
- def prompt_coro():
+ exec_(textwrap.dedent('''
+ def prompt_coro():
# Inline import, because it slows down startup when asyncio is not
# needed.
import asyncio
-
+
@asyncio.coroutine
def run():
with patch_context:
@@ -616,29 +616,29 @@ def run_application(
return result.text
return result
return run()
- '''), exec_context)
-
- return exec_context['prompt_coro']()
- else:
- try:
- with patch_context:
+ '''), exec_context)
+
+ return exec_context['prompt_coro']()
+ else:
+ try:
+ with patch_context:
result = cli.run()
-
+
if isinstance(result, Document): # Backwards-compatibility.
return result.text
return result
- finally:
- eventloop.close()
-
-
-def prompt_async(message='', **kwargs):
- """
- Similar to :func:`.prompt`, but return an asyncio coroutine instead.
- """
- kwargs['return_asyncio_coroutine'] = True
- return prompt(message, **kwargs)
-
-
+ finally:
+ eventloop.close()
+
+
+def prompt_async(message='', **kwargs):
+ """
+ Similar to :func:`.prompt`, but return an asyncio coroutine instead.
+ """
+ kwargs['return_asyncio_coroutine'] = True
+ return prompt(message, **kwargs)
+
+
def create_confirm_application(message):
"""
Create a confirmation `Application` that returns True/False.
@@ -709,8 +709,8 @@ def clear():
out.flush()
-# Deprecated alias for `prompt`.
-get_input = prompt
+# Deprecated alias for `prompt`.
+get_input = prompt
# Deprecated alias for create_prompt_layout
create_default_layout = create_prompt_layout
# Deprecated alias for create_prompt_application
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py
index b2e724c184b..16b7bde8f3e 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/conemu_output.py
@@ -1,42 +1,42 @@
-from __future__ import unicode_literals
-
-from prompt_toolkit.renderer import Output
-
-from .win32_output import Win32Output
-from .vt100_output import Vt100_Output
-
-__all__ = (
- 'ConEmuOutput',
-)
-
-
-class ConEmuOutput(object):
- """
- ConEmu (Windows) output abstraction.
-
- ConEmu is a Windows console application, but it also supports ANSI escape
- sequences. This output class is actually a proxy to both `Win32Output` and
- `Vt100_Output`. It uses `Win32Output` for console sizing and scrolling, but
- all cursor movements and scrolling happens through the `Vt100_Output`.
-
- This way, we can have 256 colors in ConEmu and Cmder. Rendering will be
- even a little faster as well.
-
- http://conemu.github.io/
- http://gooseberrycreative.com/cmder/
- """
- def __init__(self, stdout):
- self.win32_output = Win32Output(stdout)
- self.vt100_output = Vt100_Output(stdout, lambda: None)
-
- def __getattr__(self, name):
- if name in ('get_size', 'get_rows_below_cursor_position',
- 'enable_mouse_support', 'disable_mouse_support',
+from __future__ import unicode_literals
+
+from prompt_toolkit.renderer import Output
+
+from .win32_output import Win32Output
+from .vt100_output import Vt100_Output
+
+__all__ = (
+ 'ConEmuOutput',
+)
+
+
+class ConEmuOutput(object):
+ """
+ ConEmu (Windows) output abstraction.
+
+ ConEmu is a Windows console application, but it also supports ANSI escape
+ sequences. This output class is actually a proxy to both `Win32Output` and
+ `Vt100_Output`. It uses `Win32Output` for console sizing and scrolling, but
+ all cursor movements and scrolling happens through the `Vt100_Output`.
+
+ This way, we can have 256 colors in ConEmu and Cmder. Rendering will be
+ even a little faster as well.
+
+ http://conemu.github.io/
+ http://gooseberrycreative.com/cmder/
+ """
+ def __init__(self, stdout):
+ self.win32_output = Win32Output(stdout)
+ self.vt100_output = Vt100_Output(stdout, lambda: None)
+
+ def __getattr__(self, name):
+ if name in ('get_size', 'get_rows_below_cursor_position',
+ 'enable_mouse_support', 'disable_mouse_support',
'scroll_buffer_to_prompt', 'get_win32_screen_buffer_info',
'enable_bracketed_paste', 'disable_bracketed_paste'):
- return getattr(self.win32_output, name)
- else:
- return getattr(self.vt100_output, name)
-
-
-Output.register(ConEmuOutput)
+ return getattr(self.win32_output, name)
+ else:
+ return getattr(self.vt100_output, name)
+
+
+Output.register(ConEmuOutput)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py
index 846929807aa..74841312fad 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_input.py
@@ -1,137 +1,137 @@
-"""
-Parser for VT100 input stream.
-"""
-from __future__ import unicode_literals
-
-import os
-import re
-import six
-import termios
-import tty
-
+"""
+Parser for VT100 input stream.
+"""
+from __future__ import unicode_literals
+
+import os
+import re
+import six
+import termios
+import tty
+
from six.moves import range
-from ..keys import Keys
-from ..key_binding.input_processor import KeyPress
-
-__all__ = (
- 'InputStream',
- 'raw_mode',
- 'cooked_mode',
-)
-
-_DEBUG_RENDERER_INPUT = False
-_DEBUG_RENDERER_INPUT_FILENAME = 'prompt-toolkit-render-input.log'
-
-
-# Regex matching any CPR response
-# (Note that we use '\Z' instead of '$', because '$' could include a trailing
-# newline.)
-_cpr_response_re = re.compile('^' + re.escape('\x1b[') + r'\d+;\d+R\Z')
-
-# Mouse events:
-# Typical: "Esc[MaB*" Urxvt: "Esc[96;14;13M" and for Xterm SGR: "Esc[<64;85;12M"
-_mouse_event_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]+[mM]|M...)\Z')
-
-# Regex matching any valid prefix of a CPR response.
-# (Note that it doesn't contain the last character, the 'R'. The prefix has to
-# be shorter.)
-_cpr_response_prefix_re = re.compile('^' + re.escape('\x1b[') + r'[\d;]*\Z')
-
-_mouse_event_prefix_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]*|M.{0,2})\Z')
-
-
-class _Flush(object):
- """ Helper object to indicate flush operation to the parser. """
- pass
-
-
-# Mapping of vt100 escape codes to Keys.
-ANSI_SEQUENCES = {
- '\x1b': Keys.Escape,
-
- '\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
- '\x01': Keys.ControlA, # Control-A (home)
- '\x02': Keys.ControlB, # Control-B (emacs cursor left)
- '\x03': Keys.ControlC, # Control-C (interrupt)
- '\x04': Keys.ControlD, # Control-D (exit)
- '\x05': Keys.ControlE, # Contrel-E (end)
- '\x06': Keys.ControlF, # Control-F (cursor forward)
- '\x07': Keys.ControlG, # Control-G
- '\x08': Keys.ControlH, # Control-H (8) (Identical to '\b')
- '\x09': Keys.ControlI, # Control-I (9) (Identical to '\t')
- '\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n')
- '\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab)
- '\x0c': Keys.ControlL, # Control-L (clear; form feed)
- '\x0d': Keys.ControlM, # Control-M (13) (Identical to '\r')
- '\x0e': Keys.ControlN, # Control-N (14) (history forward)
- '\x0f': Keys.ControlO, # Control-O (15)
- '\x10': Keys.ControlP, # Control-P (16) (history back)
- '\x11': Keys.ControlQ, # Control-Q
- '\x12': Keys.ControlR, # Control-R (18) (reverse search)
- '\x13': Keys.ControlS, # Control-S (19) (forward search)
- '\x14': Keys.ControlT, # Control-T
- '\x15': Keys.ControlU, # Control-U
- '\x16': Keys.ControlV, # Control-V
- '\x17': Keys.ControlW, # Control-W
- '\x18': Keys.ControlX, # Control-X
- '\x19': Keys.ControlY, # Control-Y (25)
- '\x1a': Keys.ControlZ, # Control-Z
-
- '\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-|
- '\x1d': Keys.ControlSquareClose, # Control-]
- '\x1e': Keys.ControlCircumflex, # Control-^
- '\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
- '\x7f': Keys.Backspace, # (127) Backspace
- '\x1b[A': Keys.Up,
- '\x1b[B': Keys.Down,
- '\x1b[C': Keys.Right,
- '\x1b[D': Keys.Left,
- '\x1b[H': Keys.Home,
- '\x1bOH': Keys.Home,
- '\x1b[F': Keys.End,
- '\x1bOF': Keys.End,
- '\x1b[3~': Keys.Delete,
- '\x1b[3;2~': Keys.ShiftDelete, # xterm, gnome-terminal.
+from ..keys import Keys
+from ..key_binding.input_processor import KeyPress
+
+__all__ = (
+ 'InputStream',
+ 'raw_mode',
+ 'cooked_mode',
+)
+
+_DEBUG_RENDERER_INPUT = False
+_DEBUG_RENDERER_INPUT_FILENAME = 'prompt-toolkit-render-input.log'
+
+
+# Regex matching any CPR response
+# (Note that we use '\Z' instead of '$', because '$' could include a trailing
+# newline.)
+_cpr_response_re = re.compile('^' + re.escape('\x1b[') + r'\d+;\d+R\Z')
+
+# Mouse events:
+# Typical: "Esc[MaB*" Urxvt: "Esc[96;14;13M" and for Xterm SGR: "Esc[<64;85;12M"
+_mouse_event_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]+[mM]|M...)\Z')
+
+# Regex matching any valid prefix of a CPR response.
+# (Note that it doesn't contain the last character, the 'R'. The prefix has to
+# be shorter.)
+_cpr_response_prefix_re = re.compile('^' + re.escape('\x1b[') + r'[\d;]*\Z')
+
+_mouse_event_prefix_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]*|M.{0,2})\Z')
+
+
+class _Flush(object):
+ """ Helper object to indicate flush operation to the parser. """
+ pass
+
+
+# Mapping of vt100 escape codes to Keys.
+ANSI_SEQUENCES = {
+ '\x1b': Keys.Escape,
+
+ '\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
+ '\x01': Keys.ControlA, # Control-A (home)
+ '\x02': Keys.ControlB, # Control-B (emacs cursor left)
+ '\x03': Keys.ControlC, # Control-C (interrupt)
+ '\x04': Keys.ControlD, # Control-D (exit)
+ '\x05': Keys.ControlE, # Contrel-E (end)
+ '\x06': Keys.ControlF, # Control-F (cursor forward)
+ '\x07': Keys.ControlG, # Control-G
+ '\x08': Keys.ControlH, # Control-H (8) (Identical to '\b')
+ '\x09': Keys.ControlI, # Control-I (9) (Identical to '\t')
+ '\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n')
+ '\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab)
+ '\x0c': Keys.ControlL, # Control-L (clear; form feed)
+ '\x0d': Keys.ControlM, # Control-M (13) (Identical to '\r')
+ '\x0e': Keys.ControlN, # Control-N (14) (history forward)
+ '\x0f': Keys.ControlO, # Control-O (15)
+ '\x10': Keys.ControlP, # Control-P (16) (history back)
+ '\x11': Keys.ControlQ, # Control-Q
+ '\x12': Keys.ControlR, # Control-R (18) (reverse search)
+ '\x13': Keys.ControlS, # Control-S (19) (forward search)
+ '\x14': Keys.ControlT, # Control-T
+ '\x15': Keys.ControlU, # Control-U
+ '\x16': Keys.ControlV, # Control-V
+ '\x17': Keys.ControlW, # Control-W
+ '\x18': Keys.ControlX, # Control-X
+ '\x19': Keys.ControlY, # Control-Y (25)
+ '\x1a': Keys.ControlZ, # Control-Z
+
+ '\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-|
+ '\x1d': Keys.ControlSquareClose, # Control-]
+ '\x1e': Keys.ControlCircumflex, # Control-^
+ '\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
+ '\x7f': Keys.Backspace, # (127) Backspace
+ '\x1b[A': Keys.Up,
+ '\x1b[B': Keys.Down,
+ '\x1b[C': Keys.Right,
+ '\x1b[D': Keys.Left,
+ '\x1b[H': Keys.Home,
+ '\x1bOH': Keys.Home,
+ '\x1b[F': Keys.End,
+ '\x1bOF': Keys.End,
+ '\x1b[3~': Keys.Delete,
+ '\x1b[3;2~': Keys.ShiftDelete, # xterm, gnome-terminal.
'\x1b[3;5~': Keys.ControlDelete, # xterm, gnome-terminal.
- '\x1b[1~': Keys.Home, # tmux
- '\x1b[4~': Keys.End, # tmux
- '\x1b[5~': Keys.PageUp,
- '\x1b[6~': Keys.PageDown,
- '\x1b[7~': Keys.Home, # xrvt
- '\x1b[8~': Keys.End, # xrvt
- '\x1b[Z': Keys.BackTab, # shift + tab
- '\x1b[2~': Keys.Insert,
-
- '\x1bOP': Keys.F1,
- '\x1bOQ': Keys.F2,
- '\x1bOR': Keys.F3,
- '\x1bOS': Keys.F4,
+ '\x1b[1~': Keys.Home, # tmux
+ '\x1b[4~': Keys.End, # tmux
+ '\x1b[5~': Keys.PageUp,
+ '\x1b[6~': Keys.PageDown,
+ '\x1b[7~': Keys.Home, # xrvt
+ '\x1b[8~': Keys.End, # xrvt
+ '\x1b[Z': Keys.BackTab, # shift + tab
+ '\x1b[2~': Keys.Insert,
+
+ '\x1bOP': Keys.F1,
+ '\x1bOQ': Keys.F2,
+ '\x1bOR': Keys.F3,
+ '\x1bOS': Keys.F4,
'\x1b[[A': Keys.F1, # Linux console.
'\x1b[[B': Keys.F2, # Linux console.
'\x1b[[C': Keys.F3, # Linux console.
'\x1b[[D': Keys.F4, # Linux console.
'\x1b[[E': Keys.F5, # Linux console.
- '\x1b[11~': Keys.F1, # rxvt-unicode
- '\x1b[12~': Keys.F2, # rxvt-unicode
- '\x1b[13~': Keys.F3, # rxvt-unicode
- '\x1b[14~': Keys.F4, # rxvt-unicode
- '\x1b[15~': Keys.F5,
- '\x1b[17~': Keys.F6,
- '\x1b[18~': Keys.F7,
- '\x1b[19~': Keys.F8,
- '\x1b[20~': Keys.F9,
- '\x1b[21~': Keys.F10,
- '\x1b[23~': Keys.F11,
- '\x1b[24~': Keys.F12,
- '\x1b[25~': Keys.F13,
- '\x1b[26~': Keys.F14,
- '\x1b[28~': Keys.F15,
- '\x1b[29~': Keys.F16,
- '\x1b[31~': Keys.F17,
- '\x1b[32~': Keys.F18,
- '\x1b[33~': Keys.F19,
- '\x1b[34~': Keys.F20,
+ '\x1b[11~': Keys.F1, # rxvt-unicode
+ '\x1b[12~': Keys.F2, # rxvt-unicode
+ '\x1b[13~': Keys.F3, # rxvt-unicode
+ '\x1b[14~': Keys.F4, # rxvt-unicode
+ '\x1b[15~': Keys.F5,
+ '\x1b[17~': Keys.F6,
+ '\x1b[18~': Keys.F7,
+ '\x1b[19~': Keys.F8,
+ '\x1b[20~': Keys.F9,
+ '\x1b[21~': Keys.F10,
+ '\x1b[23~': Keys.F11,
+ '\x1b[24~': Keys.F12,
+ '\x1b[25~': Keys.F13,
+ '\x1b[26~': Keys.F14,
+ '\x1b[28~': Keys.F15,
+ '\x1b[29~': Keys.F16,
+ '\x1b[31~': Keys.F17,
+ '\x1b[32~': Keys.F18,
+ '\x1b[33~': Keys.F19,
+ '\x1b[34~': Keys.F20,
# Xterm
'\x1b[1;2P': Keys.F13,
@@ -147,11 +147,11 @@ ANSI_SEQUENCES = {
'\x1b[23;2~': Keys.F23,
'\x1b[24;2~': Keys.F24,
- '\x1b[1;5A': Keys.ControlUp, # Cursor Mode
- '\x1b[1;5B': Keys.ControlDown, # Cursor Mode
- '\x1b[1;5C': Keys.ControlRight, # Cursor Mode
- '\x1b[1;5D': Keys.ControlLeft, # Cursor Mode
-
+ '\x1b[1;5A': Keys.ControlUp, # Cursor Mode
+ '\x1b[1;5B': Keys.ControlDown, # Cursor Mode
+ '\x1b[1;5C': Keys.ControlRight, # Cursor Mode
+ '\x1b[1;5D': Keys.ControlLeft, # Cursor Mode
+
'\x1b[1;2A': Keys.ShiftUp,
'\x1b[1;2B': Keys.ShiftDown,
'\x1b[1;2C': Keys.ShiftRight,
@@ -165,224 +165,224 @@ ANSI_SEQUENCES = {
'\x1bOC': Keys.Right,
'\x1bOD': Keys.Left,
- '\x1b[5A': Keys.ControlUp,
- '\x1b[5B': Keys.ControlDown,
- '\x1b[5C': Keys.ControlRight,
- '\x1b[5D': Keys.ControlLeft,
-
+ '\x1b[5A': Keys.ControlUp,
+ '\x1b[5B': Keys.ControlDown,
+ '\x1b[5C': Keys.ControlRight,
+ '\x1b[5D': Keys.ControlLeft,
+
'\x1bOc': Keys.ControlRight, # rxvt
'\x1bOd': Keys.ControlLeft, # rxvt
- '\x1b[200~': Keys.BracketedPaste, # Start of bracketed paste.
-
- # Meta + arrow keys. Several terminals handle this differently.
- # The following sequences are for xterm and gnome-terminal.
- # (Iterm sends ESC followed by the normal arrow_up/down/left/right
- # sequences, and the OSX Terminal sends ESCb and ESCf for "alt
- # arrow_left" and "alt arrow_right." We don't handle these
- # explicitely, in here, because would could not distinguesh between
- # pressing ESC (to go to Vi navigation mode), followed by just the
- # 'b' or 'f' key. These combinations are handled in
- # the input processor.)
- '\x1b[1;3D': (Keys.Escape, Keys.Left),
- '\x1b[1;3C': (Keys.Escape, Keys.Right),
- '\x1b[1;3A': (Keys.Escape, Keys.Up),
- '\x1b[1;3B': (Keys.Escape, Keys.Down),
+ '\x1b[200~': Keys.BracketedPaste, # Start of bracketed paste.
+
+ # Meta + arrow keys. Several terminals handle this differently.
+ # The following sequences are for xterm and gnome-terminal.
+ # (Iterm sends ESC followed by the normal arrow_up/down/left/right
+ # sequences, and the OSX Terminal sends ESCb and ESCf for "alt
+ # arrow_left" and "alt arrow_right." We don't handle these
+ # explicitely, in here, because would could not distinguesh between
+ # pressing ESC (to go to Vi navigation mode), followed by just the
+ # 'b' or 'f' key. These combinations are handled in
+ # the input processor.)
+ '\x1b[1;3D': (Keys.Escape, Keys.Left),
+ '\x1b[1;3C': (Keys.Escape, Keys.Right),
+ '\x1b[1;3A': (Keys.Escape, Keys.Up),
+ '\x1b[1;3B': (Keys.Escape, Keys.Down),
# Sequences generated by numpad 5. Not sure what it means. (It doesn't
# appear in 'infocmp'. Just ignore.
'\x1b[E': Keys.Ignore, # Xterm.
'\x1b[G': Keys.Ignore, # Linux console.
-}
-
-
-class _IsPrefixOfLongerMatchCache(dict):
- """
- Dictiory that maps input sequences to a boolean indicating whether there is
- any key that start with this characters.
- """
- def __missing__(self, prefix):
- # (hard coded) If this could be a prefix of a CPR response, return
- # True.
- if (_cpr_response_prefix_re.match(prefix) or _mouse_event_prefix_re.match(prefix)):
- result = True
- else:
- # If this could be a prefix of anything else, also return True.
- result = any(v for k, v in ANSI_SEQUENCES.items() if k.startswith(prefix) and k != prefix)
-
- self[prefix] = result
- return result
-
-
-_IS_PREFIX_OF_LONGER_MATCH_CACHE = _IsPrefixOfLongerMatchCache()
-
-
-class InputStream(object):
- """
- Parser for VT100 input stream.
-
- Feed the data through the `feed` method and the correct callbacks of the
- `input_processor` will be called.
-
- ::
-
- def callback(key):
- pass
- i = InputStream(callback)
- i.feed('data\x01...')
-
- :attr input_processor: :class:`~prompt_toolkit.key_binding.InputProcessor` instance.
- """
- # Lookup table of ANSI escape sequences for a VT100 terminal
- # Hint: in order to know what sequences your terminal writes to stdin, run
- # "od -c" and start typing.
- def __init__(self, feed_key_callback):
- assert callable(feed_key_callback)
-
- self.feed_key_callback = feed_key_callback
- self.reset()
-
- if _DEBUG_RENDERER_INPUT:
- self.LOG = open(_DEBUG_RENDERER_INPUT_FILENAME, 'ab')
-
- def reset(self, request=False):
- self._in_bracketed_paste = False
- self._start_parser()
-
- def _start_parser(self):
- """
- Start the parser coroutine.
- """
- self._input_parser = self._input_parser_generator()
- self._input_parser.send(None)
-
- def _get_match(self, prefix):
- """
- Return the key that maps to this prefix.
- """
- # (hard coded) If we match a CPR response, return Keys.CPRResponse.
- # (This one doesn't fit in the ANSI_SEQUENCES, because it contains
- # integer variables.)
- if _cpr_response_re.match(prefix):
- return Keys.CPRResponse
-
- elif _mouse_event_re.match(prefix):
- return Keys.Vt100MouseEvent
-
- # Otherwise, use the mappings.
- try:
- return ANSI_SEQUENCES[prefix]
- except KeyError:
- return None
-
- def _input_parser_generator(self):
- """
- Coroutine (state machine) for the input parser.
- """
- prefix = ''
- retry = False
- flush = False
-
- while True:
- flush = False
-
- if retry:
- retry = False
- else:
- # Get next character.
- c = yield
-
- if c == _Flush:
- flush = True
- else:
- prefix += c
-
- # If we have some data, check for matches.
- if prefix:
- is_prefix_of_longer_match = _IS_PREFIX_OF_LONGER_MATCH_CACHE[prefix]
- match = self._get_match(prefix)
-
- # Exact matches found, call handlers..
- if (flush or not is_prefix_of_longer_match) and match:
- self._call_handler(match, prefix)
- prefix = ''
-
- # No exact match found.
- elif (flush or not is_prefix_of_longer_match) and not match:
- found = False
- retry = True
-
- # Loop over the input, try the longest match first and
- # shift.
- for i in range(len(prefix), 0, -1):
- match= self._get_match(prefix[:i])
- if match:
- self._call_handler(match, prefix[:i])
- prefix = prefix[i:]
- found = True
-
- if not found:
- self._call_handler(prefix[0], prefix[0])
- prefix = prefix[1:]
-
- def _call_handler(self, key, insert_text):
- """
- Callback to handler.
- """
- if isinstance(key, tuple):
- for k in key:
- self._call_handler(k, insert_text)
- else:
- if key == Keys.BracketedPaste:
- self._in_bracketed_paste = True
- self._paste_buffer = ''
- else:
- self.feed_key_callback(KeyPress(key, insert_text))
-
- def feed(self, data):
- """
- Feed the input stream.
-
- :param data: Input string (unicode).
- """
- assert isinstance(data, six.text_type)
-
- if _DEBUG_RENDERER_INPUT:
- self.LOG.write(repr(data).encode('utf-8') + b'\n')
- self.LOG.flush()
-
- # Handle bracketed paste. (We bypass the parser that matches all other
- # key presses and keep reading input until we see the end mark.)
- # This is much faster then parsing character by character.
- if self._in_bracketed_paste:
- self._paste_buffer += data
- end_mark = '\x1b[201~'
-
- if end_mark in self._paste_buffer:
- end_index = self._paste_buffer.index(end_mark)
-
- # Feed content to key bindings.
- paste_content = self._paste_buffer[:end_index]
- self.feed_key_callback(KeyPress(Keys.BracketedPaste, paste_content))
-
- # Quit bracketed paste mode and handle remaining input.
- self._in_bracketed_paste = False
+}
+
+
+class _IsPrefixOfLongerMatchCache(dict):
+ """
+ Dictiory that maps input sequences to a boolean indicating whether there is
+ any key that start with this characters.
+ """
+ def __missing__(self, prefix):
+ # (hard coded) If this could be a prefix of a CPR response, return
+ # True.
+ if (_cpr_response_prefix_re.match(prefix) or _mouse_event_prefix_re.match(prefix)):
+ result = True
+ else:
+ # If this could be a prefix of anything else, also return True.
+ result = any(v for k, v in ANSI_SEQUENCES.items() if k.startswith(prefix) and k != prefix)
+
+ self[prefix] = result
+ return result
+
+
+_IS_PREFIX_OF_LONGER_MATCH_CACHE = _IsPrefixOfLongerMatchCache()
+
+
+class InputStream(object):
+ """
+ Parser for VT100 input stream.
+
+ Feed the data through the `feed` method and the correct callbacks of the
+ `input_processor` will be called.
+
+ ::
+
+ def callback(key):
+ pass
+ i = InputStream(callback)
+ i.feed('data\x01...')
+
+ :attr input_processor: :class:`~prompt_toolkit.key_binding.InputProcessor` instance.
+ """
+ # Lookup table of ANSI escape sequences for a VT100 terminal
+ # Hint: in order to know what sequences your terminal writes to stdin, run
+ # "od -c" and start typing.
+ def __init__(self, feed_key_callback):
+ assert callable(feed_key_callback)
+
+ self.feed_key_callback = feed_key_callback
+ self.reset()
+
+ if _DEBUG_RENDERER_INPUT:
+ self.LOG = open(_DEBUG_RENDERER_INPUT_FILENAME, 'ab')
+
+ def reset(self, request=False):
+ self._in_bracketed_paste = False
+ self._start_parser()
+
+ def _start_parser(self):
+ """
+ Start the parser coroutine.
+ """
+ self._input_parser = self._input_parser_generator()
+ self._input_parser.send(None)
+
+ def _get_match(self, prefix):
+ """
+ Return the key that maps to this prefix.
+ """
+ # (hard coded) If we match a CPR response, return Keys.CPRResponse.
+ # (This one doesn't fit in the ANSI_SEQUENCES, because it contains
+ # integer variables.)
+ if _cpr_response_re.match(prefix):
+ return Keys.CPRResponse
+
+ elif _mouse_event_re.match(prefix):
+ return Keys.Vt100MouseEvent
+
+ # Otherwise, use the mappings.
+ try:
+ return ANSI_SEQUENCES[prefix]
+ except KeyError:
+ return None
+
+ def _input_parser_generator(self):
+ """
+ Coroutine (state machine) for the input parser.
+ """
+ prefix = ''
+ retry = False
+ flush = False
+
+ while True:
+ flush = False
+
+ if retry:
+ retry = False
+ else:
+ # Get next character.
+ c = yield
+
+ if c == _Flush:
+ flush = True
+ else:
+ prefix += c
+
+ # If we have some data, check for matches.
+ if prefix:
+ is_prefix_of_longer_match = _IS_PREFIX_OF_LONGER_MATCH_CACHE[prefix]
+ match = self._get_match(prefix)
+
+ # Exact matches found, call handlers..
+ if (flush or not is_prefix_of_longer_match) and match:
+ self._call_handler(match, prefix)
+ prefix = ''
+
+ # No exact match found.
+ elif (flush or not is_prefix_of_longer_match) and not match:
+ found = False
+ retry = True
+
+ # Loop over the input, try the longest match first and
+ # shift.
+ for i in range(len(prefix), 0, -1):
+ match= self._get_match(prefix[:i])
+ if match:
+ self._call_handler(match, prefix[:i])
+ prefix = prefix[i:]
+ found = True
+
+ if not found:
+ self._call_handler(prefix[0], prefix[0])
+ prefix = prefix[1:]
+
+ def _call_handler(self, key, insert_text):
+ """
+ Callback to handler.
+ """
+ if isinstance(key, tuple):
+ for k in key:
+ self._call_handler(k, insert_text)
+ else:
+ if key == Keys.BracketedPaste:
+ self._in_bracketed_paste = True
+ self._paste_buffer = ''
+ else:
+ self.feed_key_callback(KeyPress(key, insert_text))
+
+ def feed(self, data):
+ """
+ Feed the input stream.
+
+ :param data: Input string (unicode).
+ """
+ assert isinstance(data, six.text_type)
+
+ if _DEBUG_RENDERER_INPUT:
+ self.LOG.write(repr(data).encode('utf-8') + b'\n')
+ self.LOG.flush()
+
+ # Handle bracketed paste. (We bypass the parser that matches all other
+ # key presses and keep reading input until we see the end mark.)
+ # This is much faster then parsing character by character.
+ if self._in_bracketed_paste:
+ self._paste_buffer += data
+ end_mark = '\x1b[201~'
+
+ if end_mark in self._paste_buffer:
+ end_index = self._paste_buffer.index(end_mark)
+
+ # Feed content to key bindings.
+ paste_content = self._paste_buffer[:end_index]
+ self.feed_key_callback(KeyPress(Keys.BracketedPaste, paste_content))
+
+ # Quit bracketed paste mode and handle remaining input.
+ self._in_bracketed_paste = False
remaining = self._paste_buffer[end_index + len(end_mark):]
- self._paste_buffer = ''
-
+ self._paste_buffer = ''
+
self.feed(remaining)
- # Handle normal input character by character.
- else:
- for i, c in enumerate(data):
- if self._in_bracketed_paste:
- # Quit loop and process from this position when the parser
- # entered bracketed paste.
- self.feed(data[i:])
- break
- else:
- # Replace \r by \n. (Some clients send \r instead of \n
- # when enter is pressed. E.g. telnet and some other
+ # Handle normal input character by character.
+ else:
+ for i, c in enumerate(data):
+ if self._in_bracketed_paste:
+ # Quit loop and process from this position when the parser
+ # entered bracketed paste.
+ self.feed(data[i:])
+ break
+ else:
+ # Replace \r by \n. (Some clients send \r instead of \n
+ # when enter is pressed. E.g. telnet and some other
# terminals.)
# XXX: We should remove this in a future version. It *is*
@@ -393,41 +393,41 @@ class InputStream(object):
# When this is removed, replace Enter=ControlJ by
# Enter=ControlM in keys.py.
- if c == '\r':
- c = '\n'
- self._input_parser.send(c)
-
- def flush(self):
- """
- Flush the buffer of the input stream.
-
- This will allow us to handle the escape key (or maybe meta) sooner.
- The input received by the escape key is actually the same as the first
- characters of e.g. Arrow-Up, so without knowing what follows the escape
- sequence, we don't know whether escape has been pressed, or whether
- it's something else. This flush function should be called after a
- timeout, and processes everything that's still in the buffer as-is, so
- without assuming any characters will folow.
- """
- self._input_parser.send(_Flush)
-
- def feed_and_flush(self, data):
- """
- Wrapper around ``feed`` and ``flush``.
- """
- self.feed(data)
- self.flush()
-
-
-class raw_mode(object):
- """
- ::
-
- with raw_mode(stdin):
- ''' the pseudo-terminal stdin is now used in raw mode '''
+ if c == '\r':
+ c = '\n'
+ self._input_parser.send(c)
+
+ def flush(self):
+ """
+ Flush the buffer of the input stream.
+
+ This will allow us to handle the escape key (or maybe meta) sooner.
+ The input received by the escape key is actually the same as the first
+ characters of e.g. Arrow-Up, so without knowing what follows the escape
+ sequence, we don't know whether escape has been pressed, or whether
+ it's something else. This flush function should be called after a
+ timeout, and processes everything that's still in the buffer as-is, so
+ without assuming any characters will folow.
+ """
+ self._input_parser.send(_Flush)
+
+ def feed_and_flush(self, data):
+ """
+ Wrapper around ``feed`` and ``flush``.
+ """
+ self.feed(data)
+ self.flush()
+
+
+class raw_mode(object):
+ """
+ ::
+
+ with raw_mode(stdin):
+ ''' the pseudo-terminal stdin is now used in raw mode '''
We ignore errors when executing `tcgetattr` fails.
- """
+ """
# There are several reasons for ignoring errors:
# 1. To avoid the "Inappropriate ioctl for device" crash if somebody would
# execute this code (In a Python REPL, for instance):
@@ -442,16 +442,16 @@ class raw_mode(object):
# 2. Related, when stdin is an SSH pipe, and no full terminal was allocated.
# See: https://github.com/jonathanslenders/python-prompt-toolkit/pull/165
- def __init__(self, fileno):
- self.fileno = fileno
+ def __init__(self, fileno):
+ self.fileno = fileno
try:
self.attrs_before = termios.tcgetattr(fileno)
except termios.error:
# Ignore attribute errors.
self.attrs_before = None
-
- def __enter__(self):
- # NOTE: On os X systems, using pty.setraw() fails. Therefor we are using this:
+
+ def __enter__(self):
+ # NOTE: On os X systems, using pty.setraw() fails. Therefor we are using this:
try:
newattr = termios.tcgetattr(self.fileno)
except termios.error:
@@ -468,14 +468,14 @@ class raw_mode(object):
newattr[tty.CC][termios.VMIN] = 1
termios.tcsetattr(self.fileno, termios.TCSANOW, newattr)
-
+
# Put the terminal in cursor mode. (Instead of application mode.)
os.write(self.fileno, b'\x1b[?1l')
-
+
@classmethod
def _patch_lflag(cls, attrs):
- return attrs & ~(termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG)
-
+ return attrs & ~(termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG)
+
@classmethod
def _patch_iflag(cls, attrs):
return attrs & ~(
@@ -488,28 +488,28 @@ class raw_mode(object):
termios.ICRNL | termios.INLCR | termios.IGNCR
)
- def __exit__(self, *a, **kw):
+ def __exit__(self, *a, **kw):
if self.attrs_before is not None:
try:
termios.tcsetattr(self.fileno, termios.TCSANOW, self.attrs_before)
except termios.error:
pass
-
+
# # Put the terminal in application mode.
# self._stdout.write('\x1b[?1h')
-
-
-class cooked_mode(raw_mode):
- """
+
+
+class cooked_mode(raw_mode):
+ """
The opposide of ``raw_mode``, used when we need cooked mode inside a
`raw_mode` block. Used in `CommandLineInterface.run_in_terminal`.::
-
- with cooked_mode(stdin):
- ''' the pseudo-terminal stdin is now used in cooked mode. '''
- """
+
+ with cooked_mode(stdin):
+ ''' the pseudo-terminal stdin is now used in cooked mode. '''
+ """
@classmethod
def _patch_lflag(cls, attrs):
- return attrs | (termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG)
+ return attrs | (termios.ECHO | termios.ICANON | termios.IEXTEN | termios.ISIG)
@classmethod
def _patch_iflag(cls, attrs):
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py
index 14309431670..b800aaacec4 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/vt100_output.py
@@ -6,28 +6,28 @@ A lot of thanks, regarding outputting of colors, goes to the Pygments project:
everything has been highly optimized.)
http://pygments.org/
"""
-from __future__ import unicode_literals
-
+from __future__ import unicode_literals
+
from prompt_toolkit.filters import to_simple_filter, Condition
-from prompt_toolkit.layout.screen import Size
-from prompt_toolkit.renderer import Output
-from prompt_toolkit.styles import ANSI_COLOR_NAMES
-
+from prompt_toolkit.layout.screen import Size
+from prompt_toolkit.renderer import Output
+from prompt_toolkit.styles import ANSI_COLOR_NAMES
+
from six.moves import range
-import array
-import errno
+import array
+import errno
import os
-import six
-
-__all__ = (
- 'Vt100_Output',
-)
-
-
-FG_ANSI_COLORS = {
+import six
+
+__all__ = (
+ 'Vt100_Output',
+)
+
+
+FG_ANSI_COLORS = {
'ansidefault': 39,
-
- # Low intensity.
+
+ # Low intensity.
'ansiblack': 30,
'ansidarkred': 31,
'ansidarkgreen': 32,
@@ -36,8 +36,8 @@ FG_ANSI_COLORS = {
'ansipurple': 35,
'ansiteal': 36,
'ansilightgray': 37,
-
- # High intensity.
+
+ # High intensity.
'ansidarkgray': 90,
'ansired': 91,
'ansigreen': 92,
@@ -46,12 +46,12 @@ FG_ANSI_COLORS = {
'ansifuchsia': 95,
'ansiturquoise': 96,
'ansiwhite': 97,
-}
-
-BG_ANSI_COLORS = {
+}
+
+BG_ANSI_COLORS = {
'ansidefault': 49,
-
- # Low intensity.
+
+ # Low intensity.
'ansiblack': 40,
'ansidarkred': 41,
'ansidarkgreen': 42,
@@ -60,8 +60,8 @@ BG_ANSI_COLORS = {
'ansipurple': 45,
'ansiteal': 46,
'ansilightgray': 47,
-
- # High intensity.
+
+ # High intensity.
'ansidarkgray': 100,
'ansired': 101,
'ansigreen': 102,
@@ -70,8 +70,8 @@ BG_ANSI_COLORS = {
'ansifuchsia': 105,
'ansiturquoise': 106,
'ansiwhite': 107,
-}
-
+}
+
ANSI_COLORS_TO_RGB = {
'ansidefault': (0x00, 0x00, 0x00), # Don't use, 'default' doesn't really have a value.
@@ -98,11 +98,11 @@ ANSI_COLORS_TO_RGB = {
}
-assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
assert set(ANSI_COLORS_TO_RGB) == set(ANSI_COLOR_NAMES)
-
-
+
+
def _get_closest_ansi_color(r, g, b, exclude=()):
"""
Find closest ANSI color. Return it by name.
@@ -238,43 +238,43 @@ _16_bg_colors = _16ColorCache(bg=True)
_256_colors = _256ColorCache()
-class _EscapeCodeCache(dict):
- """
- Cache for VT100 escape codes. It maps
- (fgcolor, bgcolor, bold, underline, reverse) tuples to VT100 escape sequences.
-
- :param true_color: When True, use 24bit colors instead of 256 colors.
- """
+class _EscapeCodeCache(dict):
+ """
+ Cache for VT100 escape codes. It maps
+ (fgcolor, bgcolor, bold, underline, reverse) tuples to VT100 escape sequences.
+
+ :param true_color: When True, use 24bit colors instead of 256 colors.
+ """
def __init__(self, true_color=False, ansi_colors_only=False):
- assert isinstance(true_color, bool)
- self.true_color = true_color
+ assert isinstance(true_color, bool)
+ self.true_color = true_color
self.ansi_colors_only = to_simple_filter(ansi_colors_only)
-
- def __missing__(self, attrs):
- fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs
- parts = []
-
+
+ def __missing__(self, attrs):
+ fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs
+ parts = []
+
parts.extend(self._colors_to_code(fgcolor, bgcolor))
- if bold:
- parts.append('1')
- if italic:
- parts.append('3')
- if blink:
- parts.append('5')
- if underline:
- parts.append('4')
- if reverse:
- parts.append('7')
-
- if parts:
- result = '\x1b[0;' + ';'.join(parts) + 'm'
- else:
- result = '\x1b[0m'
-
- self[attrs] = result
- return result
-
+ if bold:
+ parts.append('1')
+ if italic:
+ parts.append('3')
+ if blink:
+ parts.append('5')
+ if underline:
+ parts.append('4')
+ if reverse:
+ parts.append('7')
+
+ if parts:
+ result = '\x1b[0;' + ';'.join(parts) + 'm'
+ else:
+ result = '\x1b[0m'
+
+ self[attrs] = result
+ return result
+
def _color_name_to_rgb(self, color):
" Turn 'ffffff', into (0xff, 0xff, 0xff). "
try:
@@ -282,35 +282,35 @@ class _EscapeCodeCache(dict):
except ValueError:
raise
else:
- r = (rgb >> 16) & 0xff
- g = (rgb >> 8) & 0xff
- b = rgb & 0xff
+ r = (rgb >> 16) & 0xff
+ g = (rgb >> 8) & 0xff
+ b = rgb & 0xff
return r, g, b
-
+
def _colors_to_code(self, fg_color, bg_color):
" Return a tuple with the vt100 values that represent this color. "
# When requesting ANSI colors only, and both fg/bg color were converted
# to ANSI, ensure that the foreground and background color are not the
# same. (Unless they were explicitely defined to be the same color.)
fg_ansi = [()]
-
+
def get(color, bg):
table = BG_ANSI_COLORS if bg else FG_ANSI_COLORS
-
+
if color is None:
return ()
-
+
# 16 ANSI colors. (Given by name.)
elif color in table:
return (table[color], )
-
+
# RGB colors. (Defined as 'ffffff'.)
else:
try:
rgb = self._color_name_to_rgb(color)
except ValueError:
return ()
-
+
# When only 16 colors are supported, use that.
if self.ansi_colors_only():
if bg: # Background.
@@ -324,7 +324,7 @@ class _EscapeCodeCache(dict):
code, name = _16_fg_colors.get_code(rgb)
fg_ansi[0] = name
return (code, )
-
+
# True colors. (Only when this feature is enabled.)
elif self.true_color:
r, g, b = rgb
@@ -341,44 +341,44 @@ class _EscapeCodeCache(dict):
return map(six.text_type, result)
-def _get_size(fileno):
- # Thanks to fabric (fabfile.org), and
- # http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/
- """
- Get the size of this pseudo terminal.
-
- :param fileno: stdout.fileno()
- :returns: A (rows, cols) tuple.
- """
- # Inline imports, because these modules are not available on Windows.
- # (This file is used by ConEmuOutput, which is used on Windows.)
- import fcntl
- import termios
-
- # Buffer for the C call
+def _get_size(fileno):
+ # Thanks to fabric (fabfile.org), and
+ # http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/
+ """
+ Get the size of this pseudo terminal.
+
+ :param fileno: stdout.fileno()
+ :returns: A (rows, cols) tuple.
+ """
+ # Inline imports, because these modules are not available on Windows.
+ # (This file is used by ConEmuOutput, which is used on Windows.)
+ import fcntl
+ import termios
+
+ # Buffer for the C call
buf = array.array(b'h' if six.PY2 else u'h', [0, 0, 0, 0])
-
- # Do TIOCGWINSZ (Get)
+
+ # Do TIOCGWINSZ (Get)
# Note: We should not pass 'True' as a fourth parameter to 'ioctl'. (True
# is the default.) This causes segmentation faults on some systems.
# See: https://github.com/jonathanslenders/python-prompt-toolkit/pull/364
fcntl.ioctl(fileno, termios.TIOCGWINSZ, buf)
-
- # Return rows, cols
- return buf[0], buf[1]
-
-
-class Vt100_Output(Output):
- """
- :param get_size: A callable which returns the `Size` of the output terminal.
+
+ # Return rows, cols
+ return buf[0], buf[1]
+
+
+class Vt100_Output(Output):
+ """
+ :param get_size: A callable which returns the `Size` of the output terminal.
:param stdout: Any object with has a `write` and `flush` method + an 'encoding' property.
- :param true_color: Use 24bit color instead of 256 colors. (Can be a :class:`SimpleFilter`.)
+ :param true_color: Use 24bit color instead of 256 colors. (Can be a :class:`SimpleFilter`.)
When `ansi_colors_only` is set, only 16 colors are used.
:param ansi_colors_only: Restrict to 16 ANSI colors only.
:param term: The terminal environment variable. (xterm, xterm-256color, linux, ...)
:param write_binary: Encode the output before writing it. If `True` (the
default), the `stdout` object is supposed to expose an `encoding` attribute.
- """
+ """
def __init__(self, stdout, get_size, true_color=False,
ansi_colors_only=None, term=None, write_binary=True):
assert callable(get_size)
@@ -388,13 +388,13 @@ class Vt100_Output(Output):
if write_binary:
assert hasattr(stdout, 'encoding')
- self._buffer = []
- self.stdout = stdout
+ self._buffer = []
+ self.stdout = stdout
self.write_binary = write_binary
- self.get_size = get_size
- self.true_color = to_simple_filter(true_color)
+ self.get_size = get_size
+ self.true_color = to_simple_filter(true_color)
self.term = term or 'xterm'
-
+
# ANSI colors only?
if ansi_colors_only is None:
# When not given, use the following default.
@@ -414,23 +414,23 @@ class Vt100_Output(Output):
self._escape_code_cache_true_color = _EscapeCodeCache(
true_color=True, ansi_colors_only=ansi_colors_only)
- @classmethod
+ @classmethod
def from_pty(cls, stdout, true_color=False, ansi_colors_only=None, term=None):
- """
- Create an Output class from a pseudo terminal.
- (This will take the dimensions by reading the pseudo
- terminal attributes.)
- """
+ """
+ Create an Output class from a pseudo terminal.
+ (This will take the dimensions by reading the pseudo
+ terminal attributes.)
+ """
assert stdout.isatty()
- def get_size():
- rows, columns = _get_size(stdout.fileno())
+ def get_size():
+ rows, columns = _get_size(stdout.fileno())
# If terminal (incorrectly) reports its size as 0, pick a reasonable default.
# See https://github.com/ipython/ipython/issues/10071
return Size(rows=(rows or 24), columns=(columns or 80))
-
+
return cls(stdout, get_size, true_color=true_color,
ansi_colors_only=ansi_colors_only, term=term)
-
+
def fileno(self):
" Return file descriptor. "
return self.stdout.fileno()
@@ -439,194 +439,194 @@ class Vt100_Output(Output):
" Return encoding used for stdout. "
return self.stdout.encoding
- def write_raw(self, data):
- """
- Write raw data to output.
- """
- self._buffer.append(data)
-
- def write(self, data):
- """
- Write text to output.
- (Removes vt100 escape codes. -- used for safely writing text.)
- """
- self._buffer.append(data.replace('\x1b', '?'))
-
- def set_title(self, title):
- """
- Set terminal title.
- """
+ def write_raw(self, data):
+ """
+ Write raw data to output.
+ """
+ self._buffer.append(data)
+
+ def write(self, data):
+ """
+ Write text to output.
+ (Removes vt100 escape codes. -- used for safely writing text.)
+ """
+ self._buffer.append(data.replace('\x1b', '?'))
+
+ def set_title(self, title):
+ """
+ Set terminal title.
+ """
if self.term not in ('linux', 'eterm-color'): # Not supported by the Linux console.
self.write_raw('\x1b]2;%s\x07' % title.replace('\x1b', '').replace('\x07', ''))
-
- def clear_title(self):
- self.set_title('')
-
- def erase_screen(self):
- """
- Erases the screen with the background colour and moves the cursor to
- home.
- """
- self.write_raw('\x1b[2J')
-
- def enter_alternate_screen(self):
- self.write_raw('\x1b[?1049h\x1b[H')
-
- def quit_alternate_screen(self):
- self.write_raw('\x1b[?1049l')
-
- def enable_mouse_support(self):
- self.write_raw('\x1b[?1000h')
-
- # Enable urxvt Mouse mode. (For terminals that understand this.)
- self.write_raw('\x1b[?1015h')
-
- # Also enable Xterm SGR mouse mode. (For terminals that understand this.)
- self.write_raw('\x1b[?1006h')
-
- # Note: E.g. lxterminal understands 1000h, but not the urxvt or sgr
- # extensions.
-
- def disable_mouse_support(self):
- self.write_raw('\x1b[?1000l')
- self.write_raw('\x1b[?1015l')
- self.write_raw('\x1b[?1006l')
-
- def erase_end_of_line(self):
- """
- Erases from the current cursor position to the end of the current line.
- """
- self.write_raw('\x1b[K')
-
- def erase_down(self):
- """
- Erases the screen from the current line down to the bottom of the
- screen.
- """
- self.write_raw('\x1b[J')
-
- def reset_attributes(self):
- self.write_raw('\x1b[0m')
-
- def set_attributes(self, attrs):
- """
- Create new style and output.
-
- :param attrs: `Attrs` instance.
- """
+
+ def clear_title(self):
+ self.set_title('')
+
+ def erase_screen(self):
+ """
+ Erases the screen with the background colour and moves the cursor to
+ home.
+ """
+ self.write_raw('\x1b[2J')
+
+ def enter_alternate_screen(self):
+ self.write_raw('\x1b[?1049h\x1b[H')
+
+ def quit_alternate_screen(self):
+ self.write_raw('\x1b[?1049l')
+
+ def enable_mouse_support(self):
+ self.write_raw('\x1b[?1000h')
+
+ # Enable urxvt Mouse mode. (For terminals that understand this.)
+ self.write_raw('\x1b[?1015h')
+
+ # Also enable Xterm SGR mouse mode. (For terminals that understand this.)
+ self.write_raw('\x1b[?1006h')
+
+ # Note: E.g. lxterminal understands 1000h, but not the urxvt or sgr
+ # extensions.
+
+ def disable_mouse_support(self):
+ self.write_raw('\x1b[?1000l')
+ self.write_raw('\x1b[?1015l')
+ self.write_raw('\x1b[?1006l')
+
+ def erase_end_of_line(self):
+ """
+ Erases from the current cursor position to the end of the current line.
+ """
+ self.write_raw('\x1b[K')
+
+ def erase_down(self):
+ """
+ Erases the screen from the current line down to the bottom of the
+ screen.
+ """
+ self.write_raw('\x1b[J')
+
+ def reset_attributes(self):
+ self.write_raw('\x1b[0m')
+
+ def set_attributes(self, attrs):
+ """
+ Create new style and output.
+
+ :param attrs: `Attrs` instance.
+ """
if self.true_color() and not self.ansi_colors_only():
self.write_raw(self._escape_code_cache_true_color[attrs])
- else:
+ else:
self.write_raw(self._escape_code_cache[attrs])
-
- def disable_autowrap(self):
- self.write_raw('\x1b[?7l')
-
- def enable_autowrap(self):
- self.write_raw('\x1b[?7h')
-
- def enable_bracketed_paste(self):
- self.write_raw('\x1b[?2004h')
-
- def disable_bracketed_paste(self):
- self.write_raw('\x1b[?2004l')
-
- def cursor_goto(self, row=0, column=0):
- """ Move cursor position. """
- self.write_raw('\x1b[%i;%iH' % (row, column))
-
- def cursor_up(self, amount):
- if amount == 0:
+
+ def disable_autowrap(self):
+ self.write_raw('\x1b[?7l')
+
+ def enable_autowrap(self):
+ self.write_raw('\x1b[?7h')
+
+ def enable_bracketed_paste(self):
+ self.write_raw('\x1b[?2004h')
+
+ def disable_bracketed_paste(self):
+ self.write_raw('\x1b[?2004l')
+
+ def cursor_goto(self, row=0, column=0):
+ """ Move cursor position. """
+ self.write_raw('\x1b[%i;%iH' % (row, column))
+
+ def cursor_up(self, amount):
+ if amount == 0:
pass
- elif amount == 1:
- self.write_raw('\x1b[A')
- else:
- self.write_raw('\x1b[%iA' % amount)
-
- def cursor_down(self, amount):
- if amount == 0:
+ elif amount == 1:
+ self.write_raw('\x1b[A')
+ else:
+ self.write_raw('\x1b[%iA' % amount)
+
+ def cursor_down(self, amount):
+ if amount == 0:
pass
- elif amount == 1:
- # Note: Not the same as '\n', '\n' can cause the window content to
- # scroll.
- self.write_raw('\x1b[B')
- else:
- self.write_raw('\x1b[%iB' % amount)
-
- def cursor_forward(self, amount):
- if amount == 0:
+ elif amount == 1:
+ # Note: Not the same as '\n', '\n' can cause the window content to
+ # scroll.
+ self.write_raw('\x1b[B')
+ else:
+ self.write_raw('\x1b[%iB' % amount)
+
+ def cursor_forward(self, amount):
+ if amount == 0:
pass
- elif amount == 1:
- self.write_raw('\x1b[C')
- else:
- self.write_raw('\x1b[%iC' % amount)
-
- def cursor_backward(self, amount):
- if amount == 0:
+ elif amount == 1:
+ self.write_raw('\x1b[C')
+ else:
+ self.write_raw('\x1b[%iC' % amount)
+
+ def cursor_backward(self, amount):
+ if amount == 0:
pass
- elif amount == 1:
- self.write_raw('\b') # '\x1b[D'
- else:
- self.write_raw('\x1b[%iD' % amount)
-
- def hide_cursor(self):
- self.write_raw('\x1b[?25l')
-
- def show_cursor(self):
- self.write_raw('\x1b[?12l\x1b[?25h') # Stop blinking cursor and show.
-
- def flush(self):
- """
- Write to output stream and flush.
- """
- if not self._buffer:
- return
-
- data = ''.join(self._buffer)
-
- try:
- # (We try to encode ourself, because that way we can replace
- # characters that don't exist in the character set, avoiding
- # UnicodeEncodeError crashes. E.g. u'\xb7' does not appear in 'ascii'.)
- # My Arch Linux installation of july 2015 reported 'ANSI_X3.4-1968'
- # for sys.stdout.encoding in xterm.
+ elif amount == 1:
+ self.write_raw('\b') # '\x1b[D'
+ else:
+ self.write_raw('\x1b[%iD' % amount)
+
+ def hide_cursor(self):
+ self.write_raw('\x1b[?25l')
+
+ def show_cursor(self):
+ self.write_raw('\x1b[?12l\x1b[?25h') # Stop blinking cursor and show.
+
+ def flush(self):
+ """
+ Write to output stream and flush.
+ """
+ if not self._buffer:
+ return
+
+ data = ''.join(self._buffer)
+
+ try:
+ # (We try to encode ourself, because that way we can replace
+ # characters that don't exist in the character set, avoiding
+ # UnicodeEncodeError crashes. E.g. u'\xb7' does not appear in 'ascii'.)
+ # My Arch Linux installation of july 2015 reported 'ANSI_X3.4-1968'
+ # for sys.stdout.encoding in xterm.
if self.write_binary:
if hasattr(self.stdout, 'buffer'):
out = self.stdout.buffer # Py3.
else:
out = self.stdout
- out.write(data.encode(self.stdout.encoding or 'utf-8', 'replace'))
- else:
- self.stdout.write(data)
-
- self.stdout.flush()
- except IOError as e:
- if e.args and e.args[0] == errno.EINTR:
- # Interrupted system call. Can happpen in case of a window
- # resize signal. (Just ignore. The resize handler will render
- # again anyway.)
- pass
- elif e.args and e.args[0] == 0:
- # This can happen when there is a lot of output and the user
- # sends a KeyboardInterrupt by pressing Control-C. E.g. in
- # a Python REPL when we execute "while True: print('test')".
- # (The `ptpython` REPL uses this `Output` class instead of
- # `stdout` directly -- in order to be network transparent.)
- # So, just ignore.
- pass
- else:
- raise
-
- self._buffer = []
-
- def ask_for_cpr(self):
- """
- Asks for a cursor position report (CPR).
- """
- self.write_raw('\x1b[6n')
- self.flush()
-
- def bell(self):
- " Sound bell. "
- self.write_raw('\a')
- self.flush()
+ out.write(data.encode(self.stdout.encoding or 'utf-8', 'replace'))
+ else:
+ self.stdout.write(data)
+
+ self.stdout.flush()
+ except IOError as e:
+ if e.args and e.args[0] == errno.EINTR:
+ # Interrupted system call. Can happpen in case of a window
+ # resize signal. (Just ignore. The resize handler will render
+ # again anyway.)
+ pass
+ elif e.args and e.args[0] == 0:
+ # This can happen when there is a lot of output and the user
+ # sends a KeyboardInterrupt by pressing Control-C. E.g. in
+ # a Python REPL when we execute "while True: print('test')".
+ # (The `ptpython` REPL uses this `Output` class instead of
+ # `stdout` directly -- in order to be network transparent.)
+ # So, just ignore.
+ pass
+ else:
+ raise
+
+ self._buffer = []
+
+ def ask_for_cpr(self):
+ """
+ Asks for a cursor position report (CPR).
+ """
+ self.write_raw('\x1b[6n')
+ self.flush()
+
+ def bell(self):
+ " Sound bell. "
+ self.write_raw('\a')
+ self.flush()
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py
index 708df868f9e..410e5fa517c 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_input.py
@@ -1,113 +1,113 @@
from __future__ import unicode_literals
-from ctypes import windll, pointer
+from ctypes import windll, pointer
from ctypes.wintypes import DWORD, HANDLE
from six.moves import range
-
-from prompt_toolkit.key_binding.input_processor import KeyPress
-from prompt_toolkit.keys import Keys
+
+from prompt_toolkit.key_binding.input_processor import KeyPress
+from prompt_toolkit.keys import Keys
from prompt_toolkit.mouse_events import MouseEventType
-from prompt_toolkit.win32_types import EventTypes, KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, INPUT_RECORD, STD_INPUT_HANDLE
-
+from prompt_toolkit.win32_types import EventTypes, KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, INPUT_RECORD, STD_INPUT_HANDLE
+
import msvcrt
import os
import sys
import six
-__all__ = (
- 'ConsoleInputReader',
- 'raw_mode',
- 'cooked_mode'
-)
-
-
-class ConsoleInputReader(object):
+__all__ = (
+ 'ConsoleInputReader',
+ 'raw_mode',
+ 'cooked_mode'
+)
+
+
+class ConsoleInputReader(object):
"""
:param recognize_paste: When True, try to discover paste actions and turn
the event into a BracketedPaste.
"""
- # Keys with character data.
- mappings = {
- b'\x1b': Keys.Escape,
-
- b'\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
- b'\x01': Keys.ControlA, # Control-A (home)
- b'\x02': Keys.ControlB, # Control-B (emacs cursor left)
- b'\x03': Keys.ControlC, # Control-C (interrupt)
- b'\x04': Keys.ControlD, # Control-D (exit)
- b'\x05': Keys.ControlE, # Contrel-E (end)
- b'\x06': Keys.ControlF, # Control-F (cursor forward)
- b'\x07': Keys.ControlG, # Control-G
- b'\x08': Keys.ControlH, # Control-H (8) (Identical to '\b')
- b'\x09': Keys.ControlI, # Control-I (9) (Identical to '\t')
- b'\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n')
- b'\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab)
- b'\x0c': Keys.ControlL, # Control-L (clear; form feed)
- b'\x0d': Keys.ControlJ, # Control-J NOTE: Windows sends \r instead of
- # \n when pressing enter. We turn it into \n
- # to be compatible with other platforms.
- b'\x0e': Keys.ControlN, # Control-N (14) (history forward)
- b'\x0f': Keys.ControlO, # Control-O (15)
- b'\x10': Keys.ControlP, # Control-P (16) (history back)
- b'\x11': Keys.ControlQ, # Control-Q
- b'\x12': Keys.ControlR, # Control-R (18) (reverse search)
- b'\x13': Keys.ControlS, # Control-S (19) (forward search)
- b'\x14': Keys.ControlT, # Control-T
- b'\x15': Keys.ControlU, # Control-U
- b'\x16': Keys.ControlV, # Control-V
- b'\x17': Keys.ControlW, # Control-W
- b'\x18': Keys.ControlX, # Control-X
- b'\x19': Keys.ControlY, # Control-Y (25)
- b'\x1a': Keys.ControlZ, # Control-Z
-
- b'\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-|
- b'\x1d': Keys.ControlSquareClose, # Control-]
- b'\x1e': Keys.ControlCircumflex, # Control-^
- b'\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
- b'\x7f': Keys.Backspace, # (127) Backspace
- }
-
- # Keys that don't carry character data.
- keycodes = {
- # Home/End
- 33: Keys.PageUp,
- 34: Keys.PageDown,
- 35: Keys.End,
- 36: Keys.Home,
-
- # Arrows
- 37: Keys.Left,
- 38: Keys.Up,
- 39: Keys.Right,
- 40: Keys.Down,
-
- 45: Keys.Insert,
- 46: Keys.Delete,
-
- # F-keys.
- 112: Keys.F1,
- 113: Keys.F2,
- 114: Keys.F3,
- 115: Keys.F4,
- 116: Keys.F5,
- 117: Keys.F6,
- 118: Keys.F7,
- 119: Keys.F8,
- 120: Keys.F9,
- 121: Keys.F10,
- 122: Keys.F11,
- 123: Keys.F12,
- }
-
- LEFT_ALT_PRESSED = 0x0002
- RIGHT_ALT_PRESSED = 0x0001
- SHIFT_PRESSED = 0x0010
- LEFT_CTRL_PRESSED = 0x0008
- RIGHT_CTRL_PRESSED = 0x0004
-
+ # Keys with character data.
+ mappings = {
+ b'\x1b': Keys.Escape,
+
+ b'\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
+ b'\x01': Keys.ControlA, # Control-A (home)
+ b'\x02': Keys.ControlB, # Control-B (emacs cursor left)
+ b'\x03': Keys.ControlC, # Control-C (interrupt)
+ b'\x04': Keys.ControlD, # Control-D (exit)
+ b'\x05': Keys.ControlE, # Contrel-E (end)
+ b'\x06': Keys.ControlF, # Control-F (cursor forward)
+ b'\x07': Keys.ControlG, # Control-G
+ b'\x08': Keys.ControlH, # Control-H (8) (Identical to '\b')
+ b'\x09': Keys.ControlI, # Control-I (9) (Identical to '\t')
+ b'\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n')
+ b'\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab)
+ b'\x0c': Keys.ControlL, # Control-L (clear; form feed)
+ b'\x0d': Keys.ControlJ, # Control-J NOTE: Windows sends \r instead of
+ # \n when pressing enter. We turn it into \n
+ # to be compatible with other platforms.
+ b'\x0e': Keys.ControlN, # Control-N (14) (history forward)
+ b'\x0f': Keys.ControlO, # Control-O (15)
+ b'\x10': Keys.ControlP, # Control-P (16) (history back)
+ b'\x11': Keys.ControlQ, # Control-Q
+ b'\x12': Keys.ControlR, # Control-R (18) (reverse search)
+ b'\x13': Keys.ControlS, # Control-S (19) (forward search)
+ b'\x14': Keys.ControlT, # Control-T
+ b'\x15': Keys.ControlU, # Control-U
+ b'\x16': Keys.ControlV, # Control-V
+ b'\x17': Keys.ControlW, # Control-W
+ b'\x18': Keys.ControlX, # Control-X
+ b'\x19': Keys.ControlY, # Control-Y (25)
+ b'\x1a': Keys.ControlZ, # Control-Z
+
+ b'\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-|
+ b'\x1d': Keys.ControlSquareClose, # Control-]
+ b'\x1e': Keys.ControlCircumflex, # Control-^
+ b'\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
+ b'\x7f': Keys.Backspace, # (127) Backspace
+ }
+
+ # Keys that don't carry character data.
+ keycodes = {
+ # Home/End
+ 33: Keys.PageUp,
+ 34: Keys.PageDown,
+ 35: Keys.End,
+ 36: Keys.Home,
+
+ # Arrows
+ 37: Keys.Left,
+ 38: Keys.Up,
+ 39: Keys.Right,
+ 40: Keys.Down,
+
+ 45: Keys.Insert,
+ 46: Keys.Delete,
+
+ # F-keys.
+ 112: Keys.F1,
+ 113: Keys.F2,
+ 114: Keys.F3,
+ 115: Keys.F4,
+ 116: Keys.F5,
+ 117: Keys.F6,
+ 118: Keys.F7,
+ 119: Keys.F8,
+ 120: Keys.F9,
+ 121: Keys.F10,
+ 122: Keys.F11,
+ 123: Keys.F12,
+ }
+
+ LEFT_ALT_PRESSED = 0x0002
+ RIGHT_ALT_PRESSED = 0x0001
+ SHIFT_PRESSED = 0x0010
+ LEFT_CTRL_PRESSED = 0x0008
+ RIGHT_CTRL_PRESSED = 0x0004
+
def __init__(self, recognize_paste=True):
self._fdcon = None
self.recognize_paste = recognize_paste
-
+
# When stdin is a tty, use that handle, otherwise, create a handle from
# CONIN$.
if sys.stdin.isatty():
@@ -121,23 +121,23 @@ class ConsoleInputReader(object):
if self._fdcon is not None:
os.close(self._fdcon)
- def read(self):
- """
+ def read(self):
+ """
Return a list of `KeyPress` instances. It won't return anything when
there was nothing to read. (This function doesn't block.)
-
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
- """
+
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
+ """
max_count = 2048 # Max events to read at the same time.
-
- read = DWORD(0)
- arrtype = INPUT_RECORD * max_count
- input_records = arrtype()
-
- # Get next batch of input event.
+
+ read = DWORD(0)
+ arrtype = INPUT_RECORD * max_count
+ input_records = arrtype()
+
+ # Get next batch of input event.
windll.kernel32.ReadConsoleInputW(
self.handle, pointer(input_records), max_count, pointer(read))
-
+
# First, get all the keys from the input buffer, in order to determine
# whether we should consider this a paste event or not.
all_keys = list(self._get_keys(read, input_records))
@@ -168,26 +168,26 @@ class ConsoleInputReader(object):
"""
Generator that yields `KeyPress` objects from the input records.
"""
- for i in range(read.value):
- ir = input_records[i]
-
- # Get the right EventType from the EVENT_RECORD.
- # (For some reason the Windows console application 'cmder'
- # [http://gooseberrycreative.com/cmder/] can return '0' for
- # ir.EventType. -- Just ignore that.)
- if ir.EventType in EventTypes:
- ev = getattr(ir.Event, EventTypes[ir.EventType])
-
- # Process if this is a key event. (We also have mouse, menu and
- # focus events.)
- if type(ev) == KEY_EVENT_RECORD and ev.KeyDown:
+ for i in range(read.value):
+ ir = input_records[i]
+
+ # Get the right EventType from the EVENT_RECORD.
+ # (For some reason the Windows console application 'cmder'
+ # [http://gooseberrycreative.com/cmder/] can return '0' for
+ # ir.EventType. -- Just ignore that.)
+ if ir.EventType in EventTypes:
+ ev = getattr(ir.Event, EventTypes[ir.EventType])
+
+ # Process if this is a key event. (We also have mouse, menu and
+ # focus events.)
+ if type(ev) == KEY_EVENT_RECORD and ev.KeyDown:
for key_press in self._event_to_key_presses(ev):
yield key_press
-
- elif type(ev) == MOUSE_EVENT_RECORD:
+
+ elif type(ev) == MOUSE_EVENT_RECORD:
for key_press in self._handle_mouse(ev):
yield key_press
-
+
@staticmethod
def _is_paste(keys):
"""
@@ -201,7 +201,7 @@ class ConsoleInputReader(object):
# other character.
text_count = 0
newline_count = 0
-
+
for k in keys:
if isinstance(k.key, six.text_type):
text_count += 1
@@ -210,155 +210,155 @@ class ConsoleInputReader(object):
return newline_count >= 1 and text_count > 1
- def _event_to_key_presses(self, ev):
- """
- For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances.
- """
- assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown
-
- result = None
-
- u_char = ev.uChar.UnicodeChar
+ def _event_to_key_presses(self, ev):
+ """
+ For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances.
+ """
+ assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown
+
+ result = None
+
+ u_char = ev.uChar.UnicodeChar
ascii_char = u_char.encode('utf-8')
-
+
# NOTE: We don't use `ev.uChar.AsciiChar`. That appears to be latin-1
# encoded. See also:
# https://github.com/ipython/ipython/issues/10004
# https://github.com/jonathanslenders/python-prompt-toolkit/issues/389
- if u_char == '\x00':
- if ev.VirtualKeyCode in self.keycodes:
- result = KeyPress(self.keycodes[ev.VirtualKeyCode], '')
- else:
- if ascii_char in self.mappings:
+ if u_char == '\x00':
+ if ev.VirtualKeyCode in self.keycodes:
+ result = KeyPress(self.keycodes[ev.VirtualKeyCode], '')
+ else:
+ if ascii_char in self.mappings:
if self.mappings[ascii_char] == Keys.ControlJ:
u_char = '\n' # Windows sends \n, turn into \r for unix compatibility.
- result = KeyPress(self.mappings[ascii_char], u_char)
- else:
- result = KeyPress(u_char, u_char)
-
- # Correctly handle Control-Arrow keys.
- if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
- ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result:
- if result.key == Keys.Left:
- result.key = Keys.ControlLeft
-
- if result.key == Keys.Right:
- result.key = Keys.ControlRight
-
- if result.key == Keys.Up:
- result.key = Keys.ControlUp
-
- if result.key == Keys.Down:
- result.key = Keys.ControlDown
-
- # Turn 'Tab' into 'BackTab' when shift was pressed.
- if ev.ControlKeyState & self.SHIFT_PRESSED and result:
- if result.key == Keys.Tab:
- result.key = Keys.BackTab
-
- # Turn 'Space' into 'ControlSpace' when control was pressed.
- if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
- ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and result.data == ' ':
- result = KeyPress(Keys.ControlSpace, ' ')
-
- # Turn Control-Enter into META-Enter. (On a vt100 terminal, we cannot
- # detect this combination. But it's really practical on Windows.)
- if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
- ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and \
- result.key == Keys.ControlJ:
- return [KeyPress(Keys.Escape, ''), result]
-
- # Return result. If alt was pressed, prefix the result with an
- # 'Escape' key, just like unix VT100 terminals do.
-
- # NOTE: Only replace the left alt with escape. The right alt key often
- # acts as altgr and is used in many non US keyboard layouts for
- # typing some special characters, like a backslash. We don't want
- # all backslashes to be prefixed with escape. (Esc-\ has a
- # meaning in E-macs, for instance.)
- if result:
- meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED
-
- if meta_pressed:
- return [KeyPress(Keys.Escape, ''), result]
- else:
- return [result]
-
- else:
- return []
-
- def _handle_mouse(self, ev):
- """
- Handle mouse events. Return a list of KeyPress instances.
- """
- FROM_LEFT_1ST_BUTTON_PRESSED = 0x1
-
- result = []
-
- # Check event type.
- if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED:
- # On a key press, generate both the mouse down and up event.
+ result = KeyPress(self.mappings[ascii_char], u_char)
+ else:
+ result = KeyPress(u_char, u_char)
+
+ # Correctly handle Control-Arrow keys.
+ if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
+ ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result:
+ if result.key == Keys.Left:
+ result.key = Keys.ControlLeft
+
+ if result.key == Keys.Right:
+ result.key = Keys.ControlRight
+
+ if result.key == Keys.Up:
+ result.key = Keys.ControlUp
+
+ if result.key == Keys.Down:
+ result.key = Keys.ControlDown
+
+ # Turn 'Tab' into 'BackTab' when shift was pressed.
+ if ev.ControlKeyState & self.SHIFT_PRESSED and result:
+ if result.key == Keys.Tab:
+ result.key = Keys.BackTab
+
+ # Turn 'Space' into 'ControlSpace' when control was pressed.
+ if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
+ ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and result.data == ' ':
+ result = KeyPress(Keys.ControlSpace, ' ')
+
+ # Turn Control-Enter into META-Enter. (On a vt100 terminal, we cannot
+ # detect this combination. But it's really practical on Windows.)
+ if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or
+ ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and \
+ result.key == Keys.ControlJ:
+ return [KeyPress(Keys.Escape, ''), result]
+
+ # Return result. If alt was pressed, prefix the result with an
+ # 'Escape' key, just like unix VT100 terminals do.
+
+ # NOTE: Only replace the left alt with escape. The right alt key often
+ # acts as altgr and is used in many non US keyboard layouts for
+ # typing some special characters, like a backslash. We don't want
+ # all backslashes to be prefixed with escape. (Esc-\ has a
+ # meaning in E-macs, for instance.)
+ if result:
+ meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED
+
+ if meta_pressed:
+ return [KeyPress(Keys.Escape, ''), result]
+ else:
+ return [result]
+
+ else:
+ return []
+
+ def _handle_mouse(self, ev):
+ """
+ Handle mouse events. Return a list of KeyPress instances.
+ """
+ FROM_LEFT_1ST_BUTTON_PRESSED = 0x1
+
+ result = []
+
+ # Check event type.
+ if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED:
+ # On a key press, generate both the mouse down and up event.
for event_type in [MouseEventType.MOUSE_DOWN, MouseEventType.MOUSE_UP]:
- data = ';'.join([
- event_type,
- str(ev.MousePosition.X),
- str(ev.MousePosition.Y)
- ])
- result.append(KeyPress(Keys.WindowsMouseEvent, data))
-
- return result
-
-
-class raw_mode(object):
- """
- ::
-
- with raw_mode(stdin):
- ''' the windows terminal is now in 'raw' mode. '''
-
- The ``fileno`` attribute is ignored. This is to be compatble with the
- `raw_input` method of `.vt100_input`.
- """
- def __init__(self, fileno=None):
+ data = ';'.join([
+ event_type,
+ str(ev.MousePosition.X),
+ str(ev.MousePosition.Y)
+ ])
+ result.append(KeyPress(Keys.WindowsMouseEvent, data))
+
+ return result
+
+
+class raw_mode(object):
+ """
+ ::
+
+ with raw_mode(stdin):
+ ''' the windows terminal is now in 'raw' mode. '''
+
+ The ``fileno`` attribute is ignored. This is to be compatble with the
+ `raw_input` method of `.vt100_input`.
+ """
+ def __init__(self, fileno=None):
self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
-
- def __enter__(self):
- # Remember original mode.
- original_mode = DWORD()
- windll.kernel32.GetConsoleMode(self.handle, pointer(original_mode))
- self.original_mode = original_mode
-
- self._patch()
-
- def _patch(self):
- # Set raw
- ENABLE_ECHO_INPUT = 0x0004
- ENABLE_LINE_INPUT = 0x0002
- ENABLE_PROCESSED_INPUT = 0x0001
-
- windll.kernel32.SetConsoleMode(
- self.handle, self.original_mode.value &
- ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT))
-
- def __exit__(self, *a, **kw):
- # Restore original mode
- windll.kernel32.SetConsoleMode(self.handle, self.original_mode)
-
-
-class cooked_mode(raw_mode):
- """
- ::
-
- with cooked_mode(stdin):
- ''' the pseudo-terminal stdin is now used in raw mode '''
- """
- def _patch(self):
- # Set cooked.
- ENABLE_ECHO_INPUT = 0x0004
- ENABLE_LINE_INPUT = 0x0002
- ENABLE_PROCESSED_INPUT = 0x0001
-
- windll.kernel32.SetConsoleMode(
- self.handle, self.original_mode.value |
- (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT))
+
+ def __enter__(self):
+ # Remember original mode.
+ original_mode = DWORD()
+ windll.kernel32.GetConsoleMode(self.handle, pointer(original_mode))
+ self.original_mode = original_mode
+
+ self._patch()
+
+ def _patch(self):
+ # Set raw
+ ENABLE_ECHO_INPUT = 0x0004
+ ENABLE_LINE_INPUT = 0x0002
+ ENABLE_PROCESSED_INPUT = 0x0001
+
+ windll.kernel32.SetConsoleMode(
+ self.handle, self.original_mode.value &
+ ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT))
+
+ def __exit__(self, *a, **kw):
+ # Restore original mode
+ windll.kernel32.SetConsoleMode(self.handle, self.original_mode)
+
+
+class cooked_mode(raw_mode):
+ """
+ ::
+
+ with cooked_mode(stdin):
+ ''' the pseudo-terminal stdin is now used in raw mode '''
+ """
+ def _patch(self):
+ # Set cooked.
+ ENABLE_ECHO_INPUT = 0x0004
+ ENABLE_LINE_INPUT = 0x0002
+ ENABLE_PROCESSED_INPUT = 0x0001
+
+ windll.kernel32.SetConsoleMode(
+ self.handle, self.original_mode.value |
+ (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT))
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py
index 4ed5beb8aa9..d4dddbab427 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/terminal/win32_output.py
@@ -1,45 +1,45 @@
-from __future__ import unicode_literals
-
-from ctypes import windll, byref, ArgumentError, c_char, c_long, c_ulong, c_uint, pointer
+from __future__ import unicode_literals
+
+from ctypes import windll, byref, ArgumentError, c_char, c_long, c_ulong, c_uint, pointer
from ctypes.wintypes import DWORD, HANDLE
-
-from prompt_toolkit.renderer import Output
-from prompt_toolkit.styles import ANSI_COLOR_NAMES
-from prompt_toolkit.win32_types import CONSOLE_SCREEN_BUFFER_INFO, STD_OUTPUT_HANDLE, STD_INPUT_HANDLE, COORD, SMALL_RECT
-
+
+from prompt_toolkit.renderer import Output
+from prompt_toolkit.styles import ANSI_COLOR_NAMES
+from prompt_toolkit.win32_types import CONSOLE_SCREEN_BUFFER_INFO, STD_OUTPUT_HANDLE, STD_INPUT_HANDLE, COORD, SMALL_RECT
+
import os
-import six
-
-__all__ = (
- 'Win32Output',
-)
-
-
-def _coord_byval(coord):
- """
- Turns a COORD object into a c_long.
- This will cause it to be passed by value instead of by reference. (That is what I think at least.)
-
- When runing ``ptipython`` is run (only with IPython), we often got the following error::
-
- Error in 'SetConsoleCursorPosition'.
- ArgumentError("argument 2: <class 'TypeError'>: wrong type",)
- argument 2: <class 'TypeError'>: wrong type
-
- It was solved by turning ``COORD`` parameters into a ``c_long`` like this.
-
- More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx
- """
- return c_long(coord.Y * 0x10000 | coord.X & 0xFFFF)
-
-
-#: If True: write the output of the renderer also to the following file. This
-#: is very useful for debugging. (e.g.: to see that we don't write more bytes
-#: than required.)
-_DEBUG_RENDER_OUTPUT = False
-_DEBUG_RENDER_OUTPUT_FILENAME = r'prompt-toolkit-windows-output.log'
-
-
+import six
+
+__all__ = (
+ 'Win32Output',
+)
+
+
+def _coord_byval(coord):
+ """
+ Turns a COORD object into a c_long.
+ This will cause it to be passed by value instead of by reference. (That is what I think at least.)
+
+ When runing ``ptipython`` is run (only with IPython), we often got the following error::
+
+ Error in 'SetConsoleCursorPosition'.
+ ArgumentError("argument 2: <class 'TypeError'>: wrong type",)
+ argument 2: <class 'TypeError'>: wrong type
+
+ It was solved by turning ``COORD`` parameters into a ``c_long`` like this.
+
+ More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx
+ """
+ return c_long(coord.Y * 0x10000 | coord.X & 0xFFFF)
+
+
+#: If True: write the output of the renderer also to the following file. This
+#: is very useful for debugging. (e.g.: to see that we don't write more bytes
+#: than required.)
+_DEBUG_RENDER_OUTPUT = False
+_DEBUG_RENDER_OUTPUT_FILENAME = r'prompt-toolkit-windows-output.log'
+
+
class NoConsoleScreenBufferError(Exception):
"""
Raised when the application is not running inside a Windows Console, but
@@ -60,29 +60,29 @@ class NoConsoleScreenBufferError(Exception):
super(NoConsoleScreenBufferError, self).__init__(message)
-class Win32Output(Output):
- """
- I/O abstraction for rendering to Windows consoles.
- (cmd.exe and similar.)
- """
- def __init__(self, stdout, use_complete_width=False):
- self.use_complete_width = use_complete_width
-
- self._buffer = []
- self.stdout = stdout
+class Win32Output(Output):
+ """
+ I/O abstraction for rendering to Windows consoles.
+ (cmd.exe and similar.)
+ """
+ def __init__(self, stdout, use_complete_width=False):
+ self.use_complete_width = use_complete_width
+
+ self._buffer = []
+ self.stdout = stdout
self.hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
-
- self._in_alternate_screen = False
-
- self.color_lookup_table = ColorLookupTable()
-
+
+ self._in_alternate_screen = False
+
+ self.color_lookup_table = ColorLookupTable()
+
# Remember the default console colors.
info = self.get_win32_screen_buffer_info()
self.default_attrs = info.wAttributes if info else 15
- if _DEBUG_RENDER_OUTPUT:
- self.LOG = open(_DEBUG_RENDER_OUTPUT_FILENAME, 'ab')
-
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG = open(_DEBUG_RENDER_OUTPUT_FILENAME, 'ab')
+
def fileno(self):
" Return file descriptor. "
return self.stdout.fileno()
@@ -91,56 +91,56 @@ class Win32Output(Output):
" Return encoding used for stdout. "
return self.stdout.encoding
- def write(self, data):
- self._buffer.append(data)
-
- def write_raw(self, data):
- " For win32, there is no difference between write and write_raw. "
- self.write(data)
-
- def get_size(self):
- from prompt_toolkit.layout.screen import Size
- info = self.get_win32_screen_buffer_info()
-
- # We take the width of the *visible* region as the size. Not the width
- # of the complete screen buffer. (Unless use_complete_width has been
- # set.)
- if self.use_complete_width:
- width = info.dwSize.X
- else:
- width = info.srWindow.Right - info.srWindow.Left
-
- height = info.srWindow.Bottom - info.srWindow.Top + 1
-
- # We avoid the right margin, windows will wrap otherwise.
- maxwidth = info.dwSize.X - 1
- width = min(maxwidth, width)
-
- # Create `Size` object.
- return Size(rows=height, columns=width)
-
- def _winapi(self, func, *a, **kw):
- """
- Flush and call win API function.
- """
- self.flush()
-
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write(('%r' % func.__name__).encode('utf-8') + b'\n')
- self.LOG.write(b' ' + ', '.join(['%r' % i for i in a]).encode('utf-8') + b'\n')
- self.LOG.write(b' ' + ', '.join(['%r' % type(i) for i in a]).encode('utf-8') + b'\n')
- self.LOG.flush()
-
- try:
- return func(*a, **kw)
- except ArgumentError as e:
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write((' Error in %r %r %s\n' % (func.__name__, e, e)).encode('utf-8'))
-
- def get_win32_screen_buffer_info(self):
- """
- Return Screen buffer info.
- """
+ def write(self, data):
+ self._buffer.append(data)
+
+ def write_raw(self, data):
+ " For win32, there is no difference between write and write_raw. "
+ self.write(data)
+
+ def get_size(self):
+ from prompt_toolkit.layout.screen import Size
+ info = self.get_win32_screen_buffer_info()
+
+ # We take the width of the *visible* region as the size. Not the width
+ # of the complete screen buffer. (Unless use_complete_width has been
+ # set.)
+ if self.use_complete_width:
+ width = info.dwSize.X
+ else:
+ width = info.srWindow.Right - info.srWindow.Left
+
+ height = info.srWindow.Bottom - info.srWindow.Top + 1
+
+ # We avoid the right margin, windows will wrap otherwise.
+ maxwidth = info.dwSize.X - 1
+ width = min(maxwidth, width)
+
+ # Create `Size` object.
+ return Size(rows=height, columns=width)
+
+ def _winapi(self, func, *a, **kw):
+ """
+ Flush and call win API function.
+ """
+ self.flush()
+
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write(('%r' % func.__name__).encode('utf-8') + b'\n')
+ self.LOG.write(b' ' + ', '.join(['%r' % i for i in a]).encode('utf-8') + b'\n')
+ self.LOG.write(b' ' + ', '.join(['%r' % type(i) for i in a]).encode('utf-8') + b'\n')
+ self.LOG.flush()
+
+ try:
+ return func(*a, **kw)
+ except ArgumentError as e:
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write((' Error in %r %r %s\n' % (func.__name__, e, e)).encode('utf-8'))
+
+ def get_win32_screen_buffer_info(self):
+ """
+ Return Screen buffer info.
+ """
# NOTE: We don't call the `GetConsoleScreenBufferInfo` API through
# `self._winapi`. Doing so causes Python to crash on certain 64bit
# Python versions. (Reproduced with 64bit Python 2.7.6, on Windows
@@ -160,74 +160,74 @@ class Win32Output(Output):
# - https://github.com/jonathanslenders/python-prompt-toolkit/issues/86
self.flush()
- sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+ sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
success = windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))
# success = self._winapi(windll.kernel32.GetConsoleScreenBufferInfo,
# self.hconsole, byref(sbinfo))
- if success:
- return sbinfo
+ if success:
+ return sbinfo
else:
raise NoConsoleScreenBufferError
-
- def set_title(self, title):
- """
- Set terminal title.
- """
- assert isinstance(title, six.text_type)
- self._winapi(windll.kernel32.SetConsoleTitleW, title)
-
- def clear_title(self):
- self._winapi(windll.kernel32.SetConsoleTitleW, '')
-
- def erase_screen(self):
- start = COORD(0, 0)
- sbinfo = self.get_win32_screen_buffer_info()
- length = sbinfo.dwSize.X * sbinfo.dwSize.Y
-
- self.cursor_goto(row=0, column=0)
- self._erase(start, length)
-
- def erase_down(self):
- sbinfo = self.get_win32_screen_buffer_info()
- size = sbinfo.dwSize
-
- start = sbinfo.dwCursorPosition
- length = ((size.X - size.X) + size.X * (size.Y - sbinfo.dwCursorPosition.Y))
-
- self._erase(start, length)
-
- def erase_end_of_line(self):
- """
- """
- sbinfo = self.get_win32_screen_buffer_info()
- start = sbinfo.dwCursorPosition
- length = sbinfo.dwSize.X - sbinfo.dwCursorPosition.X
-
- self._erase(start, length)
-
- def _erase(self, start, length):
- chars_written = c_ulong()
-
- self._winapi(windll.kernel32.FillConsoleOutputCharacterA,
- self.hconsole, c_char(b' '), DWORD(length), _coord_byval(start),
- byref(chars_written))
-
- # Reset attributes.
- sbinfo = self.get_win32_screen_buffer_info()
- self._winapi(windll.kernel32.FillConsoleOutputAttribute,
- self.hconsole, sbinfo.wAttributes, length, _coord_byval(start),
- byref(chars_written))
-
- def reset_attributes(self):
+
+ def set_title(self, title):
+ """
+ Set terminal title.
+ """
+ assert isinstance(title, six.text_type)
+ self._winapi(windll.kernel32.SetConsoleTitleW, title)
+
+ def clear_title(self):
+ self._winapi(windll.kernel32.SetConsoleTitleW, '')
+
+ def erase_screen(self):
+ start = COORD(0, 0)
+ sbinfo = self.get_win32_screen_buffer_info()
+ length = sbinfo.dwSize.X * sbinfo.dwSize.Y
+
+ self.cursor_goto(row=0, column=0)
+ self._erase(start, length)
+
+ def erase_down(self):
+ sbinfo = self.get_win32_screen_buffer_info()
+ size = sbinfo.dwSize
+
+ start = sbinfo.dwCursorPosition
+ length = ((size.X - size.X) + size.X * (size.Y - sbinfo.dwCursorPosition.Y))
+
+ self._erase(start, length)
+
+ def erase_end_of_line(self):
+ """
+ """
+ sbinfo = self.get_win32_screen_buffer_info()
+ start = sbinfo.dwCursorPosition
+ length = sbinfo.dwSize.X - sbinfo.dwCursorPosition.X
+
+ self._erase(start, length)
+
+ def _erase(self, start, length):
+ chars_written = c_ulong()
+
+ self._winapi(windll.kernel32.FillConsoleOutputCharacterA,
+ self.hconsole, c_char(b' '), DWORD(length), _coord_byval(start),
+ byref(chars_written))
+
+ # Reset attributes.
+ sbinfo = self.get_win32_screen_buffer_info()
+ self._winapi(windll.kernel32.FillConsoleOutputAttribute,
+ self.hconsole, sbinfo.wAttributes, length, _coord_byval(start),
+ byref(chars_written))
+
+ def reset_attributes(self):
" Reset the console foreground/background color. "
self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole,
self.default_attrs)
-
- def set_attributes(self, attrs):
- fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs
-
+
+ def set_attributes(self, attrs):
+ fgcolor, bgcolor, bold, underline, italic, blink, reverse = attrs
+
# Start from the default attributes.
attrs = self.default_attrs
@@ -242,306 +242,306 @@ class Win32Output(Output):
attrs |= self.color_lookup_table.lookup_bg_color(bgcolor)
# Reverse: swap these four bits groups.
- if reverse:
+ if reverse:
attrs = (attrs & ~0xff) | ((attrs & 0xf) << 4) | ((attrs & 0xf0) >> 4)
-
+
self._winapi(windll.kernel32.SetConsoleTextAttribute, self.hconsole, attrs)
-
- def disable_autowrap(self):
- # Not supported by Windows.
- pass
-
- def enable_autowrap(self):
- # Not supported by Windows.
- pass
-
- def cursor_goto(self, row=0, column=0):
- pos = COORD(x=column, y=row)
- self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
-
- def cursor_up(self, amount):
- sr = self.get_win32_screen_buffer_info().dwCursorPosition
- pos = COORD(sr.X, sr.Y - amount)
- self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
-
- def cursor_down(self, amount):
- self.cursor_up(-amount)
-
- def cursor_forward(self, amount):
- sr = self.get_win32_screen_buffer_info().dwCursorPosition
-# assert sr.X + amount >= 0, 'Negative cursor position: x=%r amount=%r' % (sr.X, amount)
-
- pos = COORD(max(0, sr.X + amount), sr.Y)
- self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
-
- def cursor_backward(self, amount):
- self.cursor_forward(-amount)
-
- def flush(self):
- """
- Write to output stream and flush.
- """
- if not self._buffer:
- # Only flush stdout buffer. (It could be that Python still has
- # something in its buffer. -- We want to be sure to print that in
- # the correct color.)
- self.stdout.flush()
- return
-
- data = ''.join(self._buffer)
-
- if _DEBUG_RENDER_OUTPUT:
- self.LOG.write(('%r' % data).encode('utf-8') + b'\n')
- self.LOG.flush()
-
- # Print characters one by one. This appears to be the best soluton
- # in oder to avoid traces of vertical lines when the completion
- # menu disappears.
- for b in data:
- written = DWORD()
-
- retval = windll.kernel32.WriteConsoleW(self.hconsole, b, 1, byref(written), None)
- assert retval != 0
-
- self._buffer = []
-
- def get_rows_below_cursor_position(self):
- info = self.get_win32_screen_buffer_info()
- return info.srWindow.Bottom - info.dwCursorPosition.Y + 1
-
- def scroll_buffer_to_prompt(self):
- """
- To be called before drawing the prompt. This should scroll the console
- to left, with the cursor at the bottom (if possible).
- """
- # Get current window size
- info = self.get_win32_screen_buffer_info()
- sr = info.srWindow
- cursor_pos = info.dwCursorPosition
-
- result = SMALL_RECT()
-
- # Scroll to the left.
- result.Left = 0
- result.Right = sr.Right - sr.Left
-
- # Scroll vertical
- win_height = sr.Bottom - sr.Top
+
+ def disable_autowrap(self):
+ # Not supported by Windows.
+ pass
+
+ def enable_autowrap(self):
+ # Not supported by Windows.
+ pass
+
+ def cursor_goto(self, row=0, column=0):
+ pos = COORD(x=column, y=row)
+ self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
+
+ def cursor_up(self, amount):
+ sr = self.get_win32_screen_buffer_info().dwCursorPosition
+ pos = COORD(sr.X, sr.Y - amount)
+ self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
+
+ def cursor_down(self, amount):
+ self.cursor_up(-amount)
+
+ def cursor_forward(self, amount):
+ sr = self.get_win32_screen_buffer_info().dwCursorPosition
+# assert sr.X + amount >= 0, 'Negative cursor position: x=%r amount=%r' % (sr.X, amount)
+
+ pos = COORD(max(0, sr.X + amount), sr.Y)
+ self._winapi(windll.kernel32.SetConsoleCursorPosition, self.hconsole, _coord_byval(pos))
+
+ def cursor_backward(self, amount):
+ self.cursor_forward(-amount)
+
+ def flush(self):
+ """
+ Write to output stream and flush.
+ """
+ if not self._buffer:
+ # Only flush stdout buffer. (It could be that Python still has
+ # something in its buffer. -- We want to be sure to print that in
+ # the correct color.)
+ self.stdout.flush()
+ return
+
+ data = ''.join(self._buffer)
+
+ if _DEBUG_RENDER_OUTPUT:
+ self.LOG.write(('%r' % data).encode('utf-8') + b'\n')
+ self.LOG.flush()
+
+ # Print characters one by one. This appears to be the best soluton
+ # in oder to avoid traces of vertical lines when the completion
+ # menu disappears.
+ for b in data:
+ written = DWORD()
+
+ retval = windll.kernel32.WriteConsoleW(self.hconsole, b, 1, byref(written), None)
+ assert retval != 0
+
+ self._buffer = []
+
+ def get_rows_below_cursor_position(self):
+ info = self.get_win32_screen_buffer_info()
+ return info.srWindow.Bottom - info.dwCursorPosition.Y + 1
+
+ def scroll_buffer_to_prompt(self):
+ """
+ To be called before drawing the prompt. This should scroll the console
+ to left, with the cursor at the bottom (if possible).
+ """
+ # Get current window size
+ info = self.get_win32_screen_buffer_info()
+ sr = info.srWindow
+ cursor_pos = info.dwCursorPosition
+
+ result = SMALL_RECT()
+
+ # Scroll to the left.
+ result.Left = 0
+ result.Right = sr.Right - sr.Left
+
+ # Scroll vertical
+ win_height = sr.Bottom - sr.Top
if 0 < sr.Bottom - cursor_pos.Y < win_height - 1:
# no vertical scroll if cursor already on the screen
result.Bottom = sr.Bottom
else:
result.Bottom = max(win_height, cursor_pos.Y)
- result.Top = result.Bottom - win_height
-
- # Scroll API
- self._winapi(windll.kernel32.SetConsoleWindowInfo, self.hconsole, True, byref(result))
-
- def enter_alternate_screen(self):
- """
- Go to alternate screen buffer.
- """
- if not self._in_alternate_screen:
- GENERIC_READ = 0x80000000
- GENERIC_WRITE = 0x40000000
-
- # Create a new console buffer and activate that one.
+ result.Top = result.Bottom - win_height
+
+ # Scroll API
+ self._winapi(windll.kernel32.SetConsoleWindowInfo, self.hconsole, True, byref(result))
+
+ def enter_alternate_screen(self):
+ """
+ Go to alternate screen buffer.
+ """
+ if not self._in_alternate_screen:
+ GENERIC_READ = 0x80000000
+ GENERIC_WRITE = 0x40000000
+
+ # Create a new console buffer and activate that one.
handle = HANDLE(self._winapi(windll.kernel32.CreateConsoleScreenBuffer, GENERIC_READ|GENERIC_WRITE,
DWORD(0), None, DWORD(1), None))
-
- self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle)
- self.hconsole = handle
- self._in_alternate_screen = True
-
- def quit_alternate_screen(self):
- """
- Make stdout again the active buffer.
- """
- if self._in_alternate_screen:
+
+ self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle)
+ self.hconsole = handle
+ self._in_alternate_screen = True
+
+ def quit_alternate_screen(self):
+ """
+ Make stdout again the active buffer.
+ """
+ if self._in_alternate_screen:
stdout = HANDLE(self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE))
- self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout)
- self._winapi(windll.kernel32.CloseHandle, self.hconsole)
- self.hconsole = stdout
- self._in_alternate_screen = False
-
- def enable_mouse_support(self):
- ENABLE_MOUSE_INPUT = 0x10
+ self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout)
+ self._winapi(windll.kernel32.CloseHandle, self.hconsole)
+ self.hconsole = stdout
+ self._in_alternate_screen = False
+
+ def enable_mouse_support(self):
+ ENABLE_MOUSE_INPUT = 0x10
handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
-
- original_mode = DWORD()
- self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
- self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value | ENABLE_MOUSE_INPUT)
-
- def disable_mouse_support(self):
- ENABLE_MOUSE_INPUT = 0x10
+
+ original_mode = DWORD()
+ self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
+ self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value | ENABLE_MOUSE_INPUT)
+
+ def disable_mouse_support(self):
+ ENABLE_MOUSE_INPUT = 0x10
handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
-
- original_mode = DWORD()
- self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
- self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value & ~ ENABLE_MOUSE_INPUT)
-
- def hide_cursor(self):
- pass
-
- def show_cursor(self):
- pass
-
- @classmethod
- def win32_refresh_window(cls):
- """
- Call win32 API to refresh the whole Window.
-
- This is sometimes necessary when the application paints background
- for completion menus. When the menu disappears, it leaves traces due
- to a bug in the Windows Console. Sending a repaint request solves it.
- """
- # Get console handle
+
+ original_mode = DWORD()
+ self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
+ self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value & ~ ENABLE_MOUSE_INPUT)
+
+ def hide_cursor(self):
+ pass
+
+ def show_cursor(self):
+ pass
+
+ @classmethod
+ def win32_refresh_window(cls):
+ """
+ Call win32 API to refresh the whole Window.
+
+ This is sometimes necessary when the application paints background
+ for completion menus. When the menu disappears, it leaves traces due
+ to a bug in the Windows Console. Sending a repaint request solves it.
+ """
+ # Get console handle
handle = HANDLE(windll.kernel32.GetConsoleWindow())
-
- RDW_INVALIDATE = 0x0001
- windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE))
-
-
-class FOREGROUND_COLOR:
- BLACK = 0x0000
- BLUE = 0x0001
- GREEN = 0x0002
- CYAN = 0x0003
- RED = 0x0004
- MAGENTA = 0x0005
- YELLOW = 0x0006
- GRAY = 0x0007
- INTENSITY = 0x0008 # Foreground color is intensified.
-
-
-class BACKROUND_COLOR:
- BLACK = 0x0000
- BLUE = 0x0010
- GREEN = 0x0020
- CYAN = 0x0030
- RED = 0x0040
- MAGENTA = 0x0050
- YELLOW = 0x0060
- GRAY = 0x0070
- INTENSITY = 0x0080 # Background color is intensified.
-
-
-def _create_ansi_color_dict(color_cls):
- " Create a table that maps the 16 named ansi colors to their Windows code. "
- return {
+
+ RDW_INVALIDATE = 0x0001
+ windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE))
+
+
+class FOREGROUND_COLOR:
+ BLACK = 0x0000
+ BLUE = 0x0001
+ GREEN = 0x0002
+ CYAN = 0x0003
+ RED = 0x0004
+ MAGENTA = 0x0005
+ YELLOW = 0x0006
+ GRAY = 0x0007
+ INTENSITY = 0x0008 # Foreground color is intensified.
+
+
+class BACKROUND_COLOR:
+ BLACK = 0x0000
+ BLUE = 0x0010
+ GREEN = 0x0020
+ CYAN = 0x0030
+ RED = 0x0040
+ MAGENTA = 0x0050
+ YELLOW = 0x0060
+ GRAY = 0x0070
+ INTENSITY = 0x0080 # Background color is intensified.
+
+
+def _create_ansi_color_dict(color_cls):
+ " Create a table that maps the 16 named ansi colors to their Windows code. "
+ return {
'ansidefault': color_cls.BLACK,
'ansiblack': color_cls.BLACK,
'ansidarkgray': color_cls.BLACK | color_cls.INTENSITY,
'ansilightgray': color_cls.GRAY,
'ansiwhite': color_cls.GRAY | color_cls.INTENSITY,
- # Low intensity.
+ # Low intensity.
'ansidarkred': color_cls.RED,
'ansidarkgreen': color_cls.GREEN,
'ansibrown': color_cls.YELLOW,
'ansidarkblue': color_cls.BLUE,
'ansipurple': color_cls.MAGENTA,
'ansiteal': color_cls.CYAN,
-
- # High intensity.
+
+ # High intensity.
'ansired': color_cls.RED | color_cls.INTENSITY,
'ansigreen': color_cls.GREEN | color_cls.INTENSITY,
'ansiyellow': color_cls.YELLOW | color_cls.INTENSITY,
'ansiblue': color_cls.BLUE | color_cls.INTENSITY,
'ansifuchsia': color_cls.MAGENTA | color_cls.INTENSITY,
'ansiturquoise': color_cls.CYAN | color_cls.INTENSITY,
- }
-
-FG_ANSI_COLORS = _create_ansi_color_dict(FOREGROUND_COLOR)
-BG_ANSI_COLORS = _create_ansi_color_dict(BACKROUND_COLOR)
-
-assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
-
-
-class ColorLookupTable(object):
- """
- Inspired by pygments/formatters/terminal256.py
- """
- def __init__(self):
- self._win32_colors = self._build_color_table()
- self.best_match = {} # Cache
-
- @staticmethod
- def _build_color_table():
- """
- Build an RGB-to-256 color conversion table
- """
- FG = FOREGROUND_COLOR
- BG = BACKROUND_COLOR
-
- return [
- (0x00, 0x00, 0x00, FG.BLACK, BG.BLACK),
- (0x00, 0x00, 0xaa, FG.BLUE, BG.BLUE),
- (0x00, 0xaa, 0x00, FG.GREEN, BG.GREEN),
- (0x00, 0xaa, 0xaa, FG.CYAN, BG.CYAN),
- (0xaa, 0x00, 0x00, FG.RED, BG.RED),
- (0xaa, 0x00, 0xaa, FG.MAGENTA, BG.MAGENTA),
- (0xaa, 0xaa, 0x00, FG.YELLOW, BG.YELLOW),
- (0x88, 0x88, 0x88, FG.GRAY, BG.GRAY),
-
- (0x44, 0x44, 0xff, FG.BLUE | FG.INTENSITY, BG.BLUE | BG.INTENSITY),
- (0x44, 0xff, 0x44, FG.GREEN | FG.INTENSITY, BG.GREEN | BG.INTENSITY),
- (0x44, 0xff, 0xff, FG.CYAN | FG.INTENSITY, BG.CYAN | BG.INTENSITY),
- (0xff, 0x44, 0x44, FG.RED | FG.INTENSITY, BG.RED | BG.INTENSITY),
- (0xff, 0x44, 0xff, FG.MAGENTA | FG.INTENSITY, BG.MAGENTA | BG.INTENSITY),
- (0xff, 0xff, 0x44, FG.YELLOW | FG.INTENSITY, BG.YELLOW | BG.INTENSITY),
-
+ }
+
+FG_ANSI_COLORS = _create_ansi_color_dict(FOREGROUND_COLOR)
+BG_ANSI_COLORS = _create_ansi_color_dict(BACKROUND_COLOR)
+
+assert set(FG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+assert set(BG_ANSI_COLORS) == set(ANSI_COLOR_NAMES)
+
+
+class ColorLookupTable(object):
+ """
+ Inspired by pygments/formatters/terminal256.py
+ """
+ def __init__(self):
+ self._win32_colors = self._build_color_table()
+ self.best_match = {} # Cache
+
+ @staticmethod
+ def _build_color_table():
+ """
+ Build an RGB-to-256 color conversion table
+ """
+ FG = FOREGROUND_COLOR
+ BG = BACKROUND_COLOR
+
+ return [
+ (0x00, 0x00, 0x00, FG.BLACK, BG.BLACK),
+ (0x00, 0x00, 0xaa, FG.BLUE, BG.BLUE),
+ (0x00, 0xaa, 0x00, FG.GREEN, BG.GREEN),
+ (0x00, 0xaa, 0xaa, FG.CYAN, BG.CYAN),
+ (0xaa, 0x00, 0x00, FG.RED, BG.RED),
+ (0xaa, 0x00, 0xaa, FG.MAGENTA, BG.MAGENTA),
+ (0xaa, 0xaa, 0x00, FG.YELLOW, BG.YELLOW),
+ (0x88, 0x88, 0x88, FG.GRAY, BG.GRAY),
+
+ (0x44, 0x44, 0xff, FG.BLUE | FG.INTENSITY, BG.BLUE | BG.INTENSITY),
+ (0x44, 0xff, 0x44, FG.GREEN | FG.INTENSITY, BG.GREEN | BG.INTENSITY),
+ (0x44, 0xff, 0xff, FG.CYAN | FG.INTENSITY, BG.CYAN | BG.INTENSITY),
+ (0xff, 0x44, 0x44, FG.RED | FG.INTENSITY, BG.RED | BG.INTENSITY),
+ (0xff, 0x44, 0xff, FG.MAGENTA | FG.INTENSITY, BG.MAGENTA | BG.INTENSITY),
+ (0xff, 0xff, 0x44, FG.YELLOW | FG.INTENSITY, BG.YELLOW | BG.INTENSITY),
+
(0x44, 0x44, 0x44, FG.BLACK | FG.INTENSITY, BG.BLACK | BG.INTENSITY),
- (0xff, 0xff, 0xff, FG.GRAY | FG.INTENSITY, BG.GRAY | BG.INTENSITY),
- ]
-
- def _closest_color(self, r, g, b):
- distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
- fg_match = 0
- bg_match = 0
-
- for r_, g_, b_, fg_, bg_ in self._win32_colors:
- rd = r - r_
- gd = g - g_
- bd = b - b_
-
- d = rd * rd + gd * gd + bd * bd
-
- if d < distance:
- fg_match = fg_
- bg_match = bg_
- distance = d
- return fg_match, bg_match
-
- def _color_indexes(self, color):
- indexes = self.best_match.get(color, None)
- if indexes is None:
- try:
- rgb = int(str(color), 16)
- except ValueError:
- rgb = 0
-
- r = (rgb >> 16) & 0xff
- g = (rgb >> 8) & 0xff
- b = rgb & 0xff
- indexes = self._closest_color(r, g, b)
- self.best_match[color] = indexes
- return indexes
-
+ (0xff, 0xff, 0xff, FG.GRAY | FG.INTENSITY, BG.GRAY | BG.INTENSITY),
+ ]
+
+ def _closest_color(self, r, g, b):
+ distance = 257 * 257 * 3 # "infinity" (>distance from #000000 to #ffffff)
+ fg_match = 0
+ bg_match = 0
+
+ for r_, g_, b_, fg_, bg_ in self._win32_colors:
+ rd = r - r_
+ gd = g - g_
+ bd = b - b_
+
+ d = rd * rd + gd * gd + bd * bd
+
+ if d < distance:
+ fg_match = fg_
+ bg_match = bg_
+ distance = d
+ return fg_match, bg_match
+
+ def _color_indexes(self, color):
+ indexes = self.best_match.get(color, None)
+ if indexes is None:
+ try:
+ rgb = int(str(color), 16)
+ except ValueError:
+ rgb = 0
+
+ r = (rgb >> 16) & 0xff
+ g = (rgb >> 8) & 0xff
+ b = rgb & 0xff
+ indexes = self._closest_color(r, g, b)
+ self.best_match[color] = indexes
+ return indexes
+
def lookup_fg_color(self, fg_color):
- """
- Return the color for use in the
- `windll.kernel32.SetConsoleTextAttribute` API call.
-
- :param fg_color: Foreground as text. E.g. 'ffffff' or 'red'
- """
- # Foreground.
- if fg_color in FG_ANSI_COLORS:
+ """
+ Return the color for use in the
+ `windll.kernel32.SetConsoleTextAttribute` API call.
+
+ :param fg_color: Foreground as text. E.g. 'ffffff' or 'red'
+ """
+ # Foreground.
+ if fg_color in FG_ANSI_COLORS:
return FG_ANSI_COLORS[fg_color]
- else:
+ else:
return self._color_indexes(fg_color)[0]
-
+
def lookup_bg_color(self, bg_color):
"""
Return the color for use in the
@@ -549,8 +549,8 @@ class ColorLookupTable(object):
:param bg_color: Background as text. E.g. 'ffffff' or 'red'
"""
- # Background.
- if bg_color in BG_ANSI_COLORS:
+ # Background.
+ if bg_color in BG_ANSI_COLORS:
return BG_ANSI_COLORS[bg_color]
- else:
+ else:
return self._color_indexes(bg_color)[1]
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py
index aab7682184b..3cd931883cc 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/utils.py
@@ -1,98 +1,98 @@
-from __future__ import unicode_literals
+from __future__ import unicode_literals
import inspect
-import os
-import signal
-import sys
-import threading
+import os
+import signal
+import sys
+import threading
import weakref
-
-from wcwidth import wcwidth
+
+from wcwidth import wcwidth
from six.moves import range
-
-
-__all__ = (
+
+
+__all__ = (
'Event',
- 'DummyContext',
- 'get_cwidth',
- 'suspend_to_background_supported',
- 'is_conemu_ansi',
- 'is_windows',
- 'in_main_thread',
- 'take_using_weights',
+ 'DummyContext',
+ 'get_cwidth',
+ 'suspend_to_background_supported',
+ 'is_conemu_ansi',
+ 'is_windows',
+ 'in_main_thread',
+ 'take_using_weights',
'test_callable_args',
-)
-
-
+)
+
+
class Event(object):
- """
+ """
Simple event to which event handlers can be attached. For instance::
-
+
class Cls:
def __init__(self):
# Define event. The first parameter is the sender.
self.event = Event(self)
-
+
obj = Cls()
-
+
def handler(sender):
pass
-
+
# Add event handler by using the += operator.
obj.event += handler
# Fire event.
obj.event()
- """
+ """
def __init__(self, sender, handler=None):
self.sender = sender
self._handlers = []
-
+
if handler is not None:
self += handler
def __call__(self):
" Fire event. "
- for handler in self._handlers:
+ for handler in self._handlers:
handler(self.sender)
-
+
def fire(self):
" Alias for just calling the event. "
self()
- def __iadd__(self, handler):
- """
- Add another handler to this callback.
+ def __iadd__(self, handler):
+ """
+ Add another handler to this callback.
(Handler should be a callable that takes exactly one parameter: the
sender object.)
- """
+ """
# Test handler.
assert callable(handler)
if not test_callable_args(handler, [None]):
raise TypeError("%r doesn't take exactly one argument." % handler)
# Add to list of event handlers.
- self._handlers.append(handler)
- return self
-
- def __isub__(self, handler):
- """
- Remove a handler from this callback.
- """
- self._handlers.remove(handler)
- return self
-
-
+ self._handlers.append(handler)
+ return self
+
+ def __isub__(self, handler):
+ """
+ Remove a handler from this callback.
+ """
+ self._handlers.remove(handler)
+ return self
+
+
# Cache of signatures. Improves the performance of `test_callable_args`.
_signatures_cache = weakref.WeakKeyDictionary()
-
-
+
+
def test_callable_args(func, args):
"""
Return True when this function can be called with the given arguments.
"""
assert isinstance(args, (list, tuple))
signature = getattr(inspect, 'signature', None)
-
+
if signature is not None:
# For Python 3, use inspect.signature.
try:
@@ -129,112 +129,112 @@ def test_callable_args(func, args):
return len(spec.args) - len(spec.defaults or []) <= len(args) <= len(spec.args)
-class DummyContext(object):
- """
- (contextlib.nested is not available on Py3)
- """
- def __enter__(self):
- pass
-
- def __exit__(self, *a):
- pass
-
-
-class _CharSizesCache(dict):
- """
- Cache for wcwidth sizes.
- """
- def __missing__(self, string):
- # Note: We use the `max(0, ...` because some non printable control
- # characters, like e.g. Ctrl-underscore get a -1 wcwidth value.
- # It can be possible that these characters end up in the input
- # text.
- if len(string) == 1:
- result = max(0, wcwidth(string))
- else:
- result = sum(max(0, wcwidth(c)) for c in string)
-
+class DummyContext(object):
+ """
+ (contextlib.nested is not available on Py3)
+ """
+ def __enter__(self):
+ pass
+
+ def __exit__(self, *a):
+ pass
+
+
+class _CharSizesCache(dict):
+ """
+ Cache for wcwidth sizes.
+ """
+ def __missing__(self, string):
+ # Note: We use the `max(0, ...` because some non printable control
+ # characters, like e.g. Ctrl-underscore get a -1 wcwidth value.
+ # It can be possible that these characters end up in the input
+ # text.
+ if len(string) == 1:
+ result = max(0, wcwidth(string))
+ else:
+ result = sum(max(0, wcwidth(c)) for c in string)
+
# Cache for short strings.
# (It's hard to tell what we can consider short...)
if len(string) < 256:
self[string] = result
- return result
-
-
-_CHAR_SIZES_CACHE = _CharSizesCache()
-
-
-def get_cwidth(string):
- """
- Return width of a string. Wrapper around ``wcwidth``.
- """
- return _CHAR_SIZES_CACHE[string]
-
-
-def suspend_to_background_supported():
- """
- Returns `True` when the Python implementation supports
- suspend-to-background. This is typically `False' on Windows systems.
- """
- return hasattr(signal, 'SIGTSTP')
-
-
-def is_windows():
- """
- True when we are using Windows.
- """
- return sys.platform.startswith('win') # E.g. 'win32', not 'darwin' or 'linux2'
-
-
-def is_conemu_ansi():
- """
- True when the ConEmu Windows console is used.
- """
- return is_windows() and os.environ.get('ConEmuANSI', 'OFF') == 'ON'
-
-
-def in_main_thread():
- """
- True when the current thread is the main thread.
- """
- return threading.current_thread().__class__.__name__ == '_MainThread'
-
-
-def take_using_weights(items, weights):
- """
- Generator that keeps yielding items from the items list, in proportion to
- their weight. For instance::
-
- # Getting the first 70 items from this generator should have yielded 10
- # times A, 20 times B and 40 times C, all distributed equally..
- take_using_weights(['A', 'B', 'C'], [5, 10, 20])
-
- :param items: List of items to take from.
- :param weights: Integers representing the weight. (Numbers have to be
- integers, not floats.)
- """
- assert isinstance(items, list)
- assert isinstance(weights, list)
- assert all(isinstance(i, int) for i in weights)
- assert len(items) == len(weights)
- assert len(items) > 0
-
- already_taken = [0 for i in items]
- item_count = len(items)
- max_weight = max(weights)
-
- i = 0
- while True:
- # Each iteration of this loop, we fill up until by (total_weight/max_weight).
- adding = True
- while adding:
- adding = False
-
- for item_i, item, weight in zip(range(item_count), items, weights):
- if already_taken[item_i] < i * weight / float(max_weight):
- yield item
- already_taken[item_i] += 1
- adding = True
-
- i += 1
+ return result
+
+
+_CHAR_SIZES_CACHE = _CharSizesCache()
+
+
+def get_cwidth(string):
+ """
+ Return width of a string. Wrapper around ``wcwidth``.
+ """
+ return _CHAR_SIZES_CACHE[string]
+
+
+def suspend_to_background_supported():
+ """
+ Returns `True` when the Python implementation supports
+ suspend-to-background. This is typically `False' on Windows systems.
+ """
+ return hasattr(signal, 'SIGTSTP')
+
+
+def is_windows():
+ """
+ True when we are using Windows.
+ """
+ return sys.platform.startswith('win') # E.g. 'win32', not 'darwin' or 'linux2'
+
+
+def is_conemu_ansi():
+ """
+ True when the ConEmu Windows console is used.
+ """
+ return is_windows() and os.environ.get('ConEmuANSI', 'OFF') == 'ON'
+
+
+def in_main_thread():
+ """
+ True when the current thread is the main thread.
+ """
+ return threading.current_thread().__class__.__name__ == '_MainThread'
+
+
+def take_using_weights(items, weights):
+ """
+ Generator that keeps yielding items from the items list, in proportion to
+ their weight. For instance::
+
+ # Getting the first 70 items from this generator should have yielded 10
+ # times A, 20 times B and 40 times C, all distributed equally..
+ take_using_weights(['A', 'B', 'C'], [5, 10, 20])
+
+ :param items: List of items to take from.
+ :param weights: Integers representing the weight. (Numbers have to be
+ integers, not floats.)
+ """
+ assert isinstance(items, list)
+ assert isinstance(weights, list)
+ assert all(isinstance(i, int) for i in weights)
+ assert len(items) == len(weights)
+ assert len(items) > 0
+
+ already_taken = [0 for i in items]
+ item_count = len(items)
+ max_weight = max(weights)
+
+ i = 0
+ while True:
+ # Each iteration of this loop, we fill up until by (total_weight/max_weight).
+ adding = True
+ while adding:
+ adding = False
+
+ for item_i, item, weight in zip(range(item_count), items, weights):
+ if already_taken[item_i] < i * weight / float(max_weight):
+ yield item
+ already_taken[item_i] += 1
+ adding = True
+
+ i += 1
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py
index f898796e066..0027873f88f 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/validation.py
@@ -1,64 +1,64 @@
-"""
-Input validation for a `Buffer`.
-(Validators will be called before accepting input.)
-"""
-from __future__ import unicode_literals
-from .filters import to_simple_filter
-
-from abc import ABCMeta, abstractmethod
-from six import with_metaclass
-
-__all__ = (
- 'ConditionalValidator',
- 'ValidationError',
- 'Validator',
-)
-
-
-class ValidationError(Exception):
- """
- Error raised by :meth:`.Validator.validate`.
-
- :param cursor_position: The cursor position where the error occured.
- :param message: Text.
- """
- def __init__(self, cursor_position=0, message=''):
- super(ValidationError, self).__init__(message)
- self.cursor_position = cursor_position
- self.message = message
-
- def __repr__(self):
- return '%s(cursor_position=%r, message=%r)' % (
- self.__class__.__name__, self.cursor_position, self.message)
-
-
-class Validator(with_metaclass(ABCMeta, object)):
- """
- Abstract base class for an input validator.
- """
- @abstractmethod
- def validate(self, document):
- """
- Validate the input.
- If invalid, this should raise a :class:`.ValidationError`.
-
- :param document: :class:`~prompt_toolkit.document.Document` instance.
- """
- pass
-
-
-class ConditionalValidator(Validator):
- """
- Validator that can be switched on/off according to
- a filter. (This wraps around another validator.)
- """
- def __init__(self, validator, filter):
- assert isinstance(validator, Validator)
-
- self.validator = validator
+"""
+Input validation for a `Buffer`.
+(Validators will be called before accepting input.)
+"""
+from __future__ import unicode_literals
+from .filters import to_simple_filter
+
+from abc import ABCMeta, abstractmethod
+from six import with_metaclass
+
+__all__ = (
+ 'ConditionalValidator',
+ 'ValidationError',
+ 'Validator',
+)
+
+
+class ValidationError(Exception):
+ """
+ Error raised by :meth:`.Validator.validate`.
+
+ :param cursor_position: The cursor position where the error occured.
+ :param message: Text.
+ """
+ def __init__(self, cursor_position=0, message=''):
+ super(ValidationError, self).__init__(message)
+ self.cursor_position = cursor_position
+ self.message = message
+
+ def __repr__(self):
+ return '%s(cursor_position=%r, message=%r)' % (
+ self.__class__.__name__, self.cursor_position, self.message)
+
+
+class Validator(with_metaclass(ABCMeta, object)):
+ """
+ Abstract base class for an input validator.
+ """
+ @abstractmethod
+ def validate(self, document):
+ """
+ Validate the input.
+ If invalid, this should raise a :class:`.ValidationError`.
+
+ :param document: :class:`~prompt_toolkit.document.Document` instance.
+ """
+ pass
+
+
+class ConditionalValidator(Validator):
+ """
+ Validator that can be switched on/off according to
+ a filter. (This wraps around another validator.)
+ """
+ def __init__(self, validator, filter):
+ assert isinstance(validator, Validator)
+
+ self.validator = validator
self.filter = to_simple_filter(filter)
-
- def validate(self, document):
- # Call the validator only if the filter is active.
- if self.filter():
- self.validator.validate(document)
+
+ def validate(self, document):
+ # Call the validator only if the filter is active.
+ if self.filter():
+ self.validator.validate(document)
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py
index 4b7de092f65..ba2d90df8e5 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/win32_types.py
@@ -1,155 +1,155 @@
-from ctypes import Union, Structure, c_char, c_short, c_long, c_ulong
-from ctypes.wintypes import DWORD, BOOL, LPVOID, WORD, WCHAR
-
-
-# Input/Output standard device numbers. Note that these are not handle objects.
-# It's the `windll.kernel32.GetStdHandle` system call that turns them into a
-# real handle object.
-STD_INPUT_HANDLE = c_ulong(-10)
-STD_OUTPUT_HANDLE = c_ulong(-11)
-STD_ERROR_HANDLE = c_ulong(-12)
-
-
-class COORD(Structure):
- """
- Struct in wincon.h
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx
- """
- _fields_ = [
- ('X', c_short), # Short
- ('Y', c_short), # Short
- ]
-
- def __repr__(self):
- return '%s(X=%r, Y=%r, type_x=%r, type_y=%r)' % (
- self.__class__.__name__, self.X, self.Y, type(self.X), type(self.Y))
-
-
-class UNICODE_OR_ASCII(Union):
- _fields_ = [
- ('AsciiChar', c_char),
- ('UnicodeChar', WCHAR),
- ]
-
-
-class KEY_EVENT_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166(v=vs.85).aspx
- """
- _fields_ = [
- ('KeyDown', c_long), # bool
- ('RepeatCount', c_short), # word
- ('VirtualKeyCode', c_short), # word
- ('VirtualScanCode', c_short), # word
- ('uChar', UNICODE_OR_ASCII), # Unicode or ASCII.
- ('ControlKeyState', c_long) # double word
- ]
-
-
-class MOUSE_EVENT_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms684239(v=vs.85).aspx
- """
- _fields_ = [
- ('MousePosition', COORD),
- ('ButtonState', c_long), # dword
- ('ControlKeyState', c_long), # dword
- ('EventFlags', c_long) # dword
- ]
-
-
-class WINDOW_BUFFER_SIZE_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms687093(v=vs.85).aspx
- """
- _fields_ = [
- ('Size', COORD)
- ]
-
-
-class MENU_EVENT_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms684213(v=vs.85).aspx
- """
- _fields_ = [
- ('CommandId', c_long) # uint
- ]
-
-
-class FOCUS_EVENT_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms683149(v=vs.85).aspx
- """
- _fields_ = [
- ('SetFocus', c_long) # bool
- ]
-
-
-class EVENT_RECORD(Union):
- _fields_ = [
- ('KeyEvent', KEY_EVENT_RECORD),
- ('MouseEvent', MOUSE_EVENT_RECORD),
- ('WindowBufferSizeEvent', WINDOW_BUFFER_SIZE_RECORD),
- ('MenuEvent', MENU_EVENT_RECORD),
- ('FocusEvent', FOCUS_EVENT_RECORD)
- ]
-
-
-class INPUT_RECORD(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx
- """
- _fields_ = [
- ('EventType', c_short), # word
- ('Event', EVENT_RECORD) # Union.
- ]
-
-
-EventTypes = {
- 1: 'KeyEvent',
- 2: 'MouseEvent',
- 4: 'WindowBufferSizeEvent',
- 8: 'MenuEvent',
- 16: 'FocusEvent'
-}
-
-
-class SMALL_RECT(Structure):
- """struct in wincon.h."""
- _fields_ = [
- ("Left", c_short),
- ("Top", c_short),
- ("Right", c_short),
- ("Bottom", c_short),
- ]
-
-
-class CONSOLE_SCREEN_BUFFER_INFO(Structure):
- """struct in wincon.h."""
- _fields_ = [
- ("dwSize", COORD),
- ("dwCursorPosition", COORD),
- ("wAttributes", WORD),
- ("srWindow", SMALL_RECT),
- ("dwMaximumWindowSize", COORD),
- ]
-
- def __str__(self):
- return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
- self.dwSize.Y, self.dwSize.X,
- self.dwCursorPosition.Y, self.dwCursorPosition.X,
- self.wAttributes,
- self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right,
- self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X,
- )
-
-
-class SECURITY_ATTRIBUTES(Structure):
- """
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx
- """
- _fields_ = [
- ('nLength', DWORD),
- ('lpSecurityDescriptor', LPVOID),
- ('bInheritHandle', BOOL),
- ]
+from ctypes import Union, Structure, c_char, c_short, c_long, c_ulong
+from ctypes.wintypes import DWORD, BOOL, LPVOID, WORD, WCHAR
+
+
+# Input/Output standard device numbers. Note that these are not handle objects.
+# It's the `windll.kernel32.GetStdHandle` system call that turns them into a
+# real handle object.
+STD_INPUT_HANDLE = c_ulong(-10)
+STD_OUTPUT_HANDLE = c_ulong(-11)
+STD_ERROR_HANDLE = c_ulong(-12)
+
+
+class COORD(Structure):
+ """
+ Struct in wincon.h
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('X', c_short), # Short
+ ('Y', c_short), # Short
+ ]
+
+ def __repr__(self):
+ return '%s(X=%r, Y=%r, type_x=%r, type_y=%r)' % (
+ self.__class__.__name__, self.X, self.Y, type(self.X), type(self.Y))
+
+
+class UNICODE_OR_ASCII(Union):
+ _fields_ = [
+ ('AsciiChar', c_char),
+ ('UnicodeChar', WCHAR),
+ ]
+
+
+class KEY_EVENT_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('KeyDown', c_long), # bool
+ ('RepeatCount', c_short), # word
+ ('VirtualKeyCode', c_short), # word
+ ('VirtualScanCode', c_short), # word
+ ('uChar', UNICODE_OR_ASCII), # Unicode or ASCII.
+ ('ControlKeyState', c_long) # double word
+ ]
+
+
+class MOUSE_EVENT_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms684239(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('MousePosition', COORD),
+ ('ButtonState', c_long), # dword
+ ('ControlKeyState', c_long), # dword
+ ('EventFlags', c_long) # dword
+ ]
+
+
+class WINDOW_BUFFER_SIZE_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms687093(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('Size', COORD)
+ ]
+
+
+class MENU_EVENT_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms684213(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('CommandId', c_long) # uint
+ ]
+
+
+class FOCUS_EVENT_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683149(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('SetFocus', c_long) # bool
+ ]
+
+
+class EVENT_RECORD(Union):
+ _fields_ = [
+ ('KeyEvent', KEY_EVENT_RECORD),
+ ('MouseEvent', MOUSE_EVENT_RECORD),
+ ('WindowBufferSizeEvent', WINDOW_BUFFER_SIZE_RECORD),
+ ('MenuEvent', MENU_EVENT_RECORD),
+ ('FocusEvent', FOCUS_EVENT_RECORD)
+ ]
+
+
+class INPUT_RECORD(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('EventType', c_short), # word
+ ('Event', EVENT_RECORD) # Union.
+ ]
+
+
+EventTypes = {
+ 1: 'KeyEvent',
+ 2: 'MouseEvent',
+ 4: 'WindowBufferSizeEvent',
+ 8: 'MenuEvent',
+ 16: 'FocusEvent'
+}
+
+
+class SMALL_RECT(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("Left", c_short),
+ ("Top", c_short),
+ ("Right", c_short),
+ ("Bottom", c_short),
+ ]
+
+
+class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("dwSize", COORD),
+ ("dwCursorPosition", COORD),
+ ("wAttributes", WORD),
+ ("srWindow", SMALL_RECT),
+ ("dwMaximumWindowSize", COORD),
+ ]
+
+ def __str__(self):
+ return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
+ self.dwSize.Y, self.dwSize.X,
+ self.dwCursorPosition.Y, self.dwCursorPosition.X,
+ self.wAttributes,
+ self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right,
+ self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X,
+ )
+
+
+class SECURITY_ATTRIBUTES(Structure):
+ """
+ http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx
+ """
+ _fields_ = [
+ ('nLength', DWORD),
+ ('lpSecurityDescriptor', LPVOID),
+ ('bInheritHandle', BOOL),
+ ]
diff --git a/contrib/python/prompt-toolkit/py2/ya.make b/contrib/python/prompt-toolkit/py2/ya.make
index ce02faf4d1b..db22aa0a70b 100644
--- a/contrib/python/prompt-toolkit/py2/ya.make
+++ b/contrib/python/prompt-toolkit/py2/ya.make
@@ -1,9 +1,9 @@
PY2_LIBRARY()
-
+
OWNER(blinkov nslus g:python-contrib)
VERSION(1.0.18)
-
+
LICENSE(BSD-3-Clause)
PEERDIR(
@@ -33,120 +33,120 @@ NO_CHECK_IMPORTS(
prompt_toolkit.win32_types
)
-PY_SRCS(
- TOP_LEVEL
- prompt_toolkit/__init__.py
- prompt_toolkit/application.py
- prompt_toolkit/auto_suggest.py
- prompt_toolkit/buffer.py
- prompt_toolkit/buffer_mapping.py
+PY_SRCS(
+ TOP_LEVEL
+ prompt_toolkit/__init__.py
+ prompt_toolkit/application.py
+ prompt_toolkit/auto_suggest.py
+ prompt_toolkit/buffer.py
+ prompt_toolkit/buffer_mapping.py
prompt_toolkit/cache.py
- prompt_toolkit/clipboard/__init__.py
- prompt_toolkit/clipboard/base.py
- prompt_toolkit/clipboard/in_memory.py
- prompt_toolkit/clipboard/pyperclip.py
- prompt_toolkit/completion.py
- prompt_toolkit/contrib/__init__.py
- prompt_toolkit/contrib/completers/__init__.py
- prompt_toolkit/contrib/completers/base.py
- prompt_toolkit/contrib/completers/filesystem.py
- prompt_toolkit/contrib/completers/system.py
- prompt_toolkit/contrib/regular_languages/__init__.py
- prompt_toolkit/contrib/regular_languages/compiler.py
- prompt_toolkit/contrib/regular_languages/completion.py
- prompt_toolkit/contrib/regular_languages/lexer.py
- prompt_toolkit/contrib/regular_languages/regex_parser.py
- prompt_toolkit/contrib/regular_languages/validation.py
- prompt_toolkit/contrib/telnet/__init__.py
- prompt_toolkit/contrib/telnet/application.py
- prompt_toolkit/contrib/telnet/log.py
- prompt_toolkit/contrib/telnet/protocol.py
- prompt_toolkit/contrib/telnet/server.py
- prompt_toolkit/contrib/validators/__init__.py
- prompt_toolkit/contrib/validators/base.py
- prompt_toolkit/document.py
- prompt_toolkit/enums.py
- prompt_toolkit/eventloop/__init__.py
- prompt_toolkit/eventloop/asyncio_base.py
- prompt_toolkit/eventloop/asyncio_posix.py
- prompt_toolkit/eventloop/asyncio_win32.py
- prompt_toolkit/eventloop/base.py
- prompt_toolkit/eventloop/callbacks.py
- prompt_toolkit/eventloop/inputhook.py
- prompt_toolkit/eventloop/posix.py
- prompt_toolkit/eventloop/posix_utils.py
+ prompt_toolkit/clipboard/__init__.py
+ prompt_toolkit/clipboard/base.py
+ prompt_toolkit/clipboard/in_memory.py
+ prompt_toolkit/clipboard/pyperclip.py
+ prompt_toolkit/completion.py
+ prompt_toolkit/contrib/__init__.py
+ prompt_toolkit/contrib/completers/__init__.py
+ prompt_toolkit/contrib/completers/base.py
+ prompt_toolkit/contrib/completers/filesystem.py
+ prompt_toolkit/contrib/completers/system.py
+ prompt_toolkit/contrib/regular_languages/__init__.py
+ prompt_toolkit/contrib/regular_languages/compiler.py
+ prompt_toolkit/contrib/regular_languages/completion.py
+ prompt_toolkit/contrib/regular_languages/lexer.py
+ prompt_toolkit/contrib/regular_languages/regex_parser.py
+ prompt_toolkit/contrib/regular_languages/validation.py
+ prompt_toolkit/contrib/telnet/__init__.py
+ prompt_toolkit/contrib/telnet/application.py
+ prompt_toolkit/contrib/telnet/log.py
+ prompt_toolkit/contrib/telnet/protocol.py
+ prompt_toolkit/contrib/telnet/server.py
+ prompt_toolkit/contrib/validators/__init__.py
+ prompt_toolkit/contrib/validators/base.py
+ prompt_toolkit/document.py
+ prompt_toolkit/enums.py
+ prompt_toolkit/eventloop/__init__.py
+ prompt_toolkit/eventloop/asyncio_base.py
+ prompt_toolkit/eventloop/asyncio_posix.py
+ prompt_toolkit/eventloop/asyncio_win32.py
+ prompt_toolkit/eventloop/base.py
+ prompt_toolkit/eventloop/callbacks.py
+ prompt_toolkit/eventloop/inputhook.py
+ prompt_toolkit/eventloop/posix.py
+ prompt_toolkit/eventloop/posix_utils.py
prompt_toolkit/eventloop/select.py
- prompt_toolkit/eventloop/utils.py
- prompt_toolkit/eventloop/win32.py
- prompt_toolkit/filters/__init__.py
- prompt_toolkit/filters/base.py
- prompt_toolkit/filters/cli.py
- prompt_toolkit/filters/types.py
- prompt_toolkit/filters/utils.py
- prompt_toolkit/history.py
- prompt_toolkit/input.py
- prompt_toolkit/interface.py
- prompt_toolkit/key_binding/__init__.py
- prompt_toolkit/key_binding/bindings/__init__.py
- prompt_toolkit/key_binding/bindings/basic.py
+ prompt_toolkit/eventloop/utils.py
+ prompt_toolkit/eventloop/win32.py
+ prompt_toolkit/filters/__init__.py
+ prompt_toolkit/filters/base.py
+ prompt_toolkit/filters/cli.py
+ prompt_toolkit/filters/types.py
+ prompt_toolkit/filters/utils.py
+ prompt_toolkit/history.py
+ prompt_toolkit/input.py
+ prompt_toolkit/interface.py
+ prompt_toolkit/key_binding/__init__.py
+ prompt_toolkit/key_binding/bindings/__init__.py
+ prompt_toolkit/key_binding/bindings/basic.py
prompt_toolkit/key_binding/bindings/completion.py
- prompt_toolkit/key_binding/bindings/emacs.py
+ prompt_toolkit/key_binding/bindings/emacs.py
prompt_toolkit/key_binding/bindings/named_commands.py
- prompt_toolkit/key_binding/bindings/scroll.py
- prompt_toolkit/key_binding/bindings/utils.py
- prompt_toolkit/key_binding/bindings/vi.py
+ prompt_toolkit/key_binding/bindings/scroll.py
+ prompt_toolkit/key_binding/bindings/utils.py
+ prompt_toolkit/key_binding/bindings/vi.py
prompt_toolkit/key_binding/defaults.py
prompt_toolkit/key_binding/digraphs.py
- prompt_toolkit/key_binding/input_processor.py
- prompt_toolkit/key_binding/manager.py
- prompt_toolkit/key_binding/registry.py
- prompt_toolkit/key_binding/vi_state.py
- prompt_toolkit/keys.py
- prompt_toolkit/layout/__init__.py
- prompt_toolkit/layout/containers.py
- prompt_toolkit/layout/controls.py
- prompt_toolkit/layout/dimension.py
- prompt_toolkit/layout/lexers.py
- prompt_toolkit/layout/margins.py
- prompt_toolkit/layout/menus.py
- prompt_toolkit/layout/mouse_handlers.py
- prompt_toolkit/layout/processors.py
- prompt_toolkit/layout/prompt.py
- prompt_toolkit/layout/screen.py
- prompt_toolkit/layout/toolbars.py
- prompt_toolkit/layout/utils.py
- prompt_toolkit/mouse_events.py
- prompt_toolkit/output.py
- prompt_toolkit/reactive.py
- prompt_toolkit/renderer.py
- prompt_toolkit/search_state.py
- prompt_toolkit/selection.py
- prompt_toolkit/shortcuts.py
+ prompt_toolkit/key_binding/input_processor.py
+ prompt_toolkit/key_binding/manager.py
+ prompt_toolkit/key_binding/registry.py
+ prompt_toolkit/key_binding/vi_state.py
+ prompt_toolkit/keys.py
+ prompt_toolkit/layout/__init__.py
+ prompt_toolkit/layout/containers.py
+ prompt_toolkit/layout/controls.py
+ prompt_toolkit/layout/dimension.py
+ prompt_toolkit/layout/lexers.py
+ prompt_toolkit/layout/margins.py
+ prompt_toolkit/layout/menus.py
+ prompt_toolkit/layout/mouse_handlers.py
+ prompt_toolkit/layout/processors.py
+ prompt_toolkit/layout/prompt.py
+ prompt_toolkit/layout/screen.py
+ prompt_toolkit/layout/toolbars.py
+ prompt_toolkit/layout/utils.py
+ prompt_toolkit/mouse_events.py
+ prompt_toolkit/output.py
+ prompt_toolkit/reactive.py
+ prompt_toolkit/renderer.py
+ prompt_toolkit/search_state.py
+ prompt_toolkit/selection.py
+ prompt_toolkit/shortcuts.py
prompt_toolkit/styles/__init__.py
prompt_toolkit/styles/base.py
prompt_toolkit/styles/defaults.py
prompt_toolkit/styles/from_dict.py
prompt_toolkit/styles/from_pygments.py
prompt_toolkit/styles/utils.py
- prompt_toolkit/terminal/__init__.py
- prompt_toolkit/terminal/conemu_output.py
- prompt_toolkit/terminal/vt100_input.py
- prompt_toolkit/terminal/vt100_output.py
- prompt_toolkit/terminal/win32_input.py
- prompt_toolkit/terminal/win32_output.py
+ prompt_toolkit/terminal/__init__.py
+ prompt_toolkit/terminal/conemu_output.py
+ prompt_toolkit/terminal/vt100_input.py
+ prompt_toolkit/terminal/vt100_output.py
+ prompt_toolkit/terminal/win32_input.py
+ prompt_toolkit/terminal/win32_output.py
prompt_toolkit/token.py
- prompt_toolkit/utils.py
- prompt_toolkit/validation.py
- prompt_toolkit/win32_types.py
-)
-
+ prompt_toolkit/utils.py
+ prompt_toolkit/validation.py
+ prompt_toolkit/win32_types.py
+)
+
RESOURCE_FILES(
PREFIX contrib/python/prompt-toolkit/py2/
.dist-info/METADATA
.dist-info/top_level.txt
)
-END()
+END()
RECURSE_FOR_TESTS(
tests
diff --git a/contrib/python/prompt-toolkit/ya.make b/contrib/python/prompt-toolkit/ya.make
index ee826dcfa84..f1f936eb3f9 100644
--- a/contrib/python/prompt-toolkit/ya.make
+++ b/contrib/python/prompt-toolkit/ya.make
@@ -1,5 +1,5 @@
-PY23_LIBRARY()
-
+PY23_LIBRARY()
+
LICENSE(Service-Py23-Proxy)
OWNER(g:python-contrib)
@@ -12,7 +12,7 @@ ENDIF()
NO_LINT()
-END()
+END()
RECURSE(
py2
diff --git a/contrib/python/wcwidth/LICENSE b/contrib/python/wcwidth/LICENSE
index 4a1bec17f05..a44c0757243 100644
--- a/contrib/python/wcwidth/LICENSE
+++ b/contrib/python/wcwidth/LICENSE
@@ -1,24 +1,24 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Jeff Quast <contact@jeffquast.com>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+The MIT License (MIT)
+
+Copyright (c) 2014 Jeff Quast <contact@jeffquast.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
Markus Kuhn -- 2007-05-26 (Unicode 5.0)
diff --git a/contrib/python/wcwidth/wcwidth/__init__.py b/contrib/python/wcwidth/wcwidth/__init__.py
index 317236272df..a9008f8235d 100644
--- a/contrib/python/wcwidth/wcwidth/__init__.py
+++ b/contrib/python/wcwidth/wcwidth/__init__.py
@@ -1,6 +1,6 @@
"""
wcwidth module.
-
+
https://github.com/jquast/wcwidth
"""
# re-export all functions & definitions, even private ones, from top-level
diff --git a/contrib/python/wcwidth/wcwidth/wcwidth.py b/contrib/python/wcwidth/wcwidth/wcwidth.py
index 54a18c5e12e..931bd0b1b34 100644
--- a/contrib/python/wcwidth/wcwidth/wcwidth.py
+++ b/contrib/python/wcwidth/wcwidth/wcwidth.py
@@ -1,83 +1,83 @@
-"""
+"""
This is a python implementation of wcwidth() and wcswidth().
-
-https://github.com/jquast/wcwidth
-
+
+https://github.com/jquast/wcwidth
+
from Markus Kuhn's C code, retrieved from:
-
- http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
-
-This is an implementation of wcwidth() and wcswidth() (defined in
-IEEE Std 1002.1-2001) for Unicode.
-
-http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
-http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
-
-In fixed-width output devices, Latin characters all occupy a single
-"cell" position of equal width, whereas ideographic CJK characters
-occupy two such cells. Interoperability between terminal-line
-applications and (teletype-style) character terminals using the
-UTF-8 encoding requires agreement on which character should advance
-the cursor by how many cell positions. No established formal
-standards exist at present on which Unicode character shall occupy
-how many cell positions on character terminals. These routines are
-a first attempt of defining such behavior based on simple rules
-applied to data provided by the Unicode Consortium.
-
-For some graphical characters, the Unicode standard explicitly
-defines a character-cell width via the definition of the East Asian
-FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
-In all these cases, there is no ambiguity about which width a
-terminal shall use. For characters in the East Asian Ambiguous (A)
-class, the width choice depends purely on a preference of backward
-compatibility with either historic CJK or Western practice.
-Choosing single-width for these characters is easy to justify as
-the appropriate long-term solution, as the CJK practice of
-displaying these characters as double-width comes from historic
-implementation simplicity (8-bit encoded characters were displayed
-single-width and 16-bit ones double-width, even for Greek,
-Cyrillic, etc.) and not any typographic considerations.
-
-Much less clear is the choice of width for the Not East Asian
-(Neutral) class. Existing practice does not dictate a width for any
-of these characters. It would nevertheless make sense
-typographically to allocate two character cells to characters such
-as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
-represented adequately with a single-width glyph. The following
-routines at present merely assign a single-cell width to all
-neutral characters, in the interest of simplicity. This is not
-entirely satisfactory and should be reconsidered before
-establishing a formal standard in this area. At the moment, the
-decision which Not East Asian (Neutral) characters should be
-represented by double-width glyphs cannot yet be answered by
-applying a simple rule from the Unicode database content. Setting
-up a proper standard for the behavior of UTF-8 character terminals
-will require a careful analysis not only of each Unicode character,
-but also of each presentation form, something the author of these
-routines has avoided to do so far.
-
-http://www.unicode.org/unicode/reports/tr11/
-
-Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
-"""
+
+ http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+
+This is an implementation of wcwidth() and wcswidth() (defined in
+IEEE Std 1002.1-2001) for Unicode.
+
+http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+
+In fixed-width output devices, Latin characters all occupy a single
+"cell" position of equal width, whereas ideographic CJK characters
+occupy two such cells. Interoperability between terminal-line
+applications and (teletype-style) character terminals using the
+UTF-8 encoding requires agreement on which character should advance
+the cursor by how many cell positions. No established formal
+standards exist at present on which Unicode character shall occupy
+how many cell positions on character terminals. These routines are
+a first attempt of defining such behavior based on simple rules
+applied to data provided by the Unicode Consortium.
+
+For some graphical characters, the Unicode standard explicitly
+defines a character-cell width via the definition of the East Asian
+FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+In all these cases, there is no ambiguity about which width a
+terminal shall use. For characters in the East Asian Ambiguous (A)
+class, the width choice depends purely on a preference of backward
+compatibility with either historic CJK or Western practice.
+Choosing single-width for these characters is easy to justify as
+the appropriate long-term solution, as the CJK practice of
+displaying these characters as double-width comes from historic
+implementation simplicity (8-bit encoded characters were displayed
+single-width and 16-bit ones double-width, even for Greek,
+Cyrillic, etc.) and not any typographic considerations.
+
+Much less clear is the choice of width for the Not East Asian
+(Neutral) class. Existing practice does not dictate a width for any
+of these characters. It would nevertheless make sense
+typographically to allocate two character cells to characters such
+as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+represented adequately with a single-width glyph. The following
+routines at present merely assign a single-cell width to all
+neutral characters, in the interest of simplicity. This is not
+entirely satisfactory and should be reconsidered before
+establishing a formal standard in this area. At the moment, the
+decision which Not East Asian (Neutral) characters should be
+represented by double-width glyphs cannot yet be answered by
+applying a simple rule from the Unicode database content. Setting
+up a proper standard for the behavior of UTF-8 character terminals
+will require a careful analysis not only of each Unicode character,
+but also of each presentation form, something the author of these
+routines has avoided to do so far.
+
+http://www.unicode.org/unicode/reports/tr11/
+
+Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+"""
from __future__ import division
-
+
# std imports
import os
import sys
import warnings
# local
-from .table_wide import WIDE_EASTASIAN
-from .table_zero import ZERO_WIDTH
+from .table_wide import WIDE_EASTASIAN
+from .table_zero import ZERO_WIDTH
from .unicode_versions import list_versions
-
+
try:
from functools import lru_cache
except ImportError:
# lru_cache was added in Python 3.2
from backports.functools_lru_cache import lru_cache
-
+
# global cache
_UNICODE_CMPTABLE = None
_PY3 = (sys.version_info[0] >= 3)
@@ -110,42 +110,42 @@ ZERO_WIDTH_CF = set([
def _bisearch(ucs, table):
- """
- Auxiliary function for binary search in interval table.
-
- :arg int ucs: Ordinal value of unicode character.
- :arg list table: List of starting and ending ranges of ordinal values,
- in form of ``[(start, end), ...]``.
- :rtype: int
- :returns: 1 if ordinal value ucs is found within lookup table, else 0.
- """
- lbound = 0
+ """
+ Auxiliary function for binary search in interval table.
+
+ :arg int ucs: Ordinal value of unicode character.
+ :arg list table: List of starting and ending ranges of ordinal values,
+ in form of ``[(start, end), ...]``.
+ :rtype: int
+ :returns: 1 if ordinal value ucs is found within lookup table, else 0.
+ """
+ lbound = 0
ubound = len(table) - 1
-
- if ucs < table[0][0] or ucs > table[ubound][1]:
- return 0
- while ubound >= lbound:
- mid = (lbound + ubound) // 2
- if ucs > table[mid][1]:
- lbound = mid + 1
- elif ucs < table[mid][0]:
- ubound = mid - 1
- else:
- return 1
-
- return 0
-
-
+
+ if ucs < table[0][0] or ucs > table[ubound][1]:
+ return 0
+ while ubound >= lbound:
+ mid = (lbound + ubound) // 2
+ if ucs > table[mid][1]:
+ lbound = mid + 1
+ elif ucs < table[mid][0]:
+ ubound = mid - 1
+ else:
+ return 1
+
+ return 0
+
+
@lru_cache(maxsize=1000)
def wcwidth(wc, unicode_version='auto'):
- r"""
+ r"""
Given one Unicode character, return its printable length on a terminal.
-
+
:param str wc: A single Unicode character.
:param str unicode_version: A Unicode version number, such as
``'6.0.0'``, the list of available version levels may be
listed by pairing function :func:`list_versions`.
-
+
Any version string may be specified without error -- the nearest
matching version is selected. When ``latest`` (default), the
highest Unicode version level is used.
@@ -157,72 +157,72 @@ def wcwidth(wc, unicode_version='auto'):
character occupies on a graphic terminal (1 or 2) is returned.
:rtype: int
- The following have a column width of -1:
-
- - C0 control characters (U+001 through U+01F).
-
- - C1 control characters and DEL (U+07F through U+0A0).
-
- The following have a column width of 0:
-
+ The following have a column width of -1:
+
+ - C0 control characters (U+001 through U+01F).
+
+ - C1 control characters and DEL (U+07F through U+0A0).
+
+ The following have a column width of 0:
+
- Non-spacing and enclosing combining characters (general
category code Mn or Me in the Unicode database).
-
+
- NULL (``U+0000``).
-
+
- COMBINING GRAPHEME JOINER (``U+034F``).
-
+
- ZERO WIDTH SPACE (``U+200B``) *through*
RIGHT-TO-LEFT MARK (``U+200F``).
-
+
- LINE SEPARATOR (``U+2028``) *and*
PARAGRAPH SEPARATOR (``U+2029``).
-
+
- LEFT-TO-RIGHT EMBEDDING (``U+202A``) *through*
RIGHT-TO-LEFT OVERRIDE (``U+202E``).
-
+
- WORD JOINER (``U+2060``) *through*
INVISIBLE SEPARATOR (``U+2063``).
-
- The following have a column width of 1:
-
+
+ The following have a column width of 1:
+
- SOFT HYPHEN (``U+00AD``).
-
+
- All remaining characters, including all printable ISO 8859-1
and WGL4 characters, Unicode control characters, etc.
-
- The following have a column width of 2:
-
- - Spacing characters in the East Asian Wide (W) or East Asian
- Full-width (F) category as defined in Unicode Technical
- Report #11 have a column width of 2.
+
+ The following have a column width of 2:
+
+ - Spacing characters in the East Asian Wide (W) or East Asian
+ Full-width (F) category as defined in Unicode Technical
+ Report #11 have a column width of 2.
- Some kinds of Emoji or symbols.
- """
+ """
# NOTE: created by hand, there isn't anything identifiable other than
# general Cf category code to identify these, and some characters in Cf
# category code are of non-zero width.
- ucs = ord(wc)
+ ucs = ord(wc)
if ucs in ZERO_WIDTH_CF:
- return 0
-
- # C0/C1 control characters
- if ucs < 32 or 0x07F <= ucs < 0x0A0:
- return -1
-
+ return 0
+
+ # C0/C1 control characters
+ if ucs < 32 or 0x07F <= ucs < 0x0A0:
+ return -1
+
_unicode_version = _wcmatch_version(unicode_version)
- # combining characters with zero width
+ # combining characters with zero width
if _bisearch(ucs, ZERO_WIDTH[_unicode_version]):
- return 0
-
+ return 0
+
return 1 + _bisearch(ucs, WIDE_EASTASIAN[_unicode_version])
-
-
+
+
def wcswidth(pwcs, n=None, unicode_version='auto'):
- """
- Given a unicode string, return its printable length on a terminal.
-
+ """
+ Given a unicode string, return its printable length on a terminal.
+
:param str pwcs: Measure width of given unicode string.
:param int n: When ``n`` is None (default), return the length of the
entire string, otherwise width the first ``n`` characters specified.
@@ -234,19 +234,19 @@ def wcswidth(pwcs, n=None, unicode_version='auto'):
:returns: The width, in cells, necessary to display the first ``n``
characters of the unicode string ``pwcs``. Returns ``-1`` if
a non-printable character is encountered.
- """
- # pylint: disable=C0103
- # Invalid argument name "n"
-
- end = len(pwcs) if n is None else n
- idx = slice(0, end)
- width = 0
- for char in pwcs[idx]:
+ """
+ # pylint: disable=C0103
+ # Invalid argument name "n"
+
+ end = len(pwcs) if n is None else n
+ idx = slice(0, end)
+ width = 0
+ for char in pwcs[idx]:
wcw = wcwidth(char, unicode_version)
- if wcw < 0:
- return -1
+ if wcw < 0:
+ return -1
width += wcw
- return width
+ return width
@lru_cache(maxsize=128)
diff --git a/contrib/python/wcwidth/ya.make b/contrib/python/wcwidth/ya.make
index 64ebbbdc2bd..f1aeefaa1c0 100644
--- a/contrib/python/wcwidth/ya.make
+++ b/contrib/python/wcwidth/ya.make
@@ -1,9 +1,9 @@
PY23_LIBRARY()
-
+
LICENSE(MIT)
OWNER(g:python-contrib blinkov)
-
+
VERSION(0.2.5)
PEERDIR(
@@ -16,15 +16,15 @@ IF (PYTHON2)
)
ENDIF()
-PY_SRCS(
- TOP_LEVEL
- wcwidth/__init__.py
- wcwidth/table_wide.py
- wcwidth/table_zero.py
+PY_SRCS(
+ TOP_LEVEL
+ wcwidth/__init__.py
+ wcwidth/table_wide.py
+ wcwidth/table_zero.py
wcwidth/unicode_versions.py
- wcwidth/wcwidth.py
-)
-
+ wcwidth/wcwidth.py
+)
+
RESOURCE_FILES(
PREFIX contrib/python/wcwidth/
.dist-info/METADATA
@@ -33,7 +33,7 @@ RESOURCE_FILES(
NO_LINT()
-END()
+END()
RECURSE_FOR_TESTS(
tests
diff --git a/contrib/python/ya.make b/contrib/python/ya.make
index 7266bf189e9..d01ced9f3aa 100644
--- a/contrib/python/ya.make
+++ b/contrib/python/ya.make
@@ -570,7 +570,7 @@ RECURSE(
jupyterhub-traefik-proxy
jupytext
kaitaistruct
- kazoo
+ kazoo
Keras-Preprocessing
kiwisolver
kombu
@@ -622,7 +622,7 @@ RECURSE(
mercurial
mistune
mitmproxy
- mkdocs
+ mkdocs
mkdocs-material
mock
model-mommy