Created
March 23, 2021 23:39
-
-
Save sean-m/bcf150a103122eba41fe602ab4566c02 to your computer and use it in GitHub Desktop.
Simple static cache for PowerShell. Intend to add an object limit and generational eviction mechanism. For right now it's basically a cleaner way to use a hashtable for caching inside a script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CacheResolverException : Exception { | |
CacheResolverException ([string]$Message, [Exception]$InnerException) : base ($Message, $InnerException) { } | |
} | |
class HotCache { | |
hidden static [Hashtable]$Records = @{} | |
hidden [UInt64] $Hit = 0 | |
hidden [UInt64] $Miss = 0 | |
hidden [int] $Limit = 0 | |
HotCache () { | |
$this.Init() | |
} | |
HotCache ($Limit) { | |
$this.Init() | |
# If this limit is exceeded, the least used record will be evicted from the cache. | |
if ($Limit -gt $this.Limit) { | |
$this.Limit = $Limit | |
} | |
} | |
hidden [void] Init() { | |
# Allows accessing Record.Count without exposing the colleciton publically | |
$this | Add-Member -MemberType ScriptProperty -Name 'Count' -Value { return [HotCache]::Records.Count } | |
} | |
[void] Add ([string]$Key, $Value) { | |
if ([String]::IsNullOrEmpty($Key)) { | |
throw '$Key is null. Key must be a non-empty string.' | |
} | |
$_key = $Key.ToLower() | |
if ([HotCache]::Records.ContainsKey($_key)) { | |
[HotCache]::Records[$_key] = $Value | |
} | |
else { | |
[HotCache]::Records.Add($_key, $Value) | |
} | |
} | |
[bool] ContainsKey ([String]$Key) { | |
if ([String]::IsNullOrEmpty($Key)) { | |
throw '$Key is null. Key must be a non-empty string.' | |
} | |
$_key = $Key.ToLower() | |
return [HotCache]::Records.ContainsKey($_key) | |
} | |
[object] Get ($Key, [Func[string,object]]$Resolve=$null) { | |
if ([String]::IsNullOrEmpty($Key)) { | |
throw '$Key is null. Key must be a non-empty string.' | |
} | |
$_key = $Key.ToLower() | |
if ([HotCache]::Records.ContainsKey($_key)) { | |
# Return resolved key | |
$this.Hit++ | |
return [HotCache]::Records[$_key] | |
} | |
else { | |
# If a resolution Func was passed, attempt to resolve the object | |
$this.Miss++ | |
if ($Resolve) { | |
try { | |
$result = $Resolve.Invoke($_key) | |
if ($result) { | |
[HotCache]::Records.Add($_key, $result) | |
return $result | |
} | |
} | |
catch { | |
throw [CacheResolverException]::new('Exception encountered while resolving key: {0}' -f $Key, $_.Exception) | |
} | |
} | |
throw "Cannot resolve value for key: $Key" | |
} | |
} | |
[object] GetStats () { | |
return [PSCustomObject]@{ | |
Count=[HotCache]::Records.Count | |
Hit=$this.Hit; | |
Miss=$this.Miss; | |
} | |
} | |
[void] Clear() { | |
[HotCache]::Records.Clear() | |
$this.Hit = 0 | |
$this.Miss = 0 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment