Class: Fontisan::Variation::Cache
- Inherits:
-
Object
- Object
- Fontisan::Variation::Cache
- Defined in:
- lib/fontisan/variation/cache.rb
Overview
Caches variation calculations for performance
This class implements a caching layer for expensive variation calculations to significantly improve instance generation performance. It caches:
- Normalized scalars per coordinate set
- Interpolated values
- Instance generation results
- Region matches
Cache strategies:
- LRU (Least Recently Used) for memory management
- Coordinate-based keys for scalar caching
- Invalidation on font modification
- Optional persistent caching across sessions
Direct Known Subclasses
Instance Attribute Summary collapse
-
#max_size ⇒ Integer
readonly
Maximum cache size.
-
#stats ⇒ Hash
readonly
Cache statistics.
Instance Method Summary collapse
-
#cached?(key) ⇒ Boolean
Check if key is cached and valid.
-
#clear ⇒ Object
Clear entire cache.
-
#empty? ⇒ Boolean
Check if cache is empty.
-
#fetch(key) { ... } ⇒ Object
Generic fetch with caching.
-
#fetch_instance(font_checksum, coordinates) { ... } ⇒ Hash
Fetch or compute instance generation result.
-
#fetch_interpolated(base_value, deltas, scalars) { ... } ⇒ Float
Fetch or compute interpolated value.
-
#fetch_region_matches(coordinates, regions) { ... } ⇒ Array
Fetch or compute region matches.
-
#fetch_scalars(coordinates, axes) { ... } ⇒ Array<Float>
Fetch or compute scalars for coordinates.
-
#full? ⇒ Boolean
Check if cache is full.
-
#initialize(max_size: 1000, ttl: nil) ⇒ Cache
constructor
Initialize cache.
-
#invalidate(key) ⇒ Object
Invalidate specific key.
-
#invalidate_matching(pattern) ⇒ Object
Invalidate keys matching pattern.
-
#size ⇒ Integer
Get cache size.
-
#statistics ⇒ Hash
Get cache statistics.
-
#store(key, value) ⇒ Object
Store value in cache.
Constructor Details
#initialize(max_size: 1000, ttl: nil) ⇒ Cache
Initialize cache
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/fontisan/variation/cache.rb', line 40 def initialize(max_size: 1000, ttl: nil) @max_size = max_size @ttl = ttl @cache = {} @access_times = {} @access_counter = 0 @stats = { hits: 0, misses: 0, evictions: 0, invalidations: 0, } end |
Instance Attribute Details
#max_size ⇒ Integer (readonly)
Returns Maximum cache size.
31 32 33 |
# File 'lib/fontisan/variation/cache.rb', line 31 def max_size @max_size end |
#stats ⇒ Hash (readonly)
Returns Cache statistics.
34 35 36 |
# File 'lib/fontisan/variation/cache.rb', line 34 def stats @stats end |
Instance Method Details
#cached?(key) ⇒ Boolean
Check if key is cached and valid
121 122 123 124 125 126 |
# File 'lib/fontisan/variation/cache.rb', line 121 def cached?(key) return false unless @cache.key?(key) return false if expired?(key) true end |
#clear ⇒ Object
Clear entire cache
143 144 145 146 147 |
# File 'lib/fontisan/variation/cache.rb', line 143 def clear @cache.clear @access_times.clear @stats[:invalidations] += 1 end |
#empty? ⇒ Boolean
Check if cache is empty
191 192 193 |
# File 'lib/fontisan/variation/cache.rb', line 191 def empty? @cache.empty? end |
#fetch(key) { ... } ⇒ Object
Generic fetch with caching
104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/fontisan/variation/cache.rb', line 104 def fetch(key) if cached?(key) @stats[:hits] += 1 touch(key) return @cache[key][:value] end @stats[:misses] += 1 value = yield store(key, value) value end |
#fetch_instance(font_checksum, coordinates) { ... } ⇒ Hash
Fetch or compute instance generation result
83 84 85 86 |
# File 'lib/fontisan/variation/cache.rb', line 83 def fetch_instance(font_checksum, coordinates, &) key = CacheKeyBuilder.instance_key(font_checksum, coordinates) fetch(key, &) end |
#fetch_interpolated(base_value, deltas, scalars) { ... } ⇒ Float
Fetch or compute interpolated value
72 73 74 75 |
# File 'lib/fontisan/variation/cache.rb', line 72 def fetch_interpolated(base_value, deltas, scalars, &) key = CacheKeyBuilder.interpolation_key(base_value, deltas, scalars) fetch(key, &) end |
#fetch_region_matches(coordinates, regions) { ... } ⇒ Array
Fetch or compute region matches
94 95 96 97 |
# File 'lib/fontisan/variation/cache.rb', line 94 def fetch_region_matches(coordinates, regions, &) key = CacheKeyBuilder.region_matches_key(coordinates, regions) fetch(key, &) end |
#fetch_scalars(coordinates, axes) { ... } ⇒ Array<Float>
Fetch or compute scalars for coordinates
60 61 62 63 |
# File 'lib/fontisan/variation/cache.rb', line 60 def fetch_scalars(coordinates, axes, &) key = CacheKeyBuilder.scalars_key(coordinates, axes) fetch(key, &) end |
#full? ⇒ Boolean
Check if cache is full
198 199 200 |
# File 'lib/fontisan/variation/cache.rb', line 198 def full? @cache.size >= @max_size end |
#invalidate(key) ⇒ Object
Invalidate specific key
152 153 154 155 156 |
# File 'lib/fontisan/variation/cache.rb', line 152 def invalidate(key) @cache.delete(key) @access_times.delete(key) @stats[:invalidations] += 1 end |
#invalidate_matching(pattern) ⇒ Object
Invalidate keys matching pattern
161 162 163 164 |
# File 'lib/fontisan/variation/cache.rb', line 161 def invalidate_matching(pattern) keys = @cache.keys.select { |k| k.match?(pattern) } keys.each { |k| invalidate(k) } end |
#size ⇒ Integer
Get cache size
184 185 186 |
# File 'lib/fontisan/variation/cache.rb', line 184 def size @cache.size end |
#statistics ⇒ Hash
Get cache statistics
169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/fontisan/variation/cache.rb', line 169 def statistics total = @stats[:hits] + @stats[:misses] hit_rate = total.zero? ? 0.0 : @stats[:hits].to_f / total @stats.merge( total_requests: total, hit_rate: hit_rate, size: @cache.size, max_size: @max_size, ) end |
#store(key, value) ⇒ Object
Store value in cache
132 133 134 135 136 137 138 139 140 |
# File 'lib/fontisan/variation/cache.rb', line 132 def store(key, value) evict_if_needed @cache[key] = { value: value, created_at: Time.now, } touch(key) end |