diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/engine/engine.go | 6 | ||||
| -rw-r--r-- | internal/engine/exclude_test.go | 7 | ||||
| -rw-r--r-- | internal/extract/plain.go | 12 | ||||
| -rw-r--r-- | internal/extract/plain_test.go | 16 |
4 files changed, 35 insertions, 6 deletions
diff --git a/internal/engine/engine.go b/internal/engine/engine.go index 7a83ccd..00a249d 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -93,8 +93,12 @@ func Load(mainFile string, names ...string) (*Engine, []*config.Diag) { // With no directory to compile them for, krino.conf's excludes are // still checked, so a mistake is reported before one is included // (review cli F10). + // Compiled with the defaults' case and fold, as a directory without + // settings of its own would compile them (triage 28g). + def := cfg.Main.Defaults.Over(config.Builtin()) + opt := cond.Options{IgnoreCase: def.Case == config.CaseIgnore, Fold: def.Fold} for _, x := range cfg.Main.Excludes { - _, cerrs := cond.Compile(cfg.Main.File, x.When, cond.Options{IgnoreCase: true, Fold: true}) + _, cerrs := cond.Compile(cfg.Main.File, x.When, opt) errs = append(errs, cerrs...) } } diff --git a/internal/engine/exclude_test.go b/internal/engine/exclude_test.go index cd1cc4b..8308a82 100644 --- a/internal/engine/exclude_test.go +++ b/internal/engine/exclude_test.go @@ -261,6 +261,13 @@ func TestLoadChecksMainExcludesWithoutDirectories(t *testing.T) { if _, errs := Load(main); len(errs) == 0 { t.Error("a broken krino.conf exclude was not reported") } + // Checked with the defaults' case and fold, as a directory would compile + // them (triage 28g): a keyword of a lone combining mark is empty only + // when folded. + main = writeConfig(t, h, "(include)\n(defaults (fold no))\n(exclude (content \"\u0301\"))\n", nil) + if _, errs := Load(main); len(errs) != 0 { + t.Errorf("checked with fold on, though the defaults say no: %v", errs) + } } // TestNoTextFormatIsNoMatch: a file whose format has no text cannot contain diff --git a/internal/extract/plain.go b/internal/extract/plain.go index 3f04c7e..ce9dedc 100644 --- a/internal/extract/plain.go +++ b/internal/extract/plain.go @@ -142,13 +142,15 @@ func decodeUTF16(b []byte, order binary.ByteOrder) string { } // decodeLatin1 decodes b as Latin-1: each byte is its own Unicode code -// point. +// point. Built directly as UTF-8 (at most two bytes per input byte), not +// through a []rune of four bytes per input byte (triage 28d). func decodeLatin1(b []byte) string { - r := make([]rune, len(b)) - for i, c := range b { - r[i] = rune(c) + var s strings.Builder + s.Grow(len(b) * 2) + for _, c := range b { + s.WriteRune(rune(c)) } - return string(r) + return s.String() } // stripMarkup turns decoded HTML/XML/SVG text into plain text: a small diff --git a/internal/extract/plain_test.go b/internal/extract/plain_test.go index 5752bf8..c8e1008 100644 --- a/internal/extract/plain_test.go +++ b/internal/extract/plain_test.go @@ -3,6 +3,7 @@ package extract import ( + "bytes" "context" "errors" "os" @@ -228,3 +229,18 @@ func TestSniffRuneStraddlingSampleBoundary(t *testing.T) { t.Errorf("got tail %q, want it to end in %q", got[len(got)-8:], want) } } + +// TestLatin1DecodingMemory: decoding Latin-1 allocates about what the UTF-8 +// result needs (at most two bytes per input byte), not a four-byte rune per +// input byte on top of it (triage 28d). +func TestLatin1DecodingMemory(t *testing.T) { + data := bytes.Repeat([]byte("Gr\xfc\xdfe "), 16000) + r := testing.Benchmark(func(b *testing.B) { + for range b.N { + decodeLatin1(data) + } + }) + if got, limit := r.AllocedBytesPerOp(), int64(3*len(data)); got > limit { + t.Errorf("decoding %d bytes allocates %d bytes, over %d", len(data), got, limit) + } +} |
