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

Side by Side Diff: lib/observe/list.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.list;
6
7 import 'dart:collection';
8 import 'package:web_ui/observe.dart';
9
10 // TODO(jmesserly): this should extend the real list implementation.
11 // See http://dartbug.com/2600. The workaround was to copy+paste lots of code
12 // from the VM.
13 /**
14 * Represents an observable list of model values. If any items are added,
15 * removed, or replaced, then observers that are registered with
16 * [observe] will be notified.
17 */
18 class ObservableList<E> extends Collection<E> implements List<E> {
19 /** The inner [List<E>] with the actual storage. */
20 final List<E> _list;
21
22 final List<Object> _observeIndex;
23 Object _observeLength;
24
25 /**
26 * Creates an observable list of the given [length].
27 *
28 * If no [length] argument is supplied an extendable list of
29 * length 0 is created.
30 *
31 * If a [length] argument is supplied, a fixed size list of that
32 * length is created.
33 */
34 ObservableList([int length = 0])
35 : _list = new List<E>(length),
36 _observeIndex = new List<Object>(length);
37
38 /**
39 * Creates an observable list with the elements of [other]. The order in
40 * the list will be the order provided by the iterator of [other].
41 */
42 factory ObservableList.from(Iterable<E> other) =>
43 new ObservableList<E>()..addAll(other);
44
45 // TODO(jmesserly): This should be on List.
46 // See http://code.google.com/p/dart/issues/detail?id=947
Siggi Cherem (dart-lang) 2013/02/13 01:43:24 947 seems to be marked as fixed... it seems that '
Jennifer Messerly 2013/02/13 05:43:15 yeah. It seems to be abstract though, so we still
47 bool remove(E item) {
48 int i = indexOf(item);
49 if (i == -1) return false;
50 removeAt(i);
51 return true;
52 }
53
54 // TODO(jmesserly): This should be on List, to match removeAt.
55 // See http://code.google.com/p/dart/issues/detail?id=5375
56 void insertAt(int index, E item) => insertRange(index, 1, item);
57
58 bool contains(E item) => Collections.contains(_list, item);
Siggi Cherem (dart-lang) 2013/02/13 01:43:24 Are you using Collections to skip over any overhea
Jennifer Messerly 2013/02/13 05:43:15 I think _list.contains would have less overhead. B
59
60 E get first => this[0];
61
62 Iterator<E> get iterator => new ListIterator<E>(this);
63
64 int get length {
65 if (observeReads) _observeLength = notifyRead(_observeLength);
66 return _list.length;
67 }
68
69 set length(int value) {
70 if (length == value) return;
71
72 if (_observeLength != null) _observeLength = notifyWrite(_observeLength);
73
74 // If we are shrinking the list, explicitly null out items so we track
75 // the change to those items.
76 for (int i = value; i < _list.length; i++) {
77 this[i] = null;
78 }
79 _observeIndex.length = value;
80 _list.length = value;
81 }
82
83 E operator [](int index) {
84 if (observeReads) _observeIndex[index] = notifyRead(_observeIndex[index]);
85 return _list[index];
86 }
87
88 operator []=(int index, E value) {
89 var observer = _observeIndex[index];
90 var oldValue = _list[index];
91 if (observer != null && oldValue != value) {
92 _observeIndex[index] = notifyWrite(observer);
93 }
94 _list[index] = value;
95 }
96
97 void add(E value) {
98 if (_observeLength != null) _observeLength = notifyWrite(_observeLength);
99 _list.add(value);
100 _observeIndex.add(null);
101 }
102
103 // ---------------------------------------------------------------------------
104 // Note: below this comment, methods are either:
105 // * redirect to Arrays
106 // * redirect to Collections
107 // * copy+paste from VM GrowableObjectArray.
108 // The general idea is to have these methods operate in terms of our primitive
109 // methods above, so they correctly track reads/writes.
Siggi Cherem (dart-lang) 2013/02/13 01:43:24 consider moving contains, insertAt, first, and ite
Jennifer Messerly 2013/02/13 05:43:15 good call
110 // ---------------------------------------------------------------------------
111
112 E removeLast() {
113 var len = length - 1;
114 var elem = this[len];
115 length = len;
116 return elem;
117 }
118
119 int indexOf(E element, [int start = 0]) =>
120 Arrays.indexOf(this, element, start, length);
121
122 int lastIndexOf(E element, [int start]) =>
123 Arrays.lastIndexOf(this, element, start);
124
125 ObservableList<E> getRange(int start, int length) {
126 if (length == 0) return [];
127 Arrays.rangeCheck(this, start, length);
128 List list = new ObservableList<E>(length);
129 Arrays.copy(this, start, list, 0, length);
130 return list;
131 }
132
133 bool get isEmpty => length == 0;
134
135 E get last => this[length - 1];
136
137 void addLast(E value) => add(value);
138
139 void addAll(Iterable<E> collection) {
140 for (E elem in collection) {
141 add(elem);
142 }
143 }
144
145 void sort([compare = Comparable.compare]) =>
146 IterableMixinWorkaround.sortList(this, compare);
147
148 List<E> get reversed => IterableMixinWorkaround.reversedList(this);
149
150 void clear() {
151 this.length = 0;
152 }
153
154 E removeAt(int index) {
155 if (index is! int) throw new ArgumentError(index);
156 E result = this[index];
157 int newLength = this.length - 1;
158 Arrays.copy(this,
159 index + 1,
160 this,
161 index,
162 newLength - index);
163 this.length = newLength;
164 return result;
165 }
166
167 void setRange(int start, int length, List<E> from, [int startFrom = 0]) {
168 Arrays.copy(from, startFrom, this, start, length);
169 }
170
171 void removeRange(int start, int length) {
172 if (length == 0) {
173 return;
174 }
175 Arrays.rangeCheck(this, start, length);
176 Arrays.copy(this,
177 start + length,
178 this,
179 start,
180 this.length - length - start);
181 this.length = this.length - length;
182 }
183
184 void insertRange(int start, int length, [E initialValue]) {
185 if (length == 0) {
186 return;
187 }
188 if ((length < 0) || (length is! int)) {
189 throw new ArgumentError("invalid length specified $length");
190 }
191 if (start < 0 || start > this.length) {
192 throw new RangeError.value(start);
193 }
194 var oldLength = this.length;
195 this.length = oldLength + length; // Will expand if needed.
196 Arrays.copy(this,
197 start,
198 this,
199 start + length,
200 oldLength - start);
201 for (int i = start; i < start + length; i++) {
202 this[i] = initialValue;
203 }
204 }
205
206 String toString() => Collections.collectionToString(this);
207 }
208
209 // TODO(jmesserly): copy+paste from collection-dev
Siggi Cherem (dart-lang) 2013/02/13 01:43:24 I assume collection-dev can't be used, or we shoud
Jennifer Messerly 2013/02/13 05:43:15 yup. According to Florian/Lasse everything you nee
210 /**
211 * Iterates over a [List] in growing index order.
212 */
213 class ListIterator<E> implements Iterator<E> {
214 final List<E> _list;
215 final int _length;
216 int _position;
217 E _current;
218
219 ListIterator(List<E> list)
220 : _list = list, _position = -1, _length = list.length;
221
222 bool moveNext() {
223 if (_list.length != _length) {
224 throw new ConcurrentModificationError(_list);
225 }
226 int nextPosition = _position + 1;
227 if (nextPosition < _length) {
228 _position = nextPosition;
229 _current = _list[nextPosition];
230 return true;
231 }
232 _current = null;
233 return false;
234 }
235
236 E get current => _current;
237 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698