-
Notifications
You must be signed in to change notification settings - Fork 530
Add support for generics #111
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
Conversation
ac9b9a5 to
d2dc51b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks great! Some minor feedback here and there that will be easy to address.
4b931e8 to
b5cf3fc
Compare
|
Thank you for your great PR. In order to keep backwward compability, however, wouldn't it be better to keep the existing implementation as suggested in AskAlexSharov's comment? |
|
@SoMuchForSubtlety Please don't force-push when people are reviewing, it tends to really screw up comments. If you must force-push, please do it just before merging or before marking ready for review. |
|
@kasegao If this is marked as v2 of the lib we don't need backwards compat. |
|
@jefferai I misunderstood. Thank you! |
|
golangci-lint fails because of a few false positives. I could disable the offending linters (golint and gosec). There are warnings about other enabled linters being deprecated |
|
I just bumped the workflows version in CI in |
Rebasing on master gets rid of the Footnotes |
|
I removed some deprecated linters from the config -- didn't even realize we had a config and weren't using defaults. Hopefully that fixes it. |
96efe48 to
0f25fd8
Compare
Thanks, I rebased on master and at least locally golangci-lint doesn't complain any more. Is there anything else open I need to change? |
|
I will do another pass -- as for stuff outstanding I still have a slight preference not to do bare |
Do you mean // Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
var ent *entry[K, V]
if ent, ok = c.items[key]; ok {
return ent.value, true
}
return value, false
}or // Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
var ent *entry[K, V]
if ent, ok = c.items[key]; ok {
return ent.value, true
}
var empty V
return empty, false
}They are the same, but the seconds one makes it clearer that we are returning an empty value (at the cost of an added line). I would be happy to switch to either style. |
|
Hm. I keep forgetting that V is not necessarily Leave it be. |
|
Looks great! I have a question for anyone following this: I'm tempted to cut a final Thoughts? |
I agree (I do, though, wish Go Modules had a way to handle this cleaner). |
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 226µs ±33% 251µs ±20% ~ (p=0.886 n=4+4) CacheSerial/Set-4 176ns ± 0% 118ns ± 0% -32.66% (p=0.029 n=4+4) CacheSerial/Get-4 27.0ns ± 1% 21.0ns ± 1% -22.19% (p=0.029 n=4+4) CacheParallel/Set-4 274ns ± 0% 235ns ± 0% -14.25% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 0% -2.87% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 4% 24.5B ±10% -34.67% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 276µs ±82% 351µs ±43% ~ (p=0.343 n=4+4) CacheSerial/Set-4 176ns ± 0% 120ns ± 0% -31.96% (p=0.029 n=4+4) CacheSerial/Get-4 27.1ns ± 2% 20.7ns ± 1% -23.62% (p=0.029 n=4+4) CacheParallel/Set-4 272ns ± 1% 233ns ± 0% -14.05% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 2% -3.33% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 9% 26.5B ± 9% -29.33% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.50 ±33% 1.00 ± 0% ~ (p=0.429 n=4+4) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
Which makes it more pleasant to use and, in general, faster: ```bash name old time/op new time/op delta GetOrCreate/Real-4 276µs ±82% 351µs ±43% ~ (p=0.343 n=4+4) CacheSerial/Set-4 176ns ± 0% 120ns ± 0% -31.96% (p=0.029 n=4+4) CacheSerial/Get-4 27.1ns ± 2% 20.7ns ± 1% -23.62% (p=0.029 n=4+4) CacheParallel/Set-4 272ns ± 1% 233ns ± 0% -14.05% (p=0.029 n=4+4) CacheParallel/Get-4 149ns ± 1% 144ns ± 2% -3.33% (p=0.029 n=4+4) name old alloc/op new alloc/op delta GetOrCreate/Real-4 37.5B ± 9% 26.5B ± 9% -29.33% (p=0.029 n=4+4) CacheSerial/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheSerial/Get-4 0.00B 0.00B ~ (all equal) CacheParallel/Set-4 128B ± 0% 104B ± 0% -18.75% (p=0.029 n=4+4) CacheParallel/Get-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta GetOrCreate/Real-4 1.50 ±33% 1.00 ± 0% ~ (p=0.429 n=4+4) CacheSerial/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheSerial/Get-4 0.00 0.00 ~ (all equal) CacheParallel/Set-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.029 n=4+4) CacheParallel/Get-4 0.00 0.00 ~ (all equal) ``` Note that this uses a temporary fork of hashicorp/golang-lru#111 ... which, cross fingers, will get merged soon.
|
@SoMuchForSubtlety Any thoughts/preferences on my above question? |
|
Sounds reasonable, I have no objections :) |
|
Amazing work! Thanks! |
| t1 simplelru.LRUCache // T1 is the LRU for recently accessed items | ||
| b1 simplelru.LRUCache // B1 is the LRU for evictions from t1 | ||
| t1 simplelru.LRUCache[K, V] // T1 is the LRU for recently accessed items | ||
| b1 simplelru.LRUCache[K, V] // B1 is the LRU for evictions from t1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the eviction tracking LRU caches don't use the value, whouldn't it be better to use LRUCache[K, struct{}] here? I might be missing something, but I can open a PR if I don't.
This PR adds support for generics.
Because there is no generic list type in the standard library yet, I added a minimal version of
container/listwith added generics support (I kept the licence header, please let me know if it should be removed).It would also be possible to keep using
container/listas is, and just update the public API (take care of interface casts internally), but most of the performance gain comes from removing interface conversions.Benchmark results against master