@@ -37,13 +37,6 @@ class GetterCache {
37
37
* Each property to be watched is recorded as a [DirtyCheckingRecord] and kept
38
38
* in a linked list. Linked list are faster than Arrays for iteration. They also
39
39
* allow removal of large blocks of watches in an efficient manner.
40
- *
41
- * [ChangeRecord]
42
- *
43
- * When the results are delivered they are a linked list of [ChangeRecord] s. For
44
- * efficiency reasons the [DirtyCheckingRecord] and [ChangeRecord] are two
45
- * different interfaces for the same underlying object this makes reporting
46
- * efficient since no additional memory allocation is performed.
47
40
*/
48
41
class DirtyCheckingChangeDetectorGroup <H > implements ChangeDetectorGroup <H > {
49
42
/**
@@ -177,6 +170,10 @@ class DirtyCheckingChangeDetectorGroup<H> implements ChangeDetectorGroup<H> {
177
170
nextGroup._prev = prevGroup;
178
171
}
179
172
_parent = null ;
173
+ _prev = _next = null ;
174
+ _recordHead._prevRecord = null ;
175
+ _recordTail._nextRecord = null ;
176
+ _recordHead = _recordTail = null ;
180
177
assert (root._assertRecordsOk ());
181
178
}
182
179
@@ -281,7 +278,7 @@ class DirtyCheckingChangeDetector<H> extends DirtyCheckingChangeDetectorGroup<H>
281
278
return true ;
282
279
}
283
280
284
- DirtyCheckingRecord < H > collectChanges ({ EvalExceptionHandler exceptionHandler,
281
+ Iterator < Record < H > > collectChanges ({ EvalExceptionHandler exceptionHandler,
285
282
AvgStopwatch stopwatch}) {
286
283
if (stopwatch != null ) stopwatch.start ();
287
284
DirtyCheckingRecord changeHead = null ;
@@ -291,11 +288,11 @@ class DirtyCheckingChangeDetector<H> extends DirtyCheckingChangeDetectorGroup<H>
291
288
int count = 0 ;
292
289
while (current != null ) {
293
290
try {
294
- if (current.check () != null ) {
291
+ if (current.check ()) {
295
292
if (changeHead == null ) {
296
293
changeHead = changeTail = current;
297
294
} else {
298
- changeTail = changeTail.nextChange = current;
295
+ changeTail = changeTail._nextChange = current;
299
296
}
300
297
}
301
298
if (stopwatch != null ) count++ ;
@@ -308,16 +305,39 @@ class DirtyCheckingChangeDetector<H> extends DirtyCheckingChangeDetectorGroup<H>
308
305
}
309
306
current = current._nextRecord;
310
307
}
311
- if (changeTail != null ) changeTail.nextChange = null ;
308
+ if (changeTail != null ) changeTail._nextChange = null ;
312
309
if (stopwatch != null ) stopwatch..stop ()..increment (count);
313
- return changeHead;
310
+ return new _ChangeIterator ( changeHead) ;
314
311
}
315
312
316
313
void remove () {
317
314
throw new StateError ('Root ChangeDetector can not be removed' );
318
315
}
319
316
}
320
317
318
+ class _ChangeIterator <H > implements Iterator <Record <H >>{
319
+ DirtyCheckingRecord _current;
320
+ DirtyCheckingRecord _next;
321
+ DirtyCheckingRecord get current => _current;
322
+
323
+ _ChangeIterator (this ._next);
324
+
325
+ bool moveNext () {
326
+ _current = _next;
327
+ if (_next != null ) {
328
+ _next = _current._nextChange;
329
+ /*
330
+ * This is important to prevent memory leaks. If we don't reset then
331
+ * a record maybe pointing to a deleted change detector group and it
332
+ * will not release the reference until it fires again. So we have
333
+ * to be eager about releasing references.
334
+ */
335
+ _current._nextChange = null ;
336
+ }
337
+ return _current != null ;
338
+ }
339
+ }
340
+
321
341
/**
322
342
* [DirtyCheckingRecord] represents as single item to check. The heart of the
323
343
* [DirtyCheckingRecord] is a the [check] method which can read the
@@ -327,7 +347,7 @@ class DirtyCheckingChangeDetector<H> extends DirtyCheckingChangeDetectorGroup<H>
327
347
* removing efficient. [DirtyCheckingRecord] also has a [nextChange] field which
328
348
* creates a single linked list of all of the changes for efficient traversal.
329
349
*/
330
- class DirtyCheckingRecord <H > implements ChangeRecord <H >, WatchRecord <H > {
350
+ class DirtyCheckingRecord <H > implements Record <H >, WatchRecord <H > {
331
351
static const List <String > _MODE_NAMES =
332
352
const ['MARKER' , 'IDENT' , 'REFLECT' , 'GETTER' , 'MAP[]' , 'ITERABLE' , 'MAP' ];
333
353
static const int _MODE_MARKER_ = 0 ;
@@ -350,7 +370,7 @@ class DirtyCheckingRecord<H> implements ChangeRecord<H>, WatchRecord<H> {
350
370
var currentValue;
351
371
DirtyCheckingRecord <H > _nextRecord;
352
372
DirtyCheckingRecord <H > _prevRecord;
353
- ChangeRecord <H > nextChange ;
373
+ Record <H > _nextChange ;
354
374
var _object;
355
375
InstanceMirror _instanceMirror;
356
376
@@ -416,12 +436,12 @@ class DirtyCheckingRecord<H> implements ChangeRecord<H>, WatchRecord<H> {
416
436
}
417
437
}
418
438
419
- ChangeRecord < H > check () {
439
+ bool check () {
420
440
assert (_mode != null );
421
441
var current;
422
442
switch (_mode) {
423
443
case _MODE_MARKER_ :
424
- return null ;
444
+ return false ;
425
445
case _MODE_REFLECT_ :
426
446
current = _instanceMirror.getField (_symbol).reflectee;
427
447
break ;
@@ -435,9 +455,9 @@ class DirtyCheckingRecord<H> implements ChangeRecord<H>, WatchRecord<H> {
435
455
current = object;
436
456
break ;
437
457
case _MODE_MAP_ :
438
- return (currentValue as _MapChangeRecord )._check (object) ? this : null ;
458
+ return (currentValue as _MapChangeRecord )._check (object);
439
459
case _MODE_ITERABLE_ :
440
- return (currentValue as _CollectionChangeRecord )._check (object) ? this : null ;
460
+ return (currentValue as _CollectionChangeRecord )._check (object);
441
461
default :
442
462
assert (false );
443
463
}
@@ -454,10 +474,10 @@ class DirtyCheckingRecord<H> implements ChangeRecord<H>, WatchRecord<H> {
454
474
} else {
455
475
previousValue = last;
456
476
currentValue = current;
457
- return this ;
477
+ return true ;
458
478
}
459
479
}
460
- return null ;
480
+ return false ;
461
481
}
462
482
463
483
0 commit comments