fix: bound the spelling checker's word cache
The remembered answers are keyed on user input and never evicted: a long session could grow the map without bound. Clear it at 10000 words and let it refill - a script repeats the same words, so re-checks are cheap.
This commit is contained in:
1 parent
823c9f2d0f
commit
b0bcb812b1
2 files changed
+38
No files matched your search
@@ -90,6 +90,12 @@ func (c *Checker) Add(word string) {
|
||||
|
||||
func normalize(w string) string { return strings.ReplaceAll(w, "’", "'") }
|
||||
|
||||
// cacheLimit bounds the remembered answers, which are keyed on user input:
|
||||
// a long session of typos would grow the map forever otherwise. When full,
|
||||
// the cache is cleared and refilled; a script repeats the same words, so
|
||||
// re-checks are cheap.
|
||||
const cacheLimit = 10000
|
||||
|
||||
// Check reports whether word is correct. Words with digits ("3rd", "R2D2")
|
||||
// and single letters are always accepted.
|
||||
func (c *Checker) Check(word string) bool {
|
||||
@@ -104,6 +110,9 @@ func (c *Checker) Check(word string) bool {
|
||||
}
|
||||
ok, found := c.cache[word]
|
||||
if !found {
|
||||
if len(c.cache) >= cacheLimit {
|
||||
clear(c.cache)
|
||||
}
|
||||
ok = c.dict.Check(word)
|
||||
c.cache[word] = ok
|
||||
}
|
||||
|
||||
@@ -180,6 +180,35 @@ func TestLatin1(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckerCacheBound(t *testing.T) {
|
||||
d, err := Parse([]byte("SET UTF-8\n"), []byte("1\nknown\n"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := NewChecker(d, nil)
|
||||
// letters encodes n in bijective base 26: distinct pure-letter words.
|
||||
letters := func(n int) string {
|
||||
var w []rune
|
||||
for {
|
||||
w = append([]rune{rune('a' + n%26)}, w...)
|
||||
if n < 26 {
|
||||
return string(w)
|
||||
}
|
||||
n = n/26 - 1
|
||||
}
|
||||
}
|
||||
for i := range 2 * cacheLimit {
|
||||
c.Check(letters(i))
|
||||
}
|
||||
if len(c.cache) > cacheLimit {
|
||||
t.Errorf("cache holds %d words, limit %d", len(c.cache), cacheLimit)
|
||||
}
|
||||
// The answers are unchanged by a clear.
|
||||
if !c.Check("known") || c.Check("knownn") {
|
||||
t.Error("wrong answers after the cache cleared")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWords(t *testing.T) {
|
||||
got := Words("Élise's well-known R2D2, l’homme… 'quoted' x")
|
||||
want := []Word{
|
||||
|
||||
Reference in new issue
Block a user