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

Side by Side Diff: lib/src/path_observer.dart

Issue 1616953004: Fixed strong mode errors and warnings reachable from lib/observe.dart (Closed) Base URL: https://github.com/dart-lang/observe.git@master
Patch Set: Removed inferrable type param Created 4 years, 11 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/src/observable_map.dart ('k') | lib/transformer.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.path_observer; 5 library observe.src.path_observer;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:math' show min; 9 import 'dart:math' show min;
10 10
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 throw new ArgumentError( 125 throw new ArgumentError(
126 'List must contain only ints, Strings, and Symbols'); 126 'List must contain only ints, Strings, and Symbols');
127 } 127 }
128 } 128 }
129 return new PropertyPath._(copy); 129 return new PropertyPath._(copy);
130 } 130 }
131 131
132 var pathObj = _pathCache[path]; 132 var pathObj = _pathCache[path];
133 if (pathObj != null) return pathObj; 133 if (pathObj != null) return pathObj;
134 134
135
136 final segments = new _PathParser().parse(path); 135 final segments = new _PathParser().parse(path);
137 if (segments == null) return _InvalidPropertyPath._instance; 136 if (segments == null) return _InvalidPropertyPath._instance;
138 137
139 // TODO(jmesserly): we could use an UnmodifiableListView here, but that adds 138 // TODO(jmesserly): we could use an UnmodifiableListView here, but that adds
140 // memory overhead. 139 // memory overhead.
141 pathObj = new PropertyPath._(segments.toList(growable: false)); 140 pathObj = new PropertyPath._(segments.toList(growable: false));
142 if (_pathCache.length >= _pathCacheLimit) { 141 if (_pathCache.length >= _pathCacheLimit) {
143 _pathCache.remove(_pathCache.keys.first); 142 _pathCache.remove(_pathCache.keys.first);
144 } 143 }
145 _pathCache[path] = pathObj; 144 _pathCache[path] = pathObj;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function 193 /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
195 // TODO(jmesserly): should reuse this instead, see 194 // TODO(jmesserly): should reuse this instead, see
196 // https://code.google.com/p/dart/issues/detail?id=11617 195 // https://code.google.com/p/dart/issues/detail?id=11617
197 int get hashCode { 196 int get hashCode {
198 int hash = 0; 197 int hash = 0;
199 for (int i = 0, len = _segments.length; i < len; i++) { 198 for (int i = 0, len = _segments.length; i < len; i++) {
200 hash = 0x1fffffff & (hash + _segments[i].hashCode); 199 hash = 0x1fffffff & (hash + _segments[i].hashCode);
201 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); 200 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
202 hash = hash ^ (hash >> 6); 201 hash = hash ^ (hash >> 6);
203 } 202 }
204 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); 203 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
205 hash = hash ^ (hash >> 11); 204 hash = hash ^ (hash >> 11);
206 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); 205 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
207 } 206 }
208 207
209 /// Returns the current value of the path from the provided [obj]ect. 208 /// Returns the current value of the path from the provided [obj]ect.
210 getValueFrom(Object obj) { 209 getValueFrom(Object obj) {
211 if (!isValid) return null; 210 if (!isValid) return null;
212 for (var segment in _segments) { 211 for (var segment in _segments) {
213 if (obj == null) return null; 212 if (obj == null) return null;
214 obj = _getObjectProperty(obj, segment); 213 obj = _getObjectProperty(obj, segment);
(...skipping 23 matching lines...) Expand all
238 observe(obj, _segments[i]); 237 observe(obj, _segments[i]);
239 238
240 if (i >= last) break; 239 if (i >= last) break;
241 obj = _getObjectProperty(obj, _segments[i++]); 240 obj = _getObjectProperty(obj, _segments[i++]);
242 } 241 }
243 } 242 }
244 243
245 // Dart note: it doesn't make sense to have compiledGetValueFromFn in Dart. 244 // Dart note: it doesn't make sense to have compiledGetValueFromFn in Dart.
246 } 245 }
247 246
248
249 /// Visible only for testing: 247 /// Visible only for testing:
250 getSegmentsOfPropertyPathForTesting(p) => p._segments; 248 getSegmentsOfPropertyPathForTesting(p) => p._segments;
251 249
252 class _InvalidPropertyPath extends PropertyPath { 250 class _InvalidPropertyPath extends PropertyPath {
253 static final _instance = new _InvalidPropertyPath(); 251 static final _instance = new _InvalidPropertyPath();
254 252
255 bool get isValid => false; 253 bool get isValid => false;
256 _InvalidPropertyPath() : super._([]); 254 _InvalidPropertyPath() : super._([]);
257 } 255 }
258 256
(...skipping 12 matching lines...) Expand all
271 } 269 }
272 } else if (property is String) { 270 } else if (property is String) {
273 return object[property]; 271 return object[property];
274 } else if (property is Symbol) { 272 } else if (property is Symbol) {
275 // Support indexer if available, e.g. Maps or polymer_expressions Scope. 273 // Support indexer if available, e.g. Maps or polymer_expressions Scope.
276 // This is the default syntax used by polymer/nodebind and 274 // This is the default syntax used by polymer/nodebind and
277 // polymer/observe-js PathObserver. 275 // polymer/observe-js PathObserver.
278 // TODO(sigmund): should we also support using checking dynamically for 276 // TODO(sigmund): should we also support using checking dynamically for
279 // whether the type practically implements the indexer API 277 // whether the type practically implements the indexer API
280 // (smoke.hasInstanceMethod(type, const Symbol('[]')))? 278 // (smoke.hasInstanceMethod(type, const Symbol('[]')))?
281 if (object is Indexable || object is Map && !_MAP_PROPERTIES.contains(proper ty)) { 279 if (object is Indexable ||
280 object is Map && !_MAP_PROPERTIES.contains(property)) {
282 return object[smoke.symbolToName(property)]; 281 return object[smoke.symbolToName(property)];
283 } 282 }
284 try { 283 try {
285 return smoke.read(object, property); 284 return smoke.read(object, property);
286 } on NoSuchMethodError catch (_) { 285 } on NoSuchMethodError catch (_) {
287 // Rethrow, unless the type implements noSuchMethod, in which case we 286 // Rethrow, unless the type implements noSuchMethod, in which case we
288 // interpret the exception as a signal that the method was not found. 287 // interpret the exception as a signal that the method was not found.
289 // Dart note: getting invalid properties is an error, unlike in JS where 288 // Dart note: getting invalid properties is an error, unlike in JS where
290 // it returns undefined. 289 // it returns undefined.
291 if (!smoke.hasNoSuchMethod(object.runtimeType)) rethrow; 290 if (!smoke.hasNoSuchMethod(object.runtimeType)) rethrow;
292 } 291 }
293 } 292 }
294 293
295 if (_logger.isLoggable(Level.FINER)) { 294 if (_logger.isLoggable(Level.FINER)) {
296 _logger.finer("can't get $property in $object"); 295 _logger.finer("can't get $property in $object");
297 } 296 }
298 return null; 297 return null;
299 } 298 }
300 299
301 bool _setObjectProperty(object, property, value) { 300 bool _setObjectProperty(object, property, value) {
302 if (object == null) return false; 301 if (object == null) return false;
303 302
304 if (property is int) { 303 if (property is int) {
305 if (object is List && property >= 0 && property < object.length) { 304 if (object is List && property >= 0 && property < object.length) {
306 object[property] = value; 305 object[property] = value;
307 return true; 306 return true;
308 } 307 }
309 } else if (property is Symbol) { 308 } else if (property is Symbol) {
310 // Support indexer if available, e.g. Maps or polymer_expressions Scope. 309 // Support indexer if available, e.g. Maps or polymer_expressions Scope.
311 if (object is Indexable || object is Map && !_MAP_PROPERTIES.contains(proper ty)) { 310 if (object is Indexable ||
311 object is Map && !_MAP_PROPERTIES.contains(property)) {
312 object[smoke.symbolToName(property)] = value; 312 object[smoke.symbolToName(property)] = value;
313 return true; 313 return true;
314 } 314 }
315 try { 315 try {
316 smoke.write(object, property, value); 316 smoke.write(object, property, value);
317 return true; 317 return true;
318 } on NoSuchMethodError catch (_) { 318 } on NoSuchMethodError catch (_) {
319 if (!smoke.hasNoSuchMethod(object.runtimeType)) rethrow; 319 if (!smoke.hasNoSuchMethod(object.runtimeType)) rethrow;
320 } 320 }
321 } 321 }
(...skipping 10 matching lines...) Expand all
332 const identStart = '[\$_a-zA-Z]'; 332 const identStart = '[\$_a-zA-Z]';
333 const identPart = '[\$_a-zA-Z0-9]'; 333 const identPart = '[\$_a-zA-Z0-9]';
334 return new RegExp('^$identStart+$identPart*\$'); 334 return new RegExp('^$identStart+$identPart*\$');
335 }(); 335 }();
336 336
337 _isIdent(s) => _identRegExp.hasMatch(s); 337 _isIdent(s) => _identRegExp.hasMatch(s);
338 338
339 // Dart note: refactored to convert to codepoints once and operate on codepoints 339 // Dart note: refactored to convert to codepoints once and operate on codepoints
340 // rather than characters. 340 // rather than characters.
341 class _PathParser { 341 class _PathParser {
342 List keys = []; 342 List<Object> keys = [];
343 int index = -1; 343 int index = -1;
344 String key; 344 String key;
345 345
346 final Map<String, List<String>> _pathStateMachine = { 346 final Map<String, Map<String, List<String>>> _pathStateMachine = {
347 'beforePath': { 347 'beforePath': {
348 'ws': ['beforePath'], 348 'ws': ['beforePath'],
349 'ident': ['inIdent', 'append'], 349 'ident': ['inIdent', 'append'],
350 '[': ['beforeElement'], 350 '[': ['beforeElement'],
351 'eof': ['afterPath'] 351 'eof': ['afterPath']
352 }, 352 },
353
354 'inPath': { 353 'inPath': {
355 'ws': ['inPath'], 354 'ws': ['inPath'],
356 '.': ['beforeIdent'], 355 '.': ['beforeIdent'],
357 '[': ['beforeElement'], 356 '[': ['beforeElement'],
358 'eof': ['afterPath'] 357 'eof': ['afterPath']
359 }, 358 },
360
361 'beforeIdent': { 359 'beforeIdent': {
362 'ws': ['beforeIdent'], 360 'ws': ['beforeIdent'],
363 'ident': ['inIdent', 'append'] 361 'ident': ['inIdent', 'append']
364 }, 362 },
365
366 'inIdent': { 363 'inIdent': {
367 'ident': ['inIdent', 'append'], 364 'ident': ['inIdent', 'append'],
368 '0': ['inIdent', 'append'], 365 '0': ['inIdent', 'append'],
369 'number': ['inIdent', 'append'], 366 'number': ['inIdent', 'append'],
370 'ws': ['inPath', 'push'], 367 'ws': ['inPath', 'push'],
371 '.': ['beforeIdent', 'push'], 368 '.': ['beforeIdent', 'push'],
372 '[': ['beforeElement', 'push'], 369 '[': ['beforeElement', 'push'],
373 'eof': ['afterPath', 'push'] 370 'eof': ['afterPath', 'push']
374 }, 371 },
375
376 'beforeElement': { 372 'beforeElement': {
377 'ws': ['beforeElement'], 373 'ws': ['beforeElement'],
378 '0': ['afterZero', 'append'], 374 '0': ['afterZero', 'append'],
379 'number': ['inIndex', 'append'], 375 'number': ['inIndex', 'append'],
380 "'": ['inSingleQuote', 'append', ''], 376 "'": ['inSingleQuote', 'append', ''],
381 '"': ['inDoubleQuote', 'append', ''] 377 '"': ['inDoubleQuote', 'append', '']
382 }, 378 },
383
384 'afterZero': { 379 'afterZero': {
385 'ws': ['afterElement', 'push'], 380 'ws': ['afterElement', 'push'],
386 ']': ['inPath', 'push'] 381 ']': ['inPath', 'push']
387 }, 382 },
388
389 'inIndex': { 383 'inIndex': {
390 '0': ['inIndex', 'append'], 384 '0': ['inIndex', 'append'],
391 'number': ['inIndex', 'append'], 385 'number': ['inIndex', 'append'],
392 'ws': ['afterElement'], 386 'ws': ['afterElement'],
393 ']': ['inPath', 'push'] 387 ']': ['inPath', 'push']
394 }, 388 },
395
396 'inSingleQuote': { 389 'inSingleQuote': {
397 "'": ['afterElement'], 390 "'": ['afterElement'],
398 'eof': ['error'], 391 'eof': ['error'],
399 'else': ['inSingleQuote', 'append'] 392 'else': ['inSingleQuote', 'append']
400 }, 393 },
401
402 'inDoubleQuote': { 394 'inDoubleQuote': {
403 '"': ['afterElement'], 395 '"': ['afterElement'],
404 'eof': ['error'], 396 'eof': ['error'],
405 'else': ['inDoubleQuote', 'append'] 397 'else': ['inDoubleQuote', 'append']
406 }, 398 },
407
408 'afterElement': { 399 'afterElement': {
409 'ws': ['afterElement'], 400 'ws': ['afterElement'],
410 ']': ['inPath', 'push'] 401 ']': ['inPath', 'push']
411 } 402 }
412 }; 403 };
413 404
414 /// From getPathCharType: determines the type of a given [code]point. 405 /// From getPathCharType: determines the type of a given [code]point.
415 String _getPathCharType(code) { 406 String _getPathCharType(code) {
416 if (code == null) return 'eof'; 407 if (code == null) return 'eof';
417 switch(code) { 408 switch (code) {
418 case 0x5B: // [ 409 case 0x5B: // [
419 case 0x5D: // ] 410 case 0x5D: // ]
420 case 0x2E: // . 411 case 0x2E: // .
421 case 0x22: // " 412 case 0x22: // "
422 case 0x27: // ' 413 case 0x27: // '
423 case 0x30: // 0 414 case 0x30: // 0
424 return _char(code); 415 return _char(code);
425 416
426 case 0x5F: // _ 417 case 0x5F: // _
427 case 0x24: // $ 418 case 0x24: // $
428 return 'ident'; 419 return 'ident';
429 420
430 case 0x20: // Space 421 case 0x20: // Space
431 case 0x09: // Tab 422 case 0x09: // Tab
432 case 0x0A: // Newline 423 case 0x0A: // Newline
433 case 0x0D: // Return 424 case 0x0D: // Return
434 case 0xA0: // No-break space 425 case 0xA0: // No-break space
435 case 0xFEFF: // Byte Order Mark 426 case 0xFEFF: // Byte Order Mark
436 case 0x2028: // Line Separator 427 case 0x2028: // Line Separator
437 case 0x2029: // Paragraph Separator 428 case 0x2029: // Paragraph Separator
438 return 'ws'; 429 return 'ws';
439 } 430 }
440 431
441 // a-z, A-Z 432 // a-z, A-Z
442 if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A)) 433 if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
443 return 'ident'; 434 return 'ident';
444 435
445 // 1-9 436 // 1-9
446 if (0x31 <= code && code <= 0x39) 437 if (0x31 <= code && code <= 0x39) return 'number';
447 return 'number';
448 438
449 return 'else'; 439 return 'else';
450 } 440 }
451 441
452 static String _char(int codepoint) => new String.fromCharCodes([codepoint]); 442 static String _char(int codepoint) => new String.fromCharCodes([codepoint]);
453 443
454 void push() { 444 void push() {
455 if (key == null) return; 445 if (key == null) return;
456 446
457 // Dart note: we store the keys with different types, rather than 447 // Dart note: we store the keys with different types, rather than
(...skipping 17 matching lines...) Expand all
475 if ((mode == 'inSingleQuote' && nextChar == "'") || 465 if ((mode == 'inSingleQuote' && nextChar == "'") ||
476 (mode == 'inDoubleQuote' && nextChar == '"')) { 466 (mode == 'inDoubleQuote' && nextChar == '"')) {
477 index++; 467 index++;
478 append(nextChar); 468 append(nextChar);
479 return true; 469 return true;
480 } 470 }
481 return false; 471 return false;
482 } 472 }
483 473
484 /// Returns the parsed keys, or null if there was a parse error. 474 /// Returns the parsed keys, or null if there was a parse error.
485 List<String> parse(String path) { 475 List<Object> parse(String path) {
486 var codePoints = stringToCodepoints(path); 476 var codePoints = stringToCodepoints(path);
487 var mode = 'beforePath'; 477 var mode = 'beforePath';
488 478
489 while (mode != null) { 479 while (mode != null) {
490 index++; 480 index++;
491 var c = index >= codePoints.length ? null : codePoints[index]; 481 var c = index >= codePoints.length ? null : codePoints[index];
492 482
493 if (c != null && 483 if (c != null &&
494 _char(c) == '\\' && _maybeUnescapeQuote(mode, codePoints)) continue; 484 _char(c) == '\\' &&
485 _maybeUnescapeQuote(mode, codePoints)) continue;
495 486
496 var type = _getPathCharType(c); 487 var type = _getPathCharType(c);
497 if (mode == 'error') return null; 488 if (mode == 'error') return null;
498 489
499 var typeMap = _pathStateMachine[mode]; 490 var typeMap = _pathStateMachine[mode];
500 var transition = typeMap[type]; 491 var transition = typeMap[type];
501 if (transition == null) transition = typeMap['else']; 492 if (transition == null) transition = typeMap['else'];
502 if (transition == null) return null; // parse error; 493 if (transition == null) return null; // parse error;
503 494
504 mode = transition[0]; 495 mode = transition[0];
505 var actionName = transition.length > 1 ? transition[1] : null; 496 var actionName = transition.length > 1 ? transition[1] : null;
506 if (actionName == 'push' && key != null) push(); 497 if (actionName == 'push' && key != null) push();
507 if (actionName == 'append') { 498 if (actionName == 'append') {
508 var newChar = transition.length > 2 && transition[2] != null 499 var newChar = transition.length > 2 && transition[2] != null
509 ? transition[2] : _char(c); 500 ? transition[2]
501 : _char(c);
510 append(newChar); 502 append(newChar);
511 } 503 }
512 504
513 if (mode == 'afterPath') return keys; 505 if (mode == 'afterPath') return keys;
514 } 506 }
515 return null; // parse error 507 return null; // parse error
516 } 508 }
517 } 509 }
518 510
519 final Logger _logger = new Logger('observe.PathObserver'); 511 final Logger _logger = new Logger('observe.PathObserver');
520 512
521
522 /// This is a simple cache. It's like LRU but we don't update an item on a 513 /// This is a simple cache. It's like LRU but we don't update an item on a
523 /// cache hit, because that would require allocation. Better to let it expire 514 /// cache hit, because that would require allocation. Better to let it expire
524 /// and reallocate the PropertyPath. 515 /// and reallocate the PropertyPath.
525 // TODO(jmesserly): this optimization is from observe-js, how valuable is it in 516 // TODO(jmesserly): this optimization is from observe-js, how valuable is it in
526 // practice? 517 // practice?
527 final _pathCache = new LinkedHashMap<String, PropertyPath>(); 518 final _pathCache = new LinkedHashMap<String, PropertyPath>();
528 519
529 /// The size of a path like "foo.bar" is approximately 160 bytes, so this 520 /// The size of a path like "foo.bar" is approximately 160 bytes, so this
530 /// reserves ~16Kb of memory for recently used paths. Since paths are frequently 521 /// reserves ~16Kb of memory for recently used paths. Since paths are frequently
531 /// reused, the theory is that this ends up being a good tradeoff in practice. 522 /// reused, the theory is that this ends up being a good tradeoff in practice.
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 bool _check({bool skipChanges: false}) { 630 bool _check({bool skipChanges: false}) {
640 bool changed = false; 631 bool changed = false;
641 _value.length = _observed.length ~/ 2; 632 _value.length = _observed.length ~/ 2;
642 var oldValues = null; 633 var oldValues = null;
643 for (var i = 0; i < _observed.length; i += 2) { 634 for (var i = 0; i < _observed.length; i += 2) {
644 var object = _observed[i]; 635 var object = _observed[i];
645 var path = _observed[i + 1]; 636 var path = _observed[i + 1];
646 var value; 637 var value;
647 if (identical(object, _observerSentinel)) { 638 if (identical(object, _observerSentinel)) {
648 var observable = path as Bindable; 639 var observable = path as Bindable;
649 value = _state == _Observer._UNOPENED ? 640 value = _state == _Observer._UNOPENED
650 observable.open((_) => this.deliver()) : 641 ? observable.open((_) => this.deliver())
651 observable.value; 642 : observable.value;
652 } else { 643 } else {
653 value = (path as PropertyPath).getValueFrom(object); 644 value = (path as PropertyPath).getValueFrom(object);
654 } 645 }
655 646
656 if (skipChanges) { 647 if (skipChanges) {
657 _value[i ~/ 2] = value; 648 _value[i ~/ 2] = value;
658 continue; 649 continue;
659 } 650 }
660 651
661 if (value == _value[i ~/ 2]) continue; 652 if (value == _value[i ~/ 2]) continue;
(...skipping 18 matching lines...) Expand all
680 } 671 }
681 672
682 /// An object accepted by [PropertyPath] where properties are read and written 673 /// An object accepted by [PropertyPath] where properties are read and written
683 /// as indexing operations, just like a [Map]. 674 /// as indexing operations, just like a [Map].
684 abstract class Indexable<K, V> { 675 abstract class Indexable<K, V> {
685 V operator [](K key); 676 V operator [](K key);
686 operator []=(K key, V value); 677 operator []=(K key, V value);
687 } 678 }
688 679
689 const _observerSentinel = const _ObserverSentinel(); 680 const _observerSentinel = const _ObserverSentinel();
690 class _ObserverSentinel { const _ObserverSentinel(); } 681
682 class _ObserverSentinel {
683 const _ObserverSentinel();
684 }
691 685
692 // Visible for testing 686 // Visible for testing
693 get observerSentinelForTesting => _observerSentinel; 687 get observerSentinelForTesting => _observerSentinel;
694 688
695 // A base class for the shared API implemented by PathObserver and 689 // A base class for the shared API implemented by PathObserver and
696 // CompoundObserver and used in _ObservedSet. 690 // CompoundObserver and used in _ObservedSet.
697 abstract class _Observer extends Bindable { 691 abstract class _Observer extends Bindable {
698 Function _notifyCallback; 692 Function _notifyCallback;
699 int _notifyArgumentCount; 693 int _notifyArgumentCount;
700 var _value; 694 var _value;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
757 var cycles = 0; 751 var cycles = 0;
758 while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) { 752 while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) {
759 cycles++; 753 cycles++;
760 } 754 }
761 return cycles > 0; 755 return cycles > 0;
762 } 756 }
763 757
764 void _report(newValue, oldValue, [extraArg]) { 758 void _report(newValue, oldValue, [extraArg]) {
765 try { 759 try {
766 switch (_notifyArgumentCount) { 760 switch (_notifyArgumentCount) {
767 case 0: _notifyCallback(); break; 761 case 0:
768 case 1: _notifyCallback(newValue); break; 762 _notifyCallback();
769 case 2: _notifyCallback(newValue, oldValue); break; 763 break;
770 case 3: _notifyCallback(newValue, oldValue, extraArg); break; 764 case 1:
765 _notifyCallback(newValue);
766 break;
767 case 2:
768 _notifyCallback(newValue, oldValue);
769 break;
770 case 3:
771 _notifyCallback(newValue, oldValue, extraArg);
772 break;
771 } 773 }
772 } catch (e, s) { 774 } catch (e, s) {
773 // Deliver errors async, so if a single callback fails it doesn't prevent 775 // Deliver errors async, so if a single callback fails it doesn't prevent
774 // other things from working. 776 // other things from working.
775 new Completer().completeError(e, s); 777 new Completer().completeError(e, s);
776 } 778 }
777 } 779 }
778 } 780 }
779 781
780 /// The observedSet abstraction is a perf optimization which reduces the total 782 /// The observedSet abstraction is a perf optimization which reduces the total
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 } 898 }
897 } else { 899 } else {
898 // TODO(sigmund): consider adding object to MapChangeRecord, and make 900 // TODO(sigmund): consider adding object to MapChangeRecord, and make
899 // this more precise. 901 // this more precise.
900 return false; 902 return false;
901 } 903 }
902 } 904 }
903 return true; 905 return true;
904 } 906 }
905 907
906 void _callback(records) { 908 void _callback(List<ChangeRecord> records) {
907 if (_canIgnoreRecords(records)) return; 909 if (_canIgnoreRecords(records)) return;
908 for (var observer in _observers.toList(growable: false)) { 910 for (var observer in _observers.toList(growable: false)) {
909 if (observer._isOpen) observer._iterateObjects(observe); 911 if (observer._isOpen) observer._iterateObjects(observe);
910 } 912 }
911 913
912 for (var observer in _observers.toList(growable: false)) { 914 for (var observer in _observers.toList(growable: false)) {
913 if (observer._isOpen) observer._check(); 915 if (observer._isOpen) observer._check();
914 } 916 }
915 } 917 }
916 } 918 }
917 919
918 const int _MAX_DIRTY_CHECK_CYCLES = 1000; 920 const int _MAX_DIRTY_CHECK_CYCLES = 1000;
OLDNEW
« no previous file with comments | « lib/src/observable_map.dart ('k') | lib/transformer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698