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

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

Issue 12096106: work in progress: observable implementation using detailed change records (Closed) Base URL: https://github.com/dart-lang/web-ui.git@master
Patch Set: 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
« no previous file with comments | « lib/observe/reference.dart ('k') | lib/src/analyzer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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.set;
6
7 import 'dart:collection';
8 import 'dart:collection-dev';
9 import 'package:web_ui/observe.dart';
10
11 /**
12 * Represents an observable map of model values. If any items are added,
13 * removed, or replaced, then observers that are registered with
14 * [observe] will be notified.
15 */
16 abstract class ObservableSet<E> implements Observable, Set<E> {
17 /**
18 * Creates a map with the default implementation.
19 */
20 factory ObservableSet() => new ObservableHashSet<E>();
21
22 /**
23 * Creates a [Map] that contains all key value pairs of [other].
24 */
25 factory ObservableSet.from(Iterable<E> other) =>
26 new ObservableHashSet<E>.from(other);
27 }
28
29
30 /**
31 * Represents an observable [HashSet] of model values. If any items are added,
32 * removed, or replaced, then observers that are registered with
33 * [observe] will be notified.
34 */
35 // Note: this code is similar to HashSet, but adding notify calls.
36 // TODO(jmesserly): also this shold extend Collection<E>, so we can delete
37 // copy+paste code. Fix once we have mixins.
38 class ObservableHashSet<E> extends Observable implements ObservableSet<E> {
39 // The map backing this set. The associations in this map are all
40 // of the form element -> element. If a value is not in the map,
41 // then it is not in the set.
42 final HashMap<E, E> _backingMap;
43
44 ObservableHashSet() : _backingMap = new HashMap<E, E>();
45
46 /**
47 * Creates a [Set] that contains all elements of [other].
48 */
49 factory ObservableHashSet.from(Iterable<E> other) =>
50 new ObservableHashSet<E>()..addAll(other);
51
52 void clear() {
53 if (hasObservers) {
54 for (var key in _backingMap.keys) {
55 notifyChange(ChangeRecord.REMOVE, key, key, null);
56 }
57 notifyChange(ChangeRecord.FIELD, 'length', _backingMap.length, 0);
58 }
59 _backingMap.clear();
60 }
61
62 void add(E value) {
63 int oldLen = _backingMap.length;
64 _backingMap[value] = value;
65 int newLen = _backingMap.length;
66 if (hasObservers && oldLen != newLen) {
67 notifyChange(ChangeRecord.FIELD, 'length', oldLen, newLen);
68 notifyChange(ChangeRecord.INSERT, value, null, value);
69 }
70 }
71
72 bool remove(Object value) {
73 if (observeReads) notifyRead(ChangeRecord.INDEX, value);
74 if (!_backingMap.containsKey(value)) return false;
75 _backingMap.remove(value);
76 notifyChange(ChangeRecord.REMOVE, value, value, null);
77 int len = _backingMap.length;
78 notifyChange(ChangeRecord.FIELD, 'length', len + 1, len);
79 return true;
80 }
81
82 bool contains(E value) {
83 if (observeReads) notifyRead(ChangeRecord.INDEX, value);
84 return _backingMap.containsKey(value);
85 }
86
87 Set<E> intersection(Collection<E> collection) {
88 Set<E> result = new Set<E>();
89 collection.forEach((E value) {
90 if (contains(value)) result.add(value);
91 });
92 return result;
93 }
94
95 bool isSubsetOf(Collection<E> other) {
96 return new Set<E>.from(other).containsAll(this);
97 }
98
99 bool containsAll(Collection<E> collection) {
100 return collection.every((E value) {
101 return contains(value);
102 });
103 }
104
105 bool get isEmpty => length == 0;
106
107 int get length {
108 if (observeReads) notifyRead(ChangeRecord.FIELD, 'length');
109 return _backingMap.length;
110 }
111
112 Iterator<E> get iterator => new _HashSetIterator<E>(this);
113
114 String toString() {
115 return Collections.collectionToString(this);
116 }
117
118
119 // ---------------------------------------------------------------------------
120 // Note: below this comment, methods are copy+paste from Collection<E> and
121 // Iterable<E>. Remove when we have mixins.
122 // ---------------------------------------------------------------------------
123 void addAll(Iterable<E> elements) {
124 for (E element in elements) add(element);
125 }
126
127 // TODO(jmesserly): mappedByList, takeList, skipList are not right.
128
129 void removeAll(Iterable elements) =>
130 IterableMixinWorkaround.removeAll(this, elements);
131 void retainAll(Iterable elements) =>
132 IterableMixinWorkaround.retainAll(this, elements);
133 void removeMatching(bool test(E element)) =>
134 IterableMixinWorkaround.removeMatching(this, test);
135 void retainMatching(bool test(E element)) =>
136 IterableMixinWorkaround.retainMatching(this, test);
137 Iterable mappedBy(f(E element)) =>
138 IterableMixinWorkaround.mappedByList(toList(), f);
139 Iterable<E> where(bool f(E element)) =>
140 IterableMixinWorkaround.where(this, f);
141 void forEach(void f(E element)) => IterableMixinWorkaround.forEach(this, f);
142 dynamic reduce(var initialValue,
143 dynamic combine(var previousValue, E element)) =>
144 IterableMixinWorkaround.reduce(this, initialValue, combine);
145 bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f);
146 String join([String separator]) =>
147 IterableMixinWorkaround.join(this, separator);
148 bool any(bool f(E element)) => IterableMixinWorkaround.any(this, f);
149 List<E> toList() => new List<E>.from(this);
150 Set<E> toSet() => new Set<E>.from(this);
151 E min([int compare(E a, E b)]) => IterableMixinWorkaround.min(this, compare);
152 E max([int compare(E a, E b)]) => IterableMixinWorkaround.max(this, compare);
153 Iterable<E> take(int n) => IterableMixinWorkaround.takeList(toList(), n);
154 Iterable<E> takeWhile(bool test(E value))
155 => IterableMixinWorkaround.takeWhile(this, test);
156 Iterable<E> skip(int n) => IterableMixinWorkaround.skipList(toList(), n);
157 Iterable<E> skipWhile(bool test(E value)) =>
158 IterableMixinWorkaround.skipWhile(this, test);
159 E get single => IterableMixinWorkaround.single(this);
160 E get first => IterableMixinWorkaround.first(this);
161 E get last => IterableMixinWorkaround.last(this);
162 E firstMatching(bool test(E value), { E orElse() }) =>
163 IterableMixinWorkaround.firstMatching(this, test, orElse);
164 E lastMatching(bool test(E value), {E orElse()}) =>
165 IterableMixinWorkaround.lastMatching(this, test, orElse);
166 E singleMatching(bool test(E value)) =>
167 IterableMixinWorkaround.singleMatching(this, test);
168 E elementAt(int index) => IterableMixinWorkaround.elementAt(this, index);
169 }
170
171 class _HashSetIterator<E> implements Iterator<E> {
172 final ObservableHashSet<E> _set;
173 final Iterator _keysIterator;
174
175 _HashSetIterator(ObservableHashSet<E> set)
176 : _set = set,
177 _keysIterator = set._backingMap.keys.iterator;
178
179 E get current {
180 E result = _keysIterator.current;
181 if (observeReads) _set.notifyRead(ChangeRecord.INDEX, result);
182 return result;
183 }
184
185 bool moveNext() {
186 if (observeReads) _set.notifyRead(ChangeRecord.FIELD, 'length');
187 bool result = _keysIterator.moveNext();
188 return result;
189 }
190 }
OLDNEW
« no previous file with comments | « lib/observe/reference.dart ('k') | lib/src/analyzer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698