classes/LRUCache.class.ps1

using namespace System.Collections.Generic

class LRUCacheEntry
{
    [object]$Key
    [object]$Item

    LRUCacheEntry($key,$item)
    {
        $this.Key = $key
        $this.Item = $item
    }
}

class LRUCache : PSObjectCache
{
    hidden [LinkedList[LRUCacheEntry]]
    $Entries

    hidden [System.Collections.IDictionary]
    $LookupTable

    [int]$Capacity

    LRUCache([scriptblock]$Fetcher,[int]$Capacity) : base($Fetcher)
    {
        $this.Capacity = $Capacity
        $this.Entries = [LinkedList[LRUCacheEntry]]::new()
    }

    hidden [void]
    Promote([LinkedListNode[LRUCacheEntry]]$Node)
    {
        if($Node -eq $Node.List.First){
            return
        }

        $Item = $Node.Value
        $Node.List.Remove($Node)
        $this.LookupTable[$Item.Key] = $this.Entries.AddFirst($Item)
        return
    }

    [psobject]
    Get($Key){
        if($this.LookupTable.Contains($Key)){
            $CacheEntry = $this.LookupTable[$Key]
            $this.Promote($CacheEntry)
            return $CacheEntry.Value.Item
        }
        else{
            try{
                $copy = & $this.Fetcher $Key
            }
            catch{
                throw $_
                return $null
            }

            while($this.Entries.Count -ge $this.Capacity)
            {
                $this.LookupTable.Remove($this.Entries.Last.Value.Key)
                $this.Entries.RemoveLast()
            }

            $this.LookupTable[$Key] = $this.Entries.AddFirst([LRUCacheEntry]::new($key,$copy))

            return $copy
        }
    }
}