From a0bf6177e2463167107f07efe646cb230f46bff3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 21 Sep 2022 23:02:25 +0530 Subject: [PATCH] Use a LRUCache rather than an Unbounded one --- go.mod | 3 ++- go.sum | 6 +++-- tools/utils/cache.go | 59 +++++++++++++++++++++++++++++++++++++++++++ tools/utils/regexp.go | 43 +------------------------------ 4 files changed, 66 insertions(+), 45 deletions(-) create mode 100644 tools/utils/cache.go diff --git a/go.mod b/go.mod index 8dab033ca..badc3391d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924 + github.com/gammazero/deque v0.2.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.3.0 github.com/jamesruan/go-rfc1924 v0.0.0-20170108144916-2767ca7c638f @@ -11,7 +12,7 @@ require ( github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 - golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e + golang.org/x/exp v0.0.0-20220921164117-439092de6870 golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 ) diff --git a/go.sum b/go.sum index b12fdd30e..aa45016c9 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924 h1:DG4UyTVIujioxwJc8Zj8Nabz1L1wTgQ/xNBSQDfdP3I= github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924/go.mod h1:+NaH2gLeY6RPBPPQf4aRotPPStg+eXc8f9ZaE4vRfD4= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/gammazero/deque v0.2.0 h1:SkieyNB4bg2/uZZLxvya0Pq6diUlwx7m2TeT7GAIWaA= +github.com/gammazero/deque v0.2.0/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -21,8 +23,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e h1:Ctm9yurWsg7aWwIpH9Bnap/IdSVxixymIb3MhiMEQQA= -golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20220921164117-439092de6870 h1:j8b6j9gzSigH28O5SjSpQSSh9lFd6f5D/q0aHjNTulc= +golang.org/x/exp v0.0.0-20220921164117-439092de6870/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY= golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= diff --git a/tools/utils/cache.go b/tools/utils/cache.go new file mode 100644 index 000000000..20814a8d8 --- /dev/null +++ b/tools/utils/cache.go @@ -0,0 +1,59 @@ +// License: GPLv3 Copyright: 2022, Kovid Goyal, + +package utils + +import ( + "fmt" + "sync" + + "github.com/gammazero/deque" +) + +var _ = fmt.Print + +type LRUCache[K comparable, V any] struct { + data map[K]V + lock sync.RWMutex + max_size int + lru deque.Deque[K] +} + +func NewLRUCache[K comparable, V any](max_size int) *LRUCache[K, V] { + ans := LRUCache[K, V]{data: map[K]V{}, max_size: max_size} + return &ans +} + +func (self *LRUCache[K, V]) GetOrCreate(key K, create func(key K) (V, error)) (V, error) { + self.lock.RLock() + ans, found := self.data[key] + self.lock.RUnlock() + if found { + return ans, nil + } + ans, err := create(key) + if err == nil { + self.lock.Lock() + self.data[key] = ans + self.lru.PushFront(key) + if self.max_size > 0 && self.lru.Len() > self.max_size { + k := self.lru.PopBack() + delete(self.data, k) + } + self.lock.Unlock() + } + return ans, err +} + +func (self *LRUCache[K, V]) MustGetOrCreate(key K, create func(key K) V) V { + self.lock.RLock() + ans, found := self.data[key] + self.lock.RUnlock() + if found { + return ans + } + ans = create(key) + self.lock.Lock() + self.data[key] = ans + self.lock.Unlock() + return ans +} diff --git a/tools/utils/regexp.go b/tools/utils/regexp.go index 127d9f0b4..551575665 100644 --- a/tools/utils/regexp.go +++ b/tools/utils/regexp.go @@ -6,52 +6,11 @@ import ( "fmt" "regexp" "strings" - "sync" ) var _ = fmt.Print -type UnboundedCache[K comparable, V any] struct { - data map[K]V - lock sync.RWMutex -} - -func NewUnboundedCache[K comparable, V any]() *UnboundedCache[K, V] { - ans := UnboundedCache[K, V]{data: map[K]V{}} - return &ans -} - -func (self *UnboundedCache[K, V]) GetOrCreate(key K, create func(key K) (V, error)) (V, error) { - self.lock.RLock() - ans, found := self.data[key] - self.lock.RUnlock() - if found { - return ans, nil - } - ans, err := create(key) - if err == nil { - self.lock.Lock() - self.data[key] = ans - self.lock.Unlock() - } - return ans, err -} - -func (self *UnboundedCache[K, V]) MustGetOrCreate(key K, create func(key K) V) V { - self.lock.RLock() - ans, found := self.data[key] - self.lock.RUnlock() - if found { - return ans - } - ans = create(key) - self.lock.Lock() - self.data[key] = ans - self.lock.Unlock() - return ans -} - -var pat_cache = NewUnboundedCache[string, *regexp.Regexp]() +var pat_cache = NewLRUCache[string, *regexp.Regexp](128) type SubMatch struct { Text string