Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1202)

Side by Side Diff: lib/observe/map.dart

Issue 12225039: Support for observable models, fixes #259 (Closed) Base URL: https://github.com/dart-lang/web-ui.git@master
Patch Set: small formatting fixes Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 library web_ui.observe.map;
6
7 import 'dart:collection';
8 import 'package:web_ui/observe.dart';
9 import 'list.dart';
10
11 typedef Map<K, dynamic> MapFactory<K>();
12
13 // TODO(jmesserly): this needs to be faster. We currently require multiple
14 // lookups per key to get the old value. Most likely this needs to be based on
15 // a modified HashMap source code.
16 /**
17 * Represents an observable map of model values. If any items are added,
18 * removed, or replaced, then observers that are registered with
19 * [observe] will be notified.
20 */
21 class ObservableMap<K, V> implements Map<K, V> {
22 final Map<K, V> _map;
23 final Map<K, Object> _observeKey;
24 Object _observeLength;
25 _ObservableMapKeyIterable<K, V> _keys;
26 _ObservableMapValueIterable<K, V> _values;
27
28 /**
29 * Creates an observable map, optionally using the provided factory
30 * [createMap] to construct a custom map type.
31 */
32 ObservableMap({MapFactory<K> createMap})
33 : _map = createMap != null ? createMap() : new Map<K, V>(),
34 _observeKey = createMap != null ? createMap() : new Map<K, Object>() {
35 _keys = new _ObservableMapKeyIterable<K, V>(this);
36 _values = new _ObservableMapValueIterable<K, V>(this);
37 }
38
39 /** Creates a new observable map using a [LinkedHashMap]. */
40 ObservableMap.linked() : this(createMap: () => new LinkedHashMap());
41
42 /**
43 * Creates an observable map that contains all key value pairs of [other].
44 */
45 factory ObservableMap.from(Map<K, V> other, {MapFactory<K> createMap}) {
46 var result = new ObservableMap<K, V>(createMap: createMap);
47 other.forEach((K key, V value) { result[key] = value; });
48 return result;
49 }
50
51
52 Iterable<K> get keys => _keys;
53
54 Iterable<V> get values => _values;
55
56 int get length {
57 _notifyReadLength();
58 return _map.length;
59 }
60
61 bool get isEmpty => length == 0;
62
63 void _notifyReadKey(K key) {
64 if (observeReads) _observeKey[key] = notifyRead(_observeKey[key]);
65 }
66
67 void _notifyReadLength() {
68 if (observeReads) _observeLength = notifyRead(_observeLength);
69 }
70
71 void _notifyReadAll() {
72 if (!observeReads) return;
73 _observeLength = notifyRead(_observeLength);
74 for (K key in _map.keys) {
75 _observeKey[key] = notifyRead(_observeKey[key]);
76 }
77 }
78
79 void _notifyWriteLength(int originalLength) {
80 if (_observeLength != null && originalLength != _map.length) {
81 _observeLength = notifyWrite(_observeLength);
82 }
83 }
84
85 void _notifyWriteKey(K key) {
86 var observer = _observeKey.remove(key);
87 if (observer != null) notifyWrite(observer);
88 }
89
90 bool containsValue(V value) {
91 _notifyReadAll();
92 return _map.containsValue(value);
93 }
94
95 bool containsKey(K key) {
96 _notifyReadKey(key);
97 return _map.containsKey(key);
98 }
99
100 V operator [](K key) {
101 _notifyReadKey(key);
102 return _map[key];
103 }
104
105 void operator []=(K key, V value) {
106 int len = _map.length;
107 V oldValue = _map[key];
108 _map[key] = value;
109 if (len != _map.length || oldValue != value) {
110 _notifyWriteKey(key);
111 _notifyWriteLength(len);
Siggi Cherem (dart-lang) 2013/02/13 01:43:24 should this be separate? I mean, if (oldValue !=
Jennifer Messerly 2013/02/13 05:43:15 Not quite, it was a bit tricky to get right. Added
Siggi Cherem (dart-lang) 2013/02/13 19:28:54 I see, so basically you are handling when the valu
Jennifer Messerly 2013/02/13 20:21:20 Uh, as I said in comment, _notifyWriteLength will
Siggi Cherem (dart-lang) 2013/02/13 20:41:13 My bad, I don't know how but I managed to complete
112 }
113 }
114
115 V putIfAbsent(K key, V ifAbsent()) {
116 // notifyRead because result depends on if the key already exists
117 _notifyReadKey(key);
118
119 int len = _map.length;
120 V result = _map.putIfAbsent(key, ifAbsent);
121 if (len != _map.length) {
122 _notifyWriteKey(key);
123 _notifyWriteLength(len);
124 }
125 return result;
126 }
127
128 V remove(K key) {
129 // notifyRead because result depends on if the key already exists
130 _notifyReadKey(key);
131
132 int len = _map.length;
133 V result = _map.remove(key);
134 if (len != _map.length) {
135 _notifyWriteKey(key);
136 _notifyWriteLength(len);
137 }
138 return result;
139 }
140
141 void clear() {
142 int len = _map.length;
143 _map.clear();
144 _notifyWriteLength(len);
145 _observeKey.values.forEach(notifyWrite);
146 _observeKey.clear();
147 }
148
149 void forEach(void f(K key, V value)) {
150 _notifyReadAll();
151 _map.forEach(f);
152 }
153
154 String toString() => Maps.mapToString(this);
155 }
156
157 class _ObservableMapKeyIterable<K, V> extends Iterable<K> {
158 final ObservableMap<K, V> _map;
159 _ObservableMapKeyIterable(this._map);
160
161 Iterator<K> get iterator => new _ObservableMapKeyIterator<K, V>(_map);
162 }
163
164 class _ObservableMapKeyIterator<K, V> implements Iterator<K> {
165 final ObservableMap<K, V> _map;
166 final Iterator<K> _keys;
167
168 _ObservableMapKeyIterator(ObservableMap<K, V> map)
169 : _map = map,
170 _keys = map._map.keys.iterator;
171
172 bool moveNext() {
173 _map._notifyReadLength();
174 return _keys.moveNext();
175 }
176
177 K get current {
178 var key = _keys.current;
179 if (key != null) _map._notifyReadKey(key);
180 return key;
181 }
182 }
183
184
185 class _ObservableMapValueIterable<K, V> extends Iterable<V> {
186 final ObservableMap<K, V> _map;
187 _ObservableMapValueIterable(this._map);
188
189 Iterator<V> get iterator => new _ObservableMapValueIterator<K, V>(_map);
190 }
191
192 class _ObservableMapValueIterator<K, V> implements Iterator<V> {
193 final ObservableMap<K, V> _map;
194 final Iterator<K> _keys;
195 final Iterator<V> _values;
196
197 _ObservableMapValueIterator(ObservableMap<K, V> map)
198 : _map = map,
199 _keys = map._map.keys.iterator,
200 _values = map._map.values.iterator;
201
202 bool moveNext() {
203 _map._notifyReadLength();
204 bool moreKeys = _keys.moveNext();
205 bool moreValues = _values.moveNext();
206 if (moreKeys != moreValues) {
207 throw new StateError('keys and values should be the same length');
208 }
209 return moreValues;
210 }
211
212 V get current {
213 var key = _keys.current;
214 if (key != null) _map._notifyReadKey(key);
215 return _values.current;
216 }
217 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698