Portable runtime regular expressions with deterministic work limits
///|
test {
let pattern = "(a|b)+"
let regex = @regex.Regex::compile(pattern)
match regex.matches("!abba!", work=@regex.WorkLimit::new(10000)) {
Complete(matched, used) => {
assert_true(matched)
assert_true(used > 0)
}
Exhausted(_) => fail("Expected enough work")
}
assert_eq(regex.matches("abba", work=@regex.WorkLimit::new(0)), Exhausted(0))
}| Operation | Charge before work |
|---|---|
| Input scan | UTF-16 length plus one end marker, even for an early match |
| Initial scratch | Two cells per NFA node |
| Closure | One per popped node, plus one per stack push/pop and output append |
| Class membership | Interval count plus one, an upper bound on the tree walk |
| Key construction | One per allocated key cell and copied node |
| State indexing | One per hashed word, probe and equality word examined |
| Index growth | New slot cells, then one per existing entry and rehash probe |
| Transition table | One per symbol/end cell, plus two state record fields |
| Growable buffers | New fixed capacity plus copied live cells, then one per store |
| Buffer clearing | One per live cell cleared |
| Pattern/input | Outcome/units | Native ms / MiB RSS | JS ms / MiB RSS |
|---|---|---|---|
| Morphir FQName, 20-unit name | Match / 801 | <1 / 2.0 | <1 / 49.4 |
| Morphir FQName, 97-unit name | Match / 2,012 | <1 / 2.0 | 1 / 49.5 |
| ^(?:a?){150}a{150}$, ten a units | Non-match / 28,229 | <1 / 2.1 | 2 / 55.1 |
| a(?:a\|b){20}c, 90,000 pseudo-random a/b units | Exhausted / 100,000 | <1 / 2.7 | 1 / 60.4 |
| ^a+$, 90,000 a units | Match / 90,119 | <1 / 2.3 | 2 / 60.5 |
| ^(?:a+)+$, 90,000 a units then ! | Non-match / 90,134 | <1 / 2.3 | 2 / 60.6 |
| ^(?:a\|aa)+$, same input | Non-match / 90,169 | <1 / 2.3 | 2 / 61.0 |
| ^a+$, ten million a units | Exhausted / 0 | <1 / 40.2 | <1 / 453.2 |
| Core path | Module path |
|---|---|
| internal/regex_engine/shared_types | internal/shared_types |
| internal/regex_engine/shared_types/rechar_set | internal/shared_types/rechar_set |
| string/internal/regex_engine | internal/regex_engine |
| string/internal/regex_engine/ast | internal/regex_engine/ast |
| string/internal/regex_engine/symbol_map | internal/regex_engine/symbol_map |
| string/internal/regex_parser | internal/regex_parser |
| string/regex_profile.mbt, string/regex_utf16.mbt | Same file names |
pub(all) suberror CompileError {
InvalidPattern(String)
UnsupportedPattern(String)
CompilationLimit(CompileLimit)
} derive(Debug)fn CompileLimits::new(source_units? : Int, nesting? : Int, expanded_units? : Int) -> CompileLimits raise ConfigurationErrorpub struct Regex {
// private fields
}Install
Download zipPortable runtime regular expressions with deterministic work limits