| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'dart:collection'; | |
| 6 | |
| 7 /** | |
| 8 * Store of bytes associated with string keys. | |
| 9 * | |
| 10 * Each key must be not longer than 100 characters and consist of only `[a-z]`, | |
| 11 * `[0-9]`, `.` and `_` characters. The key cannot be an empty string, the | |
| 12 * literal `.`, or contain the sequence `..`. | |
| 13 * | |
| 14 * Note that associations are not guaranteed to be persistent. The value | |
| 15 * associated with a key can change or become `null` at any point in time. | |
| 16 * | |
| 17 * TODO(scheglov) Research using asynchronous API. | |
| 18 */ | |
| 19 abstract class ByteStore { | |
| 20 /** | |
| 21 * Return the bytes associated with the given [key]. | |
| 22 * Return `null` if the association does not exist. | |
| 23 */ | |
| 24 List<int> get(String key); | |
| 25 | |
| 26 /** | |
| 27 * Associate the given [bytes] with the [key]. | |
| 28 */ | |
| 29 void put(String key, List<int> bytes); | |
| 30 } | |
| 31 | |
| 32 /** | |
| 33 * [ByteStore] which stores data only in memory. | |
| 34 */ | |
| 35 class MemoryByteStore implements ByteStore { | |
| 36 final Map<String, List<int>> _map = {}; | |
| 37 | |
| 38 @override | |
| 39 List<int> get(String key) { | |
| 40 return _map[key]; | |
| 41 } | |
| 42 | |
| 43 @override | |
| 44 void put(String key, List<int> bytes) { | |
| 45 _map[key] = bytes; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 /** | |
| 50 * A wrapper around [ByteStore] which adds an in-memory LRU cache to it. | |
| 51 */ | |
| 52 class MemoryCachingByteStore implements ByteStore { | |
| 53 final ByteStore _store; | |
| 54 final int _maxSizeBytes; | |
| 55 | |
| 56 final _map = new LinkedHashMap<String, List<int>>(); | |
| 57 int _currentSizeBytes = 0; | |
| 58 | |
| 59 MemoryCachingByteStore(this._store, this._maxSizeBytes); | |
| 60 | |
| 61 @override | |
| 62 List<int> get(String key) { | |
| 63 List<int> bytes = _map.remove(key); | |
| 64 if (bytes == null) { | |
| 65 bytes = _store.get(key); | |
| 66 if (bytes != null) { | |
| 67 _map[key] = bytes; | |
| 68 _currentSizeBytes += bytes.length; | |
| 69 _evict(); | |
| 70 } | |
| 71 } else { | |
| 72 _map[key] = bytes; | |
| 73 } | |
| 74 return bytes; | |
| 75 } | |
| 76 | |
| 77 @override | |
| 78 void put(String key, List<int> bytes) { | |
| 79 _store.put(key, bytes); | |
| 80 _currentSizeBytes -= _map[key]?.length ?? 0; | |
| 81 _map[key] = bytes; | |
| 82 _currentSizeBytes += bytes.length; | |
| 83 _evict(); | |
| 84 } | |
| 85 | |
| 86 void _evict() { | |
| 87 while (_currentSizeBytes > _maxSizeBytes) { | |
| 88 if (_map.isEmpty) { | |
| 89 // Should be impossible, since _currentSizeBytes should always match | |
| 90 // _map. But recover anyway. | |
| 91 assert(false); | |
| 92 _currentSizeBytes = 0; | |
| 93 break; | |
| 94 } | |
| 95 String key = _map.keys.first; | |
| 96 List<int> bytes = _map.remove(key); | |
| 97 _currentSizeBytes -= bytes.length; | |
| 98 } | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 /** | |
| 103 * [ByteStore] which does not store any data. | |
| 104 */ | |
| 105 class NullByteStore implements ByteStore { | |
| 106 @override | |
| 107 List<int> get(String key) => null; | |
| 108 | |
| 109 @override | |
| 110 void put(String key, List<int> bytes) {} | |
| 111 } | |
| OLD | NEW |