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 |