Description
ES6 Maps and Sets can't be used directly for Dart LinkedHashMap and LinkedHashSet but they could be used in a way that is more efficient that the current implementation that uses Object.create(null)
dictionaries.
The current implementation uses three object dictionaries - one for Strings, one for small-ish non-negative integers and a final one for hash-buckets. The object dictionaries cannot be relied on to maintain insertion order, and even if they could, elements are spread between the String and small-integer dictionaries and the hash buckets, so the elements are maintained in a double-linked list.
An implementation based on ES6 Maps could use one or two maps. The first Map could be used for primitive objects (strings, numbers), and keys that don't override hashCode
and ==
, which includes a lot of useful types like enums. The second map would be used to map hashCode
values to buckets.
The reliable ES6 Map insertion order could be exploited by having two modes - a direct mode where only the first Map is active, and the map stores the values directly associated with the keys, and a linked mode more like the current implementation where the key-value pairs are in a double-linked list to maintain the insertion order between the first Map and the hash buckets. The implementation would transition from direct mode to linked mode only when an insertion key is presented that does not meet the criteria for using the first set.
In direct mode an Iterator like .keys.iterator
would use the JavaScript iterator. In linked mode the iterator would walk the double-linked list. it might be worthwhile to transition to linked mode for certain operations, for example, .keys.last
can't be done on a direct ES6 Map without iterating all the keys.
Detecting whether an object overrides hashCode
can probably be done with some special compiler support to compare the get$hashCode
property with that on Object
. If this turns out to be infeasible, direct mode could still be used for primitive values. This should still be substantially better when the keys are numbers.
ES6 Maps treat null
and undefined
as different keys so this would have to be handled by the implementation.