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

Unified Diff: pkg/mdv_observe/lib/src/observable_list.dart

Issue 14908005: "Reverting 22561" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/mdv_observe/lib/src/observable_box.dart ('k') | pkg/mdv_observe/lib/src/observable_map.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/mdv_observe/lib/src/observable_list.dart
diff --git a/pkg/mdv_observe/lib/src/observable_list.dart b/pkg/mdv_observe/lib/src/observable_list.dart
deleted file mode 100644
index c3ae880cb3fa10d553fafdb219d62084471c76ec..0000000000000000000000000000000000000000
--- a/pkg/mdv_observe/lib/src/observable_list.dart
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of mdv_observe;
-
-/**
- * Represents an observable list of model values. If any items are added,
- * removed, or replaced, then observers that are listening to [changes]
- * will be notified.
- */
-// TODO(jmesserly): remove implements List<E> once we can extend ListBase<E>
-class ObservableList<E> extends _ListBaseWorkaround with ObservableMixin
- implements List<E> {
- List<ListChangeRecord> _records;
-
- static const _LENGTH = const Symbol('length');
-
- /** The inner [List<E>] with the actual storage. */
- final List<E> _list;
-
- /**
- * Creates an observable list of the given [length].
- *
- * If no [length] argument is supplied an extendable list of
- * length 0 is created.
- *
- * If a [length] argument is supplied, a fixed size list of that
- * length is created.
- */
- ObservableList([int length])
- : _list = length != null ? new List<E>(length) : <E>[];
-
- /**
- * Creates an observable list with the elements of [other]. The order in
- * the list will be the order provided by the iterator of [other].
- */
- factory ObservableList.from(Iterable<E> other) =>
- new ObservableList<E>()..addAll(other);
-
- // TODO(jmesserly): remove once we have mirrors
- getValueWorkaround(key) => key == _LENGTH ? length : null;
-
- setValueWorkaround(key, value) {
- if (key == _LENGTH) length = value;
- }
-
- int get length => _list.length;
-
- set length(int value) {
- int len = _list.length;
- if (len == value) return;
-
- // Produce notifications if needed
- if (hasObservers) {
- if (value < len) {
- // Remove items, then adjust length. Note the reverse order.
- _recordChange(new ListChangeRecord(value, removedCount: len - value));
- } else {
- // Adjust length then add items
- _recordChange(new ListChangeRecord(len, addedCount: value - len));
- }
- }
-
- _list.length = value;
- }
-
- E operator [](int index) => _list[index];
-
- void operator []=(int index, E value) {
- var oldValue = _list[index];
- if (hasObservers) {
- _recordChange(new ListChangeRecord(index, addedCount: 1, removedCount: 1));
- }
- _list[index] = value;
- }
-
- // The following methods are here so that we can provide nice change events.
-
- void setAll(int index, Iterable<E> iterable) {
- if (iterable is! List && iterable is! Set) {
- iterable = iterable.toList();
- }
- var len = iterable.length;
- _list.setAll(index, iterable);
- if (hasObservers && len > 0) {
- _recordChange(
- new ListChangeRecord(index, addedCount: len, removedCount: len));
- }
- }
-
- void add(E value) {
- int len = _list.length;
- if (hasObservers) {
- _recordChange(new ListChangeRecord(len, addedCount: 1));
- }
-
- _list.add(value);
- }
-
- void addAll(Iterable<E> iterable) {
- int len = _list.length;
- _list.addAll(iterable);
- int added = _list.length - len;
- if (hasObservers && added > 0) {
- _recordChange(new ListChangeRecord(len, addedCount: added));
- }
- }
-
- bool remove(Object element) {
- for (int i = 0; i < this.length; i++) {
- if (this[i] == element) {
- removeRange(i, 1);
- return true;
- }
- }
- return false;
- }
-
- void removeRange(int start, int end) {
- _rangeCheck(start, end);
- int length = end - start;
- _list.setRange(start, this.length - length, this, end);
-
- int len = _list.length;
- _list.length -= length;
- if (hasObservers && length > 0) {
- _recordChange(new ListChangeRecord(start, removedCount: length));
- }
- }
-
- void insertAll(int index, Iterable<E> iterable) {
- if (index < 0 || index > length) {
- throw new RangeError.range(index, 0, length);
- }
- // TODO(floitsch): we can probably detect more cases.
- if (iterable is! List && iterable is! Set) {
- iterable = iterable.toList();
- }
- int insertionLength = iterable.length;
- // There might be errors after the length change, in which case the list
- // will end up being modified but the operation not complete. Unless we
- // always go through a "toList" we can't really avoid that.
- int len = _list.length;
- _list.length += insertionLength;
-
- _list.setRange(index + insertionLength, this.length, this, index);
- _list.setAll(index, iterable);
-
- if (hasObservers && insertionLength > 0) {
- _recordChange(new ListChangeRecord(index, addedCount: insertionLength));
- }
- }
-
- void insert(int index, E element) {
- if (index < 0 || index > length) {
- throw new RangeError.range(index, 0, length);
- }
- if (index == length) {
- add(element);
- return;
- }
- // We are modifying the length just below the is-check. Without the check
- // Array.copy could throw an exception, leaving the list in a bad state
- // (with a length that has been increased, but without a new element).
- if (index is! int) throw new ArgumentError(index);
- _list.length++;
- _list.setRange(index + 1, length, this, index);
- if (hasObservers) {
- _recordChange(new ListChangeRecord(index, addedCount: 1));
- }
- _list[index] = element;
- }
-
-
- E removeAt(int index) {
- E result = this[index];
- removeRange(index, index + 1);
- return result;
- }
-
- void _rangeCheck(int start, int end) {
- if (start < 0 || start > this.length) {
- throw new RangeError.range(start, 0, this.length);
- }
- if (end < start || end > this.length) {
- throw new RangeError.range(end, start, this.length);
- }
- }
-
- void _recordChange(ListChangeRecord record) {
- if (_records == null) {
- _records = [];
- queueChangeRecords(_summarizeRecords);
- }
- _records.add(record);
- }
-
- /**
- * We need to summarize change records. Consumers of these records want to
- * apply the batch sequentially, and ensure that they can find inserted
- * items by looking at that position in the list. This property does not
- * hold in our record-as-you-go records. Consider:
- *
- * var model = toObservable(['a', 'b']);
- * model.removeAt(1);
- * model.insertAll(0, ['c', 'd', 'e']);
- * model.removeRange(1, 3);
- * model.insert(1, 'f');
- *
- * Here, we inserted some records and then removed some of them.
- * If someone processed these records naively, they would "play back" the
- * insert incorrectly, because those items will be shifted.
- *
- * We summarize changes using a straightforward technique:
- * Simulate the moves and use the final item positions to synthesize a
- * new list of changes records. This has the advantage of not depending
- * on the actual *values*, so we don't need to perform N^2 edit
- */
- // TODO(jmesserly): there's probably something smarter here, but this
- // algorithm is pretty simple. It has complexity equivalent to the original
- // list modifications.
- // One simple idea: we can simply update the index map as we do the operations
- // to the list, then produce the records at the end.
- void _summarizeRecords() {
- int oldLength = length;
- for (var r in _records) {
- oldLength += r.removedCount - r.addedCount;
- }
-
- if (length != oldLength) {
- notifyPropertyChange(_LENGTH, oldLength, length);
- }
-
- if (_records.length == 1) {
- notifyChange(_records[0]);
- _records = null;
- return;
- }
-
- var items = [];
- for (int i = 0; i < oldLength; i++) items.add(i);
- for (var r in _records) {
- items.removeRange(r.index, r.index + r.removedCount);
-
- // Represent inserts with -1.
- items.insertAll(r.index, new List.filled(r.addedCount, -1));
- }
- assert(items.length == length);
-
- _records = null;
-
- int index = 0;
- int offset = 0;
- while (index < items.length) {
- // Skip unchanged items.
- while (index < items.length && items[index] == index + offset) {
- index++;
- }
-
- // Find inserts
- int startIndex = index;
- while (index < items.length && items[index] == -1) {
- index++;
- }
-
- int added = index - startIndex;
-
- // Use the delta between our actual and expected position to determine
- // how much was removed.
- int actualItem = index < items.length ? items[index] : oldLength;
- int expectedItem = startIndex + offset;
-
- int removed = actualItem - expectedItem;
-
- if (added > 0 || removed > 0) {
- notifyChange(new ListChangeRecord(startIndex, addedCount: added,
- removedCount: removed));
- }
-
- offset += removed - added;
- }
- }
-}
-
-// TODO(jmesserly): bogus type to workaround spurious VM bug with generic base
-// class and mixins.
-abstract class _ListBaseWorkaround extends ListBase<dynamic> {}
« no previous file with comments | « pkg/mdv_observe/lib/src/observable_box.dart ('k') | pkg/mdv_observe/lib/src/observable_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698