// Copyright (c) 2014, 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. // VM-internalized implementation of a default-constructed LinkedHashMap. // Currently calls the runtime for most operations. class _InternalLinkedHashMap implements HashMap, LinkedHashMap { factory _InternalLinkedHashMap() native "LinkedHashMap_allocate"; int get length native "LinkedHashMap_getLength"; V operator [](K key) native "LinkedHashMap_lookUp"; void operator []=(K key, V value) native "LinkedHashMap_insertOrUpdate"; V remove(K key) native "LinkedHashMap_remove"; void clear() native "LinkedHashMap_clear"; bool containsKey(K key) native "LinkedHashMap_containsKey"; bool get isEmpty => length == 0; bool get isNotEmpty => !isEmpty; List _toArray() native "LinkedHashMap_toArray"; // "Modificaton marks" are tokens used to detect concurrent modification. // Considering only modifications (M) and iterator creation (I) events, e.g.: // M, M, M, I, I, M, I, M, M, I, I, I, M ... // a new mark is allocated at the start of each run of I's and cleared from // the map at the start of each run of M's. Iterators' moveNext check whether // the map's mark was changed or cleared since the iterator was created. // TODO(koda): Consider a counter instead. Object _getModMark(bool create) native "LinkedHashMap_getModMark"; void addAll(Map other) { other.forEach((K key, V value) { this[key] = value; }); } V putIfAbsent(K key, Function ifAbsent) { if (containsKey(key)) { return this[key]; } else { V value = ifAbsent(); this[key] = value; return value; } } bool containsValue(V value) { for (V v in values) { if (v == value) { return true; } } return false; } void forEach(Function f) { for (K key in keys) { f(key, this[key]); } } // The even-indexed entries of toArray are the keys. Iterable get keys => new _ListStepIterable(this, _getModMark(true), _toArray(), -2, 2); // The odd-indexed entries of toArray are the values. Iterable get values => new _ListStepIterable(this, _getModMark(true), _toArray(), -1, 2); String toString() => Maps.mapToString(this); } // Iterates over a list from a given offset and step size. class _ListStepIterable extends IterableBase { _InternalLinkedHashMap _map; Object _modMark; List _list; int _offset; int _step; _ListStepIterable(this._map, this._modMark, this._list, this._offset, this._step); Iterator get iterator => new _ListStepIterator(_map, _modMark, _list, _offset, _step); // TODO(koda): Should this check for concurrent modification? int get length => _map.length; bool get isEmpty => length == 0; bool get isNotEmpty => !isEmpty; } class _ListStepIterator implements Iterator { _InternalLinkedHashMap _map; Object _modMark; List _list; int _offset; int _step; _ListStepIterator(this._map, this._modMark, this._list, this._offset, this._step); bool moveNext() { if (_map._getModMark(false) != _modMark) { throw new ConcurrentModificationError(_map); } _offset += _step; return _offset < _list.length; } E get current { if (_offset < 0 || _offset >= _list.length) { return null; } return _list[_offset]; } }