Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster regexp prefixes #728

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Faster regexp prefixes #728

wants to merge 3 commits into from

Conversation

bboreham
Copy link
Contributor

@bboreham bboreham commented Oct 22, 2024

This is cherry-picking prometheus/prometheus#15210 and prometheus/prometheus#15237.

Do a better job of regexps with a long series of choices followed by .*, like:

		"(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuSoAl.*|qbvKMimS.*|IecrXtPa.*|seTckYqt.*|NxnyHkgB.*|fIDlOgKb.*|UhlWIygH.*|OtNoJxHG.*|cUTkFVIV.*|mTgFIHjr.*|jQkoIDtE.*|PPMKxRXl.*|AwMfwVkQ.*|CQyMrTQJ.*|BzrqxVSi.*|nTpcWuhF.*|PertdywG.*|ZZDgCtXN.*|WWdDPyyE.*|uVtNQsKk.*|BdeCHvPZ.*|wshRnFlH.*|aOUIitIp.*|RxZeCdXT.*|CFZMslCj.*|AVBZRDxl.*|IzIGCnhw.*|ythYuWiz.*|oztXVXhl.*|VbLkwqQx.*|qvaUgyVC.*|VawUjPWC.*|ecloYJuj.*|boCLTdSU.*|uPrKeAZx.*|hrMWLWBq.*|JOnUNHRM.*|rYnujkPq.*|dDEdZhIj.*|DRrfvugG.*|yEGfDxVV.*|YMYdJWuP.*|PHUQZNWM.*|AmKNrLis.*|zTxndVfn.*|FPsHoJnc.*|EIulZTua.*|KlAPhdzg.*|ScHJJCLt.*|NtTfMzME.*|eMCwuFdo.*|SEpJVJbR.*|cdhXZeCx.*|sAVtBwRh.*|kVFEVcMI.*|jzJrxraA.*|tGLHTell.*|NNWoeSaw.*|DcOKSetX.*|UXZAJyka.*|THpMphDP.*|rizheevl.*|kDCBRidd.*|pCZZRqyu.*|pSygkitl.*|SwZGkAaW.*|wILOrfNX.*|QkwVOerj.*|kHOMxPDr.*|EwOVycJv.*|AJvtzQFS.*|yEOjKYYB.*|LizIINLL.*|JBRSsfcG.*|YPiUqqNl.*|IsdEbvee.*|MjEpGcBm.*|OxXZVgEQ.*|xClXGuxa.*|UzRCGFEb.*|buJbvfvA.*|IPZQxRet.*|oFYShsMc.*|oBHffuHO.*|bzzKrcBR.*|KAjzrGCl.*|IPUsAVls.*|OGMUMbIU.*|gyDccHuR.*|bjlalnDd.*|ZLWjeMna.*|fdsuIlxQ.*|dVXtiomV.*|XxedTjNg.*|XWMHlNoA.*|nnyqArQX.*|opfkWGhb.*|wYtnhdYb.*))",

Benchmarks:

goos: linux
goarch: amd64
pkg: github.com/prometheus/prometheus/model/labels
cpu: Intel(R) Core(TM) i7-14700K
                                                             │  before.txt   │              after.txt              │
                                                             │    sec/op     │    sec/op     vs base               │
FastRegexMatcher/#00-28                                         30.64n ±  1%   30.54n ±  0%   -0.31% (p=0.013 n=6)
FastRegexMatcher/()-28                                          30.53n ±  1%   30.54n ±  0%        ~ (p=0.797 n=6)
FastRegexMatcher/foo-28                                         34.98n ±  2%   35.49n ±  4%        ~ (p=0.132 n=6)
FastRegexMatcher/foo()-28                                       32.72n ±  2%   32.48n ±  1%        ~ (p=0.132 n=6)
FastRegexMatcher/^foo-28                                        32.64n ±  1%   32.46n ±  1%        ~ (p=0.310 n=6)
FastRegexMatcher/(foo|bar)-28                                   40.03n ±  2%   39.81n ±  1%        ~ (p=0.240 n=6)
FastRegexMatcher/foo.*-28                                       88.04n ±  4%   88.31n ±  3%        ~ (p=0.818 n=6)
FastRegexMatcher/.*foo-28                                       92.68n ±  2%   93.71n ±  3%        ~ (p=0.394 n=6)
FastRegexMatcher/^.*foo$-28                                     92.52n ±  2%   91.69n ±  3%        ~ (p=0.394 n=6)
FastRegexMatcher/^.+foo$-28                                     92.53n ±  2%   93.77n ±  4%        ~ (p=0.394 n=6)
FastRegexMatcher/.?-28                                          48.95n ±  3%   45.94n ±  1%   -6.15% (p=0.002 n=6)
FastRegexMatcher/.*-28                                          56.60n ±  1%   56.67n ±  0%        ~ (p=0.818 n=6)
FastRegexMatcher/().*-28                                        56.60n ±  3%   56.65n ±  1%        ~ (p=0.699 n=6)
FastRegexMatcher/.*()-28                                        56.43n ±  1%   56.74n ±  4%        ~ (p=0.071 n=6)
FastRegexMatcher/().*()-28                                      56.44n ±  0%   56.75n ±  0%   +0.54% (p=0.009 n=6)
FastRegexMatcher/.+-28                                          64.14n ±  1%   58.23n ±  0%   -9.22% (p=0.002 n=6)
FastRegexMatcher/.+()-28                                        63.91n ±  1%   58.34n ±  1%   -8.72% (p=0.002 n=6)
FastRegexMatcher/foo.+-28                                       89.91n ±  7%   87.30n ±  5%        ~ (p=0.132 n=6)
FastRegexMatcher/.+foo-28                                       92.22n ±  3%   91.93n ±  3%        ~ (p=0.937 n=6)
FastRegexMatcher/foo_.+-28                                      79.14n ±  9%   79.27n ±  5%        ~ (p=0.589 n=6)
FastRegexMatcher/foo_.*-28                                      77.31n ± 10%   80.60n ±  4%        ~ (p=0.180 n=6)
FastRegexMatcher/.*foo.*-28                                     143.8n ±  0%   144.4n ±  0%   +0.42% (p=0.011 n=6)
FastRegexMatcher/.+foo.+-28                                     149.6n ±  1%   148.5n ±  0%   -0.74% (p=0.004 n=6)
FastRegexMatcher/(?s:.*)-28                                     30.52n ±  0%   30.57n ±  0%        ~ (p=0.121 n=6)
FastRegexMatcher/(?s:.+)-28                                     33.80n ±  2%   33.80n ±  0%        ~ (p=1.000 n=6)
FastRegexMatcher/(?s:^.*foo$)-28                                91.40n ±  3%   92.20n ±  4%        ~ (p=0.699 n=6)
FastRegexMatcher/(?i:foo)-28                                    59.48n ± 11%   58.60n ±  1%   -1.48% (p=0.002 n=6)
FastRegexMatcher/(?i:(foo|bar))-28                              136.3n ±  0%   133.5n ±  0%   -2.09% (p=0.002 n=6)
FastRegexMatcher/(?i:(foo1|foo2|bar))-28                        222.1n ±  1%   223.2n ±  1%   +0.47% (p=0.045 n=6)
FastRegexMatcher/^(?i:foo|oo)|(bar)$-28                         507.7n ±  1%   509.7n ±  1%        ~ (p=0.310 n=6)
FastRegexMatcher/(?i:(foo1|foo2|aaa|bbb|ccc|ddd|e-28            687.1n ±  1%   526.0n ±  0%  -23.44% (p=0.002 n=6)
FastRegexMatcher/((.*)(bar|b|buzz)(.+)|foo)$-28                 345.2n ±  0%   344.1n ±  0%   -0.33% (p=0.002 n=6)
FastRegexMatcher/^$-28                                          30.58n ±  0%   30.54n ±  1%        ~ (p=0.513 n=6)
FastRegexMatcher/(prometheus|api_prom)_api_v1_.+-28             111.3n ±  0%   110.6n ±  0%   -0.58% (p=0.002 n=6)
FastRegexMatcher/10\.0\.(1|2)\.+-28                             80.71n ±  9%   80.34n ±  6%        ~ (p=0.623 n=6)
FastRegexMatcher/10\.0\.(1|2).+-28                              81.55n ±  9%   82.96n ± 10%        ~ (p=0.937 n=6)
FastRegexMatcher/((fo(bar))|.+foo)-28                           183.3n ±  1%   186.5n ±  0%   +1.75% (p=0.002 n=6)
FastRegexMatcher/zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKM-28            183.1n ±  1%   178.6n ±  1%   -2.48% (p=0.002 n=6)
FastRegexMatcher/jyyfj00j0061|jyyfj00j0062|jyyfj9-28            168.3n ±  2%   181.0n ±  1%   +7.54% (p=0.002 n=6)
FastRegexMatcher/(?i:(zQPbMkNO|NNSPdvMi|iWuuSoAl|-28            694.3n ±  2%   527.4n ±  0%  -24.05% (p=0.002 n=6)
FastRegexMatcher/(?i:(AAAAAAAAAAAAAAAAAAAAAAAA|BB-28            212.9n ±  0%   211.2n ±  1%   -0.82% (p=0.002 n=6)
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS-28            171.8n ±  1%   172.2n ±  1%        ~ (p=0.199 n=6)
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS#01-28         839.6n ±  1%   299.9n ±  0%  -64.28% (p=0.002 n=6)
FastRegexMatcher/(?i:(.*zQPbMkNO|.*NNSPdvMi|.*iWu-28            5.158µ ±  0%   5.150µ ±  0%        ~ (p=0.065 n=6)
FastRegexMatcher/fo.?-28                                        89.38n ±  1%   85.39n ±  9%        ~ (p=0.310 n=6)
FastRegexMatcher/foo.?-28                                       89.31n ±  4%   89.84n ±  2%        ~ (p=0.589 n=6)
FastRegexMatcher/f.?o-28                                        90.08n ±  4%   84.83n ±  7%   -5.83% (p=0.009 n=6)
FastRegexMatcher/.*foo.?-28                                     149.4n ±  1%   148.8n ±  1%        ~ (p=0.104 n=6)
FastRegexMatcher/.?foo.+-28                                     144.0n ±  1%   143.0n ±  0%   -0.69% (p=0.006 n=6)
FastRegexMatcher/foo.?|bar-28                                   138.6n ±  4%   139.2n ±  3%        ~ (p=0.937 n=6)
FastRegexMatcher/ſſs-28                                         34.96n ±  2%   35.95n ±  1%   +2.83% (p=0.004 n=6)
FastRegexMatcher/.*-.*-.*-.*-.*-28                              130.4n ±  1%   126.1n ±  1%   -3.33% (p=0.002 n=6)
FastRegexMatcher/(.+)-(.+)-(.+)-(.+)-(.+)-28                    130.3n ±  1%   125.7n ±  1%   -3.57% (p=0.002 n=6)
FastRegexMatcher/((.*))(?i:f)((.*))o((.*))o((.*))-28            2.751µ ±  0%   2.760µ ±  0%   +0.33% (p=0.009 n=6)
FastRegexMatcher/((.*))f((.*))(?i:o)((.*))o((.*))-28            2.190µ ±  0%   2.201µ ±  0%   +0.53% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=none/ascii=true-28        4.152n ±  0%   4.653n ±  1%  +12.07% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=none/ascii=false-28       111.5n ±  0%   113.4n ±  0%   +1.75% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=first/ascii=true-28      17.150n ±  1%   7.856n ±  1%  -54.20% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=first/ascii=false-28      135.4n ±  0%   129.4n ±  1%   -4.43% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=true-28       16.995n ±  1%   7.833n ±  0%  -53.91% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=false-28       125.7n ±  0%   126.7n ±  2%   +0.84% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=all/ascii=true-28        18.875n ±  1%   9.577n ±  0%  -49.26% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=all/ascii=false-28        124.5n ±  0%   120.0n ±  1%   -3.61% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=none/ascii=true-28       32.64n ±  2%   38.75n ±  0%  +18.70% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=none/ascii=false-28      1.734µ ±  2%   1.728µ ±  1%        ~ (p=0.169 n=6)
ToNormalizedLower/length=100/uppercase=first/ascii=true-28      61.87n ±  1%   42.42n ±  1%  -31.44% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=first/ascii=false-28     1.805µ ±  0%   1.794µ ±  1%        ~ (p=0.104 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=true-28       63.37n ±  0%   40.45n ±  0%  -36.16% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=false-28      1.745µ ±  1%   1.735µ ±  0%   -0.54% (p=0.037 n=6)
ToNormalizedLower/length=100/uppercase=all/ascii=true-28        81.14n ±  1%   61.95n ±  1%  -23.65% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=all/ascii=false-28       1.683µ ±  1%   1.669µ ±  1%   -0.86% (p=0.006 n=6)
ToNormalizedLower/length=1000/uppercase=none/ascii=true-28      285.8n ±  1%   340.6n ±  1%  +19.17% (p=0.002 n=6)
ToNormalizedLower/length=1000/uppercase=none/ascii=false-28     15.13µ ±  0%   15.12µ ±  0%        ~ (p=0.699 n=6)
ToNormalizedLower/length=1000/uppercase=first/ascii=true-28     435.6n ±  5%   524.8n ±  1%  +20.46% (p=0.002 n=6)
ToNormalizedLower/length=1000/uppercase=first/ascii=false-28    15.59µ ±  0%   15.55µ ±  1%        ~ (p=0.485 n=6)
ToNormalizedLower/length=1000/uppercase=last/ascii=true-28      433.1n ±  1%   436.4n ±  1%        ~ (p=0.065 n=6)
ToNormalizedLower/length=1000/uppercase=last/ascii=false-28     15.08µ ±  0%   15.07µ ±  1%        ~ (p=0.909 n=6)
ToNormalizedLower/length=1000/uppercase=all/ascii=true-28       603.4n ±  1%   672.9n ±  1%  +11.50% (p=0.002 n=6)
ToNormalizedLower/length=1000/uppercase=all/ascii=false-28      14.43µ ±  0%   14.38µ ±  0%   -0.36% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=none/ascii=true-28      1.111µ ±  0%   1.305µ ±  2%  +17.47% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=none/ascii=false-28     58.91µ ±  6%   58.68µ ±  0%   -0.39% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=first/ascii=true-28     1.642µ ±  2%   1.991µ ±  1%  +21.29% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=first/ascii=false-28    60.57µ ±  1%   60.78µ ±  0%        ~ (p=0.149 n=6)
ToNormalizedLower/length=4000/uppercase=last/ascii=true-28      1.656µ ±  4%   1.810µ ±  2%   +9.33% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=last/ascii=false-28     58.72µ ±  2%   58.70µ ±  4%        ~ (p=0.974 n=6)
ToNormalizedLower/length=4000/uppercase=all/ascii=true-28       2.513µ ±  1%   2.678µ ±  4%   +6.59% (p=0.002 n=6)
ToNormalizedLower/length=4000/uppercase=all/ascii=false-28      56.58µ ±  0%   56.47µ ±  0%        ~ (p=0.240 n=6)
ZeroOrOneCharacterStringMatcher-28                              2.436n ±  0%   2.434n ±  1%        ~ (p=0.515 n=6)
geomean                                                         219.0n         209.1n         -4.49%

                                                             │   before.txt   │                after.txt                 │
                                                             │      B/op      │     B/op      vs base                    │
FastRegexMatcher/#00-28                                          0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/()-28                                           0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo-28                                          0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo()-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^foo-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(foo|bar)-28                                    0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.*-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^.*foo$-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^.+foo$-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.?-28                                           0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*-28                                           0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/().*-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*()-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/().*()-28                                       0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+-28                                           0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+()-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.+-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+foo-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo_.+-28                                       0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo_.*-28                                       0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo.*-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+foo.+-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:.*)-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:.+)-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:^.*foo$)-28                                 0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:foo)-28                                     0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo|bar))-28                               0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo1|foo2|bar))-28                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^(?i:foo|oo)|(bar)$-28                          0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo1|foo2|aaa|bbb|ccc|ddd|e-28             560.0 ± 0%       240.0 ± 0%   -57.14% (p=0.002 n=6)
FastRegexMatcher/((.*)(bar|b|buzz)(.+)|foo)$-28                  0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^$-28                                           0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(prometheus|api_prom)_api_v1_.+-28              0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/10\.0\.(1|2)\.+-28                              0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/10\.0\.(1|2).+-28                               0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((fo(bar))|.+foo)-28                            0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKM-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/jyyfj00j0061|jyyfj00j0062|jyyfj9-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO|NNSPdvMi|iWuuSoAl|-28             560.0 ± 0%       240.0 ± 0%   -57.14% (p=0.002 n=6)
FastRegexMatcher/(?i:(AAAAAAAAAAAAAAAAAAAAAAAA|BB-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS#01-28          560.0 ± 0%         0.0 ± 0%  -100.00% (p=0.002 n=6)
FastRegexMatcher/(?i:(.*zQPbMkNO|.*NNSPdvMi|.*iWu-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/fo.?-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.?-28                                        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/f.?o-28                                         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo.?-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.?foo.+-28                                      0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.?|bar-28                                    0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/ſſs-28                                          0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*-.*-.*-.*-.*-28                               0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(.+)-(.+)-(.+)-(.+)-(.+)-28                     0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((.*))(?i:f)((.*))o((.*))o((.*))-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((.*))f((.*))(?i:o)((.*))o((.*))-28             0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=none/ascii=true-28         0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=none/ascii=false-28        9.000 ± 0%       9.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=first/ascii=true-28        16.00 ± 0%        0.00 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=first/ascii=false-28       17.00 ± 0%       11.00 ± 0%   -35.29% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=true-28         16.00 ± 0%        0.00 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=false-28        11.00 ± 0%       11.00 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=all/ascii=true-28          16.00 ± 0%        0.00 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=all/ascii=false-28         22.00 ± 0%       16.00 ± 0%   -27.27% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=none/ascii=true-28        0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=none/ascii=false-28     1.050Ki ± 0%     1.050Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=first/ascii=true-28       112.0 ± 0%         0.0 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=first/ascii=false-28    1.104Ki ± 0%     1.061Ki ± 0%    -3.98% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=true-28        112.0 ± 0%         0.0 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=false-28     1.061Ki ± 0%     1.061Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=all/ascii=true-28         112.0 ± 0%         0.0 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=all/ascii=false-28      1.137Ki ± 0%     1.094Ki ± 0%    -3.78% (p=0.002 n=6)
ToNormalizedLower/length=1000/uppercase=none/ascii=true-28       0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=none/ascii=false-28    4.862Ki ± 0%     4.862Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=first/ascii=true-28    1.000Ki ± 0%     1.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=first/ascii=false-28   5.375Ki ± 0%     5.375Ki ± 0%         ~ (p=1.000 n=6)
ToNormalizedLower/length=1000/uppercase=last/ascii=true-28     1.000Ki ± 0%     1.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=last/ascii=false-28    4.975Ki ± 0%     4.975Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=all/ascii=true-28      1.000Ki ± 0%     1.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=all/ascii=false-28     5.712Ki ± 0%     5.712Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=none/ascii=true-28       0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=none/ascii=false-28    17.41Ki ± 0%     17.41Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=first/ascii=true-28    4.000Ki ± 0%     4.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=first/ascii=false-28   19.49Ki ± 0%     19.49Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=last/ascii=true-28     4.000Ki ± 0%     4.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=last/ascii=false-28    17.89Ki ± 0%     17.89Ki ± 0%         ~ (p=1.000 n=6)
ToNormalizedLower/length=4000/uppercase=all/ascii=true-28      4.000Ki ± 0%     4.000Ki ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=all/ascii=false-28     20.91Ki ± 0%     20.91Ki ± 0%         ~ (p=1.000 n=6) ¹
ZeroOrOneCharacterStringMatcher-28                               0.000 ± 0%       0.000 ± 0%         ~ (p=1.000 n=6) ¹
geomean                                                                     ²                 ?                      ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean

                                                             │  before.txt   │               after.txt                │
                                                             │   allocs/op   │ allocs/op   vs base                    │
FastRegexMatcher/#00-28                                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/()-28                                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo-28                                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo()-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^foo-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(foo|bar)-28                                   0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.*-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^.*foo$-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^.+foo$-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.?-28                                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*-28                                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/().*-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*()-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/().*()-28                                      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+-28                                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+()-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.+-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+foo-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo_.+-28                                      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo_.*-28                                      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo.*-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.+foo.+-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:.*)-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:.+)-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?s:^.*foo$)-28                                0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:foo)-28                                    0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo|bar))-28                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo1|foo2|bar))-28                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^(?i:foo|oo)|(bar)$-28                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(foo1|foo2|aaa|bbb|ccc|ddd|e-28           18.000 ± 0%     3.000 ± 0%   -83.33% (p=0.002 n=6)
FastRegexMatcher/((.*)(bar|b|buzz)(.+)|foo)$-28                 0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/^$-28                                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(prometheus|api_prom)_api_v1_.+-28             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/10\.0\.(1|2)\.+-28                             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/10\.0\.(1|2).+-28                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((fo(bar))|.+foo)-28                           0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKM-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/jyyfj00j0061|jyyfj00j0062|jyyfj9-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO|NNSPdvMi|iWuuSoAl|-28           18.000 ± 0%     3.000 ± 0%   -83.33% (p=0.002 n=6)
FastRegexMatcher/(?i:(AAAAAAAAAAAAAAAAAAAAAAAA|BB-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuS#01-28         18.00 ± 0%      0.00 ± 0%  -100.00% (p=0.002 n=6)
FastRegexMatcher/(?i:(.*zQPbMkNO|.*NNSPdvMi|.*iWu-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/fo.?-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.?-28                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/f.?o-28                                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*foo.?-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.?foo.+-28                                     0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/foo.?|bar-28                                   0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/ſſs-28                                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/.*-.*-.*-.*-.*-28                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/(.+)-(.+)-(.+)-(.+)-(.+)-28                    0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((.*))(?i:f)((.*))o((.*))o((.*))-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
FastRegexMatcher/((.*))f((.*))(?i:o)((.*))o((.*))-28            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=none/ascii=true-28        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=none/ascii=false-28       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=first/ascii=true-28       1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=first/ascii=false-28      1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=true-28        1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=last/ascii=false-28       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=10/uppercase=all/ascii=true-28         1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=10/uppercase=all/ascii=false-28        1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=none/ascii=true-28       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=none/ascii=false-28      4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=first/ascii=true-28      1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=first/ascii=false-28     5.000 ± 0%     4.000 ± 0%   -20.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=true-28       1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=last/ascii=false-28      4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=100/uppercase=all/ascii=true-28        1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.002 n=6)
ToNormalizedLower/length=100/uppercase=all/ascii=false-28       5.000 ± 0%     5.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=none/ascii=true-28      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=none/ascii=false-28     4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=first/ascii=true-28     1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=first/ascii=false-28    5.000 ± 0%     5.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=last/ascii=true-28      1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=last/ascii=false-28     4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=all/ascii=true-28       1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=1000/uppercase=all/ascii=false-28      5.000 ± 0%     5.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=none/ascii=true-28      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=none/ascii=false-28     4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=first/ascii=true-28     1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=first/ascii=false-28    5.000 ± 0%     5.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=last/ascii=true-28      1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=last/ascii=false-28     4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=all/ascii=true-28       1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=6) ¹
ToNormalizedLower/length=4000/uppercase=all/ascii=false-28      5.000 ± 0%     5.000 ± 0%         ~ (p=1.000 n=6) ¹
ZeroOrOneCharacterStringMatcher-28                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=6) ¹
geomean                                                                    ²               ?                      ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean

@bboreham bboreham force-pushed the faster-regexp-prefixes branch 2 times, most recently from f9ee6fd to e4f85f7 Compare October 31, 2024 09:19
@bboreham bboreham marked this pull request as ready for review October 31, 2024 09:28
@bboreham bboreham force-pushed the faster-regexp-prefixes branch from 30ca2ce to 5e6f0bd Compare November 4, 2024 12:23
Given a regex like `a(b|c).*`, find ab and ac as prefixes.
Even though the original may have looked like `ab.*|ac.*`, Go extracts
the sub-prefixes, but we want the longer strings when the optimisation
to put them into a map applies.

Signed-off-by: Bryan Boreham <[email protected]>
Up to 32-byte values this saves garbage, runs faster.
For prefixes, only `toLower` the part we need for the map lookup.

Split toNormalisedLower into fast and slow paths, to avoid a penalty
for the `copy` call in the case where no allocations are done.

Signed-off-by: Bryan Boreham <[email protected]>
The case-sensitive path goes ~10% faster if we don't stop to ask whether
it is insensitive.

Signed-off-by: Bryan Boreham <[email protected]>
@bboreham bboreham force-pushed the faster-regexp-prefixes branch from 5e6f0bd to 0f12cf6 Compare November 8, 2024 11:50
Copy link
Collaborator

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting PR. I think the overall idea is nice, but I think I've found a potential issue. Generally speaking, I think we're lacking some tests around edge cases that could be introduced by these changes. Also the fact that I've run fuzzy tests for 5m and they passed, but my simple test has failed is a bit concerning about the tests coverage we have here :|

m.setMatches = matches
m.stringMatcher = stringMatcherFromRegexp(parsed)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I think this is superfluous and can be removed to keep code easier to follow. If there are setMatches we only use them in matcher (see compileMatchStringFunction()) so stringMatcher is never used.

@@ -164,27 +171,27 @@ func (m *FastRegexMatcher) IsOptimized() bool {
// findSetMatches extract equality matches from a regexp.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This comment needs to be updated. It returns prefixes too now.

}

func findSetMatchesFromAlternate(re *syntax.Regexp, base string) (matches []string, matchesCaseSensitive bool) {
func findSetMatchesFromAlternate(re *syntax.Regexp, base string) (matches []string, prefixes []prefixMatcher, matchesCaseSensitive bool) {
matches = []string{}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? 🤔

if i > 0 && re.Sub[i].Op == syntax.OpStar && len(matches) > 0 {
prefixes = make([]prefixMatcher, 0, len(matches))
for _, prefix := range matches {
right := stringMatcherFromRegexpInternal(re.Sub[i])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we're matching re.Sub[i] as the right side, but what if i is not the last sub of regexp and there are others?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example this test fails:

	const pattern = "a.*a|b.*b|c.*c|d.*d|e.*e|f.*f|g.*g|h.*h|i.*i|l.*l|m.*m|n.*n|o.*o|p.*p|q.*q|r.*r|s.*s|t.*t|u.*u|v.*v|z.*z"

	standard := regexp.MustCompile(pattern)
	require.True(t, standard.MatchString("aa"))
	require.True(t, standard.MatchString("aXa"))
	require.False(t, standard.MatchString("aXb"))

	matcher, err := newFastRegexMatcherWithoutCache(pattern)
	require.NoError(t, err)
	require.True(t, matcher.MatchString("aa"))
	require.True(t, matcher.MatchString("aXa"))
	require.False(t, matcher.MatchString("aXb"))

Comment on lines +271 to +273
if i == len(re.Sub)-1 && len(p) > 0 {
prefixes = append(prefixes, p...)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got lost here. What is this used for? Can we have a code commend to explain it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants