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

Unified Diff: runtime/lib/expando_patch.dart

Issue 18826007: Reland r24563 and r24564 with fixes cumbersome API leading to leaks. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 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 | « no previous file | runtime/lib/object.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/lib/expando_patch.dart
===================================================================
--- runtime/lib/expando_patch.dart (revision 24817)
+++ runtime/lib/expando_patch.dart (working copy)
@@ -3,61 +3,135 @@
// BSD-style license that can be found in the LICENSE file.
patch class Expando<T> {
- /* patch */ Expando([this.name]) : _data = new List();
+ /* patch */ Expando([this.name])
+ : _data = new List(_minSize),
+ _used = 0;
+ static const _minSize = 8;
+ static final _deletedEntry = new _WeakProperty(null, null);
+
/* patch */ T operator[](Object object) {
_checkType(object);
- var doCompact = false;
- var result = null;
- for (int i = 0; i < _data.length; ++i) {
- var key = _data[i].key;
- if (identical(key, object)) {
- result = _data[i].value;
- break;
+
+ var mask = _size - 1;
+ var idx = object.hashCode & mask;
+ var wp = _data[idx];
+
+ while (wp != null) {
+ if (identical(wp.key, object)) {
+ return wp.value;
+ } else if (wp.key == null) {
+ // This entry has been cleared by the GC.
+ _data[idx] = _deletedEntry;
}
- if (key == null) {
- doCompact = true;
- _data[i] = null;
- }
+ idx = (idx + 1) & mask;
+ wp = _data[idx];
}
- if (doCompact) {
- _data = _data.where((e) => (e != null)).toList();
- }
- return result;
+
+ return null;
}
/* patch */ void operator[]=(Object object, T value) {
_checkType(object);
- var doCompact = false;
- int i = 0;
- for (; i < _data.length; ++i) {
- var key = _data[i].key;
- if (identical(key, object)) {
- break;
+
+ var mask = _size - 1;
+ var idx = object.hashCode & mask;
+ var empty_idx = -1;
+ var wp = _data[idx];
+
+ while (wp != null) {
+ if (identical(wp.key, object)) {
+ if (value != null) {
+ // Update the associated value.
+ wp.value = value;
+ } else {
+ // Mark the entry as deleted.
+ _data[idx] = _deletedEntry;
+ }
+ return;
+ } else if ((empty_idx < 0) && identical(wp, _deletedEntry)) {
+ empty_idx = idx; // Insert at this location if not found.
+ } else if (wp.key == null) {
+ // This entry has been cleared by the GC.
+ _data[idx] = _deletedEntry;
+ if (empty_idx < 0) {
+ empty_idx = idx; // Insert at this location if not found.
+ }
}
- if (key == null) {
- doCompact = true;
- _data[i] = null;
+ idx = (idx + 1) & mask;
+ wp = _data[idx];
+ }
+
+ if (value == null) {
+ // Not entering a null value. We just needed to make sure to clear an
+ // existing value if it existed.
+ return;
+ }
+
+ if (empty_idx >= 0) {
+ // We will be reusing the empty slot below.
+ _used--;
+ idx = empty_idx;
+ }
+
+ if (_used < _limit) {
+ _data[idx] = new _WeakProperty(object, value);
+ _used++;
+ return;
+ }
+
+ // Grow/reallocate if too many slots have been used.
+ _rehash();
+ this[object] = value; // Recursively add the value.
+ }
+
+ _rehash() {
+ // Determine the population count of the map to allocate an appropriately
+ // sized map below.
+ var count = 0;
+ var old_data = _data;
+ var len = old_data.length;
+ for (var i = 0; i < len; i++) {
+ var entry = old_data[i];
+ if ((entry != null) && (entry.key != null)) {
+ // Only count non-cleared entries.
+ count++;
}
}
- if (i != _data.length && value == null) {
- doCompact = true;
- _data[i] = null;
- } else if (i != _data.length) {
- _data[i].value = value;
- } else {
- _data.add(new _WeakProperty(object, value));
+
+ var new_size = _size;
+ if (count <= (new_size >> 2)) {
+ new_size = new_size >> 1;
+ } else if (count > (new_size >> 1)) {
+ new_size = new_size << 1;
}
- if (doCompact) {
- _data = _data.where((e) => (e != null)).toList();
+ new_size = (new_size < _minSize) ? _minSize : new_size;
+
+ // Reset the mappings to empty so that we can just add the existing
+ // valid entries.
+ _data = new List(new_size);
+ _used = 0;
+
+ for (var i = 0; i < old_data.length; i++) {
+ var entry = old_data[i];
+ if ((entry != null) && (entry.key != null)) {
+ this[entry.key] = entry.value;
+ }
}
}
static _checkType(object) {
- if (object == null || object is bool || object is num || object is String) {
+ if ((object == null) ||
+ (object is bool) ||
+ (object is num) ||
+ (object is String)) {
throw new ArgumentError(object);
}
}
+ get _size => _data.length;
+ get _limit => (3 * (_size ~/ 4));
+
List _data;
+ int _used; // Number of used (active and deleted) slots.
}
« no previous file with comments | « no previous file | runtime/lib/object.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698