blob: e8a2b83ee0d40cc4ba8d7240e886e67a46cbb02a [file]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:meta/meta.dart';
/// LRU cache of objects.
class Cache<K, V> {
final int _maxSizeBytes;
final int Function(V) _meter;
@visibleForTesting
final map = <K, V>{};
int _currentSizeBytes = 0;
int _evictedBytes = 0;
int _evictedEntryCount = 0;
int _evictionCount = 0;
Cache(this._maxSizeBytes, this._meter);
int get currentSizeBytes => _currentSizeBytes;
int get entryCount => map.length;
int get evictedBytes => _evictedBytes;
int get evictedEntryCount => _evictedEntryCount;
int get evictionCount => _evictionCount;
int get maxSizeBytes => _maxSizeBytes;
V? get(K key) {
var value = map.remove(key);
if (value != null) {
map[key] = value;
}
return value;
}
void put(K key, V value) {
V? oldValue = map[key];
if (oldValue != null) {
_currentSizeBytes -= _meter(oldValue);
}
map[key] = value;
_currentSizeBytes += _meter(value);
_evict();
}
void _evict() {
if (_currentSizeBytes > _maxSizeBytes) {
var keysToRemove = <K>[];
var evictedBytes = 0;
for (var entry in map.entries) {
keysToRemove.add(entry.key);
var entrySize = _meter(entry.value);
_currentSizeBytes -= entrySize;
evictedBytes += entrySize;
if (_currentSizeBytes <= _maxSizeBytes) {
break;
}
}
for (var key in keysToRemove) {
map.remove(key);
}
if (keysToRemove.isNotEmpty) {
_evictionCount++;
_evictedBytes += evictedBytes;
_evictedEntryCount += keysToRemove.length;
}
}
}
}