Skip to content

Repository files navigation

Go LRU Cache

Go Version CI Coverage Go Reference License: MIT

A generic, fixed-capacity LRU cache for Go, built on a generic doubly linked list.

  • lru — a fixed-capacity cache with a least recently used eviction policy, safe for concurrent use.
  • list — the generic doubly linked list the cache is built on, usable on its own.

Requirements

Go 1.22 or newer.

Installation

go get github.com/mrLexx/go-cache

Usage

package main

import (
	"fmt"

	"github.com/mrLexx/go-cache/lru"
)

func main() {
	cache := lru.MustNew[string, int](128)

	cache.Set("a", 1)
	cache.Set("b", 2)

	value, ok := cache.Get("a")
	fmt.Println(value, ok) // 1 true

	value, ok = cache.Get("missing")
	fmt.Println(value, ok) // 0 false
}

MustNew panics on an invalid capacity, which suits package-level variables and tests. Elsewhere, use New and handle the error:

cache, err := lru.New[string, int](128)
if err != nil {
	return fmt.Errorf("create cache: %w", err)
}

The capacity must be in the range [1, 1024]. Outside it, New returns an error wrapping ErrInvalidCapacity:

_, err := lru.New[string, int](0)
fmt.Println(errors.Is(err, lru.ErrInvalidCapacity)) // true

Eviction

Once the cache is full, storing a new key drops the least recently used entry. Both Get and Set count as a use, so reading a key protects it from the next eviction:

cache := lru.MustNew[string, int](2)

cache.Set("a", 1)
cache.Set("b", 2)

cache.Get("a")    // "a" is now the most recently used
cache.Set("c", 3) // evicts "b", not "a"

Storing a key that is already present overwrites its value and evicts nothing. Set reports whether the key was there before, and Clear empties the cache while keeping it usable with its original capacity.

The list package

list is a plain generic doubly linked list and does not depend on the cache:

l := list.New[string]()

l.PushBack("b")
l.PushBack("c")
first := l.PushFront("a") // a, b, c

l.MoveToFront(l.Back())   // c, a, b
l.Remove(first)           // c, b

for item := l.Front(); item != nil; item = item.Next {
	fmt.Println(item.Value)
}

Unlike Cache, a List is not safe for concurrent use; guard it yourself if several goroutines touch it.

Documentation

Full API documentation lives in the doc comments, most of it backed by runnable examples:

go doc github.com/mrLexx/go-cache/lru
go doc github.com/mrLexx/go-cache/list

Development

The project uses Task to automate building, testing and linting. It replaces the classic Makefile.

1. Installing Task

Install task on your machine before you begin.

The full list of installation methods is available in the official documentation.

2. Available commands

To list every available command with its description, run this in the project root:

task --list

Main development commands:

  • task bench — Runs benchmarks
  • task coverage:check — Checks coverage without running tests
  • task coverage:html — Generates an HTML coverage report
  • task deps:update — Updates dependencies
  • task docs — Updates the command list in README.md
  • task fix:apply — Applies automatic fixes (go fix)
  • task fix:diff — Previews automatic fixes as a diff (go fix -diff)
  • task format — Formats the code (gofumpt + gci)
  • task formatters:install — Installs gofumpt and gci
  • task golangci-lint:install — Installs golangci-lint
  • task install — Installs all tools
  • task lint — Runs golangci-lint
  • task test — Runs unit tests with the race detector
  • task test:coverage — Runs tests with coverage
  • task test:example — Runs Example tests

About

A generic, fixed-capacity LRU cache for Go, built on a generic doubly linked list

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages