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

Side by Side Diff: pkg/observe/lib/src/observable_list.dart

Issue 82593004: [observe] add isEmpty/isNotEmpty to ObservableList reflection (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/observe/test/observable_list_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library observe.src.observable_list; 5 library observe.src.observable_list;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection' show ListBase, UnmodifiableListView; 8 import 'dart:collection' show ListBase, UnmodifiableListView;
9 import 'package:observe/observe.dart'; 9 import 'package:observe/observe.dart';
10 import 'list_diff.dart' show projectListSplices, calcSplices; 10 import 'list_diff.dart' show projectListSplices, calcSplices;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 bool get _hasListObservers => 75 bool get _hasListObservers =>
76 _listChanges != null && _listChanges.hasListener; 76 _listChanges != null && _listChanges.hasListener;
77 77
78 @reflectable int get length => _list.length; 78 @reflectable int get length => _list.length;
79 79
80 @reflectable set length(int value) { 80 @reflectable set length(int value) {
81 int len = _list.length; 81 int len = _list.length;
82 if (len == value) return; 82 if (len == value) return;
83 83
84 // Produce notifications if needed 84 // Produce notifications if needed
85 notifyPropertyChange(#length, len, value); 85 _notifyChangeLength(len, value);
86 if (_hasListObservers) { 86 if (_hasListObservers) {
87 if (value < len) { 87 if (value < len) {
88 _recordChange(new ListChangeRecord(this, value, 88 _recordChange(new ListChangeRecord(this, value,
89 removed: _list.getRange(value, len).toList())); 89 removed: _list.getRange(value, len).toList()));
90 } else { 90 } else {
91 _recordChange(new ListChangeRecord(this, len, addedCount: value - len)); 91 _recordChange(new ListChangeRecord(this, len, addedCount: value - len));
92 } 92 }
93 } 93 }
94 94
95 _list.length = value; 95 _list.length = value;
96 } 96 }
97 97
98 @reflectable E operator [](int index) => _list[index]; 98 @reflectable E operator [](int index) => _list[index];
99 99
100 @reflectable void operator []=(int index, E value) { 100 @reflectable void operator []=(int index, E value) {
101 var oldValue = _list[index]; 101 var oldValue = _list[index];
102 if (_hasListObservers) { 102 if (_hasListObservers) {
103 _recordChange(new ListChangeRecord(this, index, addedCount: 1, 103 _recordChange(new ListChangeRecord(this, index, addedCount: 1,
104 removed: [oldValue])); 104 removed: [oldValue]));
105 } 105 }
106 _list[index] = value; 106 _list[index] = value;
107 } 107 }
108 108
109 // Forwarders so we can reflect on the properties.
110 @reflectable bool get isEmpty => super.isEmpty;
111 @reflectable bool get isNotEmpty => super.isNotEmpty;
112
113 // TODO(jmesserly): should we support first/last/single? They're kind of
114 // dangerous to use in a path because they throw exceptions. Also we'd need
115 // to produce property change notifications which seems to conflict with our
116 // existing list notifications.
117
109 // The following methods are here so that we can provide nice change events. 118 // The following methods are here so that we can provide nice change events.
110 119
111 void setAll(int index, Iterable<E> iterable) { 120 void setAll(int index, Iterable<E> iterable) {
112 if (iterable is! List && iterable is! Set) { 121 if (iterable is! List && iterable is! Set) {
113 iterable = iterable.toList(); 122 iterable = iterable.toList();
114 } 123 }
115 var len = iterable.length; 124 var len = iterable.length;
116 if (_hasListObservers && len > 0) { 125 if (_hasListObservers && len > 0) {
117 _recordChange(new ListChangeRecord(this, index, addedCount: len, 126 _recordChange(new ListChangeRecord(this, index, addedCount: len,
118 removed: _list.getRange(index, len).toList())); 127 removed: _list.getRange(index, len).toList()));
119 } 128 }
120 _list.setAll(index, iterable); 129 _list.setAll(index, iterable);
121 } 130 }
122 131
123 void add(E value) { 132 void add(E value) {
124 int len = _list.length; 133 int len = _list.length;
125 notifyPropertyChange(#length, len, len + 1); 134 _notifyChangeLength(len, len + 1);
126 if (_hasListObservers) { 135 if (_hasListObservers) {
127 _recordChange(new ListChangeRecord(this, len, addedCount: 1)); 136 _recordChange(new ListChangeRecord(this, len, addedCount: 1));
128 } 137 }
129 138
130 _list.add(value); 139 _list.add(value);
131 } 140 }
132 141
133 void addAll(Iterable<E> iterable) { 142 void addAll(Iterable<E> iterable) {
134 int len = _list.length; 143 int len = _list.length;
135 _list.addAll(iterable); 144 _list.addAll(iterable);
136 145
137 notifyPropertyChange(#length, len, _list.length); 146 _notifyChangeLength(len, _list.length);
138 147
139 int added = _list.length - len; 148 int added = _list.length - len;
140 if (_hasListObservers && added > 0) { 149 if (_hasListObservers && added > 0) {
141 _recordChange(new ListChangeRecord(this, len, addedCount: added)); 150 _recordChange(new ListChangeRecord(this, len, addedCount: added));
142 } 151 }
143 } 152 }
144 153
145 bool remove(Object element) { 154 bool remove(Object element) {
146 for (int i = 0; i < this.length; i++) { 155 for (int i = 0; i < this.length; i++) {
147 if (this[i] == element) { 156 if (this[i] == element) {
148 removeRange(i, i + 1); 157 removeRange(i, i + 1);
149 return true; 158 return true;
150 } 159 }
151 } 160 }
152 return false; 161 return false;
153 } 162 }
154 163
155 void removeRange(int start, int end) { 164 void removeRange(int start, int end) {
156 _rangeCheck(start, end); 165 _rangeCheck(start, end);
157 int rangeLength = end - start; 166 int rangeLength = end - start;
158 int len = _list.length; 167 int len = _list.length;
159 168
160 notifyPropertyChange(#length, len, len - rangeLength); 169 _notifyChangeLength(len, len - rangeLength);
161 if (_hasListObservers && rangeLength > 0) { 170 if (_hasListObservers && rangeLength > 0) {
162 _recordChange(new ListChangeRecord(this, start, 171 _recordChange(new ListChangeRecord(this, start,
163 removed: _list.getRange(start, end).toList())); 172 removed: _list.getRange(start, end).toList()));
164 } 173 }
165 174
166 _list.removeRange(start, end); 175 _list.removeRange(start, end);
167 } 176 }
168 177
169 void insertAll(int index, Iterable<E> iterable) { 178 void insertAll(int index, Iterable<E> iterable) {
170 if (index < 0 || index > length) { 179 if (index < 0 || index > length) {
171 throw new RangeError.range(index, 0, length); 180 throw new RangeError.range(index, 0, length);
172 } 181 }
173 // TODO(floitsch): we can probably detect more cases. 182 // TODO(floitsch): we can probably detect more cases.
174 if (iterable is! List && iterable is! Set) { 183 if (iterable is! List && iterable is! Set) {
175 iterable = iterable.toList(); 184 iterable = iterable.toList();
176 } 185 }
177 int insertionLength = iterable.length; 186 int insertionLength = iterable.length;
178 // There might be errors after the length change, in which case the list 187 // There might be errors after the length change, in which case the list
179 // will end up being modified but the operation not complete. Unless we 188 // will end up being modified but the operation not complete. Unless we
180 // always go through a "toList" we can't really avoid that. 189 // always go through a "toList" we can't really avoid that.
181 int len = _list.length; 190 int len = _list.length;
182 _list.length += insertionLength; 191 _list.length += insertionLength;
183 192
184 _list.setRange(index + insertionLength, this.length, this, index); 193 _list.setRange(index + insertionLength, this.length, this, index);
185 _list.setAll(index, iterable); 194 _list.setAll(index, iterable);
186 195
187 notifyPropertyChange(#length, len, _list.length); 196 _notifyChangeLength(len, _list.length);
188 197
189 if (_hasListObservers && insertionLength > 0) { 198 if (_hasListObservers && insertionLength > 0) {
190 _recordChange(new ListChangeRecord(this, index, 199 _recordChange(new ListChangeRecord(this, index,
191 addedCount: insertionLength)); 200 addedCount: insertionLength));
192 } 201 }
193 } 202 }
194 203
195 void insert(int index, E element) { 204 void insert(int index, E element) {
196 if (index < 0 || index > length) { 205 if (index < 0 || index > length) {
197 throw new RangeError.range(index, 0, length); 206 throw new RangeError.range(index, 0, length);
198 } 207 }
199 if (index == length) { 208 if (index == length) {
200 add(element); 209 add(element);
201 return; 210 return;
202 } 211 }
203 // We are modifying the length just below the is-check. Without the check 212 // We are modifying the length just below the is-check. Without the check
204 // Array.copy could throw an exception, leaving the list in a bad state 213 // Array.copy could throw an exception, leaving the list in a bad state
205 // (with a length that has been increased, but without a new element). 214 // (with a length that has been increased, but without a new element).
206 if (index is! int) throw new ArgumentError(index); 215 if (index is! int) throw new ArgumentError(index);
207 _list.length++; 216 _list.length++;
208 _list.setRange(index + 1, length, this, index); 217 _list.setRange(index + 1, length, this, index);
209 218
210 notifyPropertyChange(#length, _list.length - 1, _list.length); 219 _notifyChangeLength(_list.length - 1, _list.length);
211 if (_hasListObservers) { 220 if (_hasListObservers) {
212 _recordChange(new ListChangeRecord(this, index, addedCount: 1)); 221 _recordChange(new ListChangeRecord(this, index, addedCount: 1));
213 } 222 }
214 _list[index] = element; 223 _list[index] = element;
215 } 224 }
216 225
217 226
218 E removeAt(int index) { 227 E removeAt(int index) {
219 E result = this[index]; 228 E result = this[index];
220 removeRange(index, index + 1); 229 removeRange(index, index + 1);
(...skipping 12 matching lines...) Expand all
233 void _recordChange(ListChangeRecord record) { 242 void _recordChange(ListChangeRecord record) {
234 if (!_hasListObservers) return; 243 if (!_hasListObservers) return;
235 244
236 if (_listRecords == null) { 245 if (_listRecords == null) {
237 _listRecords = []; 246 _listRecords = [];
238 scheduleMicrotask(deliverListChanges); 247 scheduleMicrotask(deliverListChanges);
239 } 248 }
240 _listRecords.add(record); 249 _listRecords.add(record);
241 } 250 }
242 251
252 void _notifyChangeLength(int oldValue, int newValue) {
253 notifyPropertyChange(#length, oldValue, newValue);
254 notifyPropertyChange(#isEmpty, oldValue == 0, newValue == 0);
255 notifyPropertyChange(#isNotEmpty, oldValue != 0, newValue != 0);
256 }
257
243 bool deliverListChanges() { 258 bool deliverListChanges() {
244 if (_listRecords == null) return false; 259 if (_listRecords == null) return false;
245 var records = projectListSplices(this, _listRecords); 260 var records = projectListSplices(this, _listRecords);
246 _listRecords = null; 261 _listRecords = null;
247 262
248 if (_hasListObservers) { 263 if (_hasListObservers) {
249 _listChanges.add(new UnmodifiableListView<ListChangeRecord>(records)); 264 _listChanges.add(new UnmodifiableListView<ListChangeRecord>(records));
250 return true; 265 return true;
251 } 266 }
252 return false; 267 return false;
(...skipping 10 matching lines...) Expand all
263 * final state of a list. The basic approach is to calculate the edit distance 278 * final state of a list. The basic approach is to calculate the edit distance
264 * matrix and choose the shortest path through it. 279 * matrix and choose the shortest path through it.
265 * 280 *
266 * Complexity is `O(l * p)` where `l` is the length of the current list and 281 * Complexity is `O(l * p)` where `l` is the length of the current list and
267 * `p` is the length of the old list. 282 * `p` is the length of the old list.
268 */ 283 */
269 static List<ListChangeRecord> calculateChangeRecords( 284 static List<ListChangeRecord> calculateChangeRecords(
270 List<Object> oldValue, List<Object> newValue) => 285 List<Object> oldValue, List<Object> newValue) =>
271 calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length); 286 calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length);
272 } 287 }
OLDNEW
« no previous file with comments | « no previous file | pkg/observe/test/observable_list_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698