package gott import ( "container/list" "sync" ) // cacheEntry holds a cached template AST type cacheEntry struct { key string tmpl *Template element *list.Element // pointer to LRU list element } // astCache is a thread-safe LRU cache for parsed template ASTs type astCache struct { mu sync.RWMutex items map[string]*cacheEntry lru *list.List // front = most recently used, back = least recently used maxSize int // 0 = unlimited } // newCache creates a new LRU cache with the specified max size. // If maxSize is 0, the cache has no size limit. func newCache(maxSize int) *astCache { return &astCache{ items: make(map[string]*cacheEntry), lru: list.New(), maxSize: maxSize, } } // Get retrieves a cached template by key. // Returns the template and true if found, nil and false otherwise. // Accessing an entry moves it to the front of the LRU list. func (c *astCache) Get(key string) (*Template, bool) { c.mu.Lock() defer c.mu.Unlock() entry, ok := c.items[key] if !ok { return nil, false } // Move to front of LRU list (most recently used) c.lru.MoveToFront(entry.element) return entry.tmpl, true } // Put stores a template in the cache. // If the cache is at capacity, the least recently used entry is evicted. func (c *astCache) Put(key string, tmpl *Template) { c.mu.Lock() defer c.mu.Unlock() // Check if key already exists if entry, ok := c.items[key]; ok { // Update existing entry entry.tmpl = tmpl c.lru.MoveToFront(entry.element) return } // Evict LRU entry if at capacity if c.maxSize > 0 && len(c.items) >= c.maxSize { c.evictLRU() } // Create new entry entry := &cacheEntry{ key: key, tmpl: tmpl, } entry.element = c.lru.PushFront(entry) c.items[key] = entry } // evictLRU removes the least recently used entry. // Caller must hold the write lock. func (c *astCache) evictLRU() { oldest := c.lru.Back() if oldest == nil { return } entry := oldest.Value.(*cacheEntry) c.lru.Remove(oldest) delete(c.items, entry.key) } // Clear removes all entries from the cache. func (c *astCache) Clear() { c.mu.Lock() defer c.mu.Unlock() c.items = make(map[string]*cacheEntry) c.lru.Init() } // Len returns the number of entries in the cache. func (c *astCache) Len() int { c.mu.RLock() defer c.mu.RUnlock() return len(c.items) }