blob: 9ba5a72df527ede620641e974c3f5c7360ff763f [file] [log] [blame]
// Copyright (c) 2013, 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.
/// Note: the VM concatenates all patch files into a single patch file. This
/// file is the first patch in "dart:core" which contains all the imports
/// used by patches of that library. We plan to change this when we have a
/// shared front end and simply use parts.
import "dart:_internal" as internal show Symbol;
import "dart:_internal"
show
ClassID,
CodeUnits,
EfficientLengthIterable,
FixedLengthListBase,
IterableElementError,
ListIterator,
Lists,
POWERS_OF_TEN,
SubListIterable,
UnmodifiableListBase,
is64Bit,
makeFixedListUnmodifiable,
makeListFixedLength,
patch;
import "dart:async" show Completer, Future, Timer;
import "dart:collection"
show
HashMap,
IterableBase,
LinkedHashMap,
LinkedList,
LinkedListEntry,
ListBase,
Maps,
UnmodifiableMapView;
import "dart:convert" show ASCII, Encoding, JSON, LATIN1, UTF8;
import "dart:isolate" show Isolate;
import "dart:math" show Random;
import "dart:typed_data" show Uint8List, Int64List, Uint16List, Uint32List;
/// These are the additional parts of this patch library:
// part "array.dart";
// part "array_patch.dart";
// part "bigint.dart";
// part "bool_patch.dart";
// part "date_patch.dart";
// part "double.dart";
// part "double_patch.dart";
// part "errors_patch.dart";
// part "expando_patch.dart";
// part "function.dart";
// part "function_patch.dart";
// part "growable_array.dart";
// part "identical_patch.dart";
// part "immutable_map.dart";
// part "integers.dart";
// part "integers_patch.dart";
// part "invocation_mirror_patch.dart";
// part "lib_prefix.dart";
// part "map_patch.dart";
// part "null_patch.dart";
// part "object_patch.dart";
// part "regexp_patch.dart";
// part "stacktrace.dart";
// part "stopwatch_patch.dart";
// part "string_buffer_patch.dart";
// part "string_patch.dart";
// part "type_patch.dart";
// part "uri_patch.dart";
// part "weak_property.dart";
@patch
@erase
class num {
}
@patch
abstract class Iterable<E> {
@patch
bool contains(E element) {
for (E e in this) {
if (e == element) return true;
}
return false;
}
}
// The members of this class are cloned and added to each class that
// represents an enum type.
class _EnumHelper {
String _name;
String toString() => _name;
int get hashCode => _name.hashCode;
}
// _SyncIterable and _syncIterator are used by the compiler to
// implement sync* generator functions. A sync* generator allocates
// and returns a new _SyncIterable object.
typedef bool _SyncGeneratorCallback<T>(_SyncIterator<T> iterator);
class _SyncIterable<T> extends IterableBase<T> {
// _moveNextFn is the closurized body of the generator function.
final _SyncGeneratorCallback<T> _moveNextFn;
const _SyncIterable(this._moveNextFn);
Iterator<T> get iterator {
// Note: _Closure._clone returns _Closure which is not related to
// _SyncGeneratorCallback, which means we need explicit cast.
return new _SyncIterator<T>(
(_moveNextFn as _Closure)._clone() as _SyncGeneratorCallback<T>);
}
}
class _SyncIterator<T> implements Iterator<T> {
_SyncGeneratorCallback<T> _moveNextFn;
Iterator<T> _yieldEachIterator;
// These two fields are set by generated code for the yield and yield*
// statement.
T _current;
Iterable<T> _yieldEachIterable;
T get current =>
_yieldEachIterator != null ? _yieldEachIterator.current : _current;
_SyncIterator(this._moveNextFn);
bool moveNext() {
if (_moveNextFn == null) {
return false;
}
while (true) {
if (_yieldEachIterator != null) {
if (_yieldEachIterator.moveNext()) {
return true;
}
_yieldEachIterator = null;
}
// _moveNextFn() will update the values of _yieldEachIterable
// and _current.
if (!_moveNextFn(this)) {
_moveNextFn = null;
_current = null;
return false;
}
if (_yieldEachIterable != null) {
// Spec mandates: it is a dynamic error if the class of [the object
// returned by yield*] does not implement Iterable.
_yieldEachIterator = _yieldEachIterable.iterator;
_yieldEachIterable = null;
_current = null;
continue;
}
return true;
}
}
}
@patch
class StackTrace {
@patch
static StackTrace get current native "StackTrace_current";
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
class _List<E> extends FixedLengthListBase<E> {
factory _List(int length) native "List_allocate";
E operator [](int index) native "List_getIndexed";
void operator []=(int index, E value) native "List_setIndexed";
int get length native "List_getLength";
List _slice(int start, int count, bool needsTypeArgument) {
if (count <= 64) {
final result = needsTypeArgument ? new _List<E>(count) : new _List(count);
for (int i = 0; i < result.length; i++) {
result[i] = this[start + i];
}
return result;
} else {
return _sliceInternal(start, count, needsTypeArgument);
}
}
List _sliceInternal(int start, int count, bool needsTypeArgument)
native "List_slice";
// List interface.
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
if (start < 0 || start > this.length) {
throw new RangeError.range(start, 0, this.length);
}
if (end < start || end > this.length) {
throw new RangeError.range(end, start, this.length);
}
int length = end - start;
if (length == 0) return;
if (identical(this, iterable)) {
Lists.copy(this, skipCount, this, start, length);
} else if (ClassID.getID(iterable) == ClassID.cidArray) {
final _List<E> iterableAsList = iterable;
Lists.copy(iterableAsList, skipCount, this, start, length);
} else if (iterable is List<E>) {
Lists.copy(iterable, skipCount, this, start, length);
} else {
Iterator it = iterable.iterator;
while (skipCount > 0) {
if (!it.moveNext()) return;
skipCount--;
}
for (int i = start; i < end; i++) {
if (!it.moveNext()) return;
this[i] = it.current;
}
}
}
List<E> sublist(int start, [int end]) {
end = RangeError.checkValidRange(start, end, this.length);
int length = end - start;
if (length == 0) return <E>[];
var result = new _GrowableList<E>.withData(_slice(start, length, false));
result._setLength(length);
return result;
}
// Iterable interface.
void forEach(f(E element)) {
final length = this.length;
for (int i = 0; i < length; i++) {
f(this[i]);
}
}
Iterator<E> get iterator {
return new _FixedSizeArrayIterator<E>(this);
}
E get first {
if (length > 0) return this[0];
throw IterableElementError.noElement();
}
E get last {
if (length > 0) return this[length - 1];
throw IterableElementError.noElement();
}
E get single {
if (length == 1) return this[0];
if (length == 0) throw IterableElementError.noElement();
throw IterableElementError.tooMany();
}
List<E> toList({bool growable: true}) {
var length = this.length;
if (length > 0) {
var result = _slice(0, length, !growable);
if (growable) {
result = new _GrowableList<E>.withData(result).._setLength(length);
}
return result;
}
// _GrowableList.withData must not be called with empty list.
return growable ? <E>[] : new List<E>(0);
}
}
// This is essentially the same class as _List, but it does not
// permit any modification of array elements from Dart code. We use
// this class for arrays constructed from Dart array literals.
// TODO(hausner): We should consider the trade-offs between two
// classes (and inline cache misses) versus a field in the native
// implementation (checks when modifying). We should keep watching
// the inline cache misses.
class _ImmutableList<E> extends UnmodifiableListBase<E> {
factory _ImmutableList._uninstantiable() {
throw new UnsupportedError(
"ImmutableArray can only be allocated by the VM");
}
factory _ImmutableList._from(List from, int offset, int length)
native "ImmutableList_from";
E operator [](int index) native "List_getIndexed";
int get length native "List_getLength";
List<E> sublist(int start, [int end]) {
end = RangeError.checkValidRange(start, end, this.length);
int length = end - start;
if (length == 0) return <E>[];
List list = new _List(length);
for (int i = 0; i < length; i++) {
list[i] = this[start + i];
}
var result = new _GrowableList<E>.withData(list);
result._setLength(length);
return result;
}
// Collection interface.
void forEach(f(E element)) {
final length = this.length;
for (int i = 0; i < length; i++) {
f(this[i]);
}
}
Iterator<E> get iterator {
return new _FixedSizeArrayIterator<E>(this);
}
E get first {
if (length > 0) return this[0];
throw IterableElementError.noElement();
}
E get last {
if (length > 0) return this[length - 1];
throw IterableElementError.noElement();
}
E get single {
if (length == 1) return this[0];
if (length == 0) throw IterableElementError.noElement();
throw IterableElementError.tooMany();
}
List<E> toList({bool growable: true}) {
var length = this.length;
if (length > 0) {
List list = growable ? new _List(length) : new _List<E>(length);
for (int i = 0; i < length; i++) {
list[i] = this[i];
}
if (!growable) return list;
var result = new _GrowableList<E>.withData(list);
result._setLength(length);
return result;
}
return growable ? <E>[] : new _List<E>(0);
}
}
// Iterator for arrays with fixed size.
class _FixedSizeArrayIterator<E> implements Iterator<E> {
final List<E> _array;
final int _length; // Cache array length for faster access.
int _index;
E _current;
_FixedSizeArrayIterator(List array)
: _array = array,
_length = array.length,
_index = 0 {
assert(array is _List || array is _ImmutableList);
}
E get current => _current;
bool moveNext() {
if (_index >= _length) {
_current = null;
return false;
}
_current = _array[_index];
_index++;
return true;
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
// The _GrowableArrayMarker class is used to signal to the List() factory
// whether a parameter was passed.
class _GrowableArrayMarker implements int {
const _GrowableArrayMarker();
}
// TODO(vipunen): We might want to do this differently.
const int _GROWABLE_ARRAY_MARKER = -42;
@patch
class List<E> {
@patch
factory List([int length]) = List<E>._internal;
@patch
factory List.filled(int length, E fill, {bool growable: false}) {
// All error handling on the length parameter is done at the implementation
// of new _List.
var result = growable ? new _GrowableList<E>(length) : new _List<E>(length);
if (fill != null) {
for (int i = 0; i < length; i++) {
result[i] = fill;
}
}
return result;
}
@patch
factory List.from(Iterable elements, {bool growable: true}) {
if (elements is EfficientLengthIterable) {
int length = elements.length;
var list = growable ? new _GrowableList<E>(length) : new _List<E>(length);
if (length > 0) {
// Avoid creating iterator unless necessary.
int i = 0;
for (var element in elements) {
list[i++] = element;
}
}
return list;
}
List<E> list = new _GrowableList<E>(0);
for (E e in elements) {
list.add(e);
}
if (growable) return list;
return makeListFixedLength(list);
}
@patch
factory List.unmodifiable(Iterable elements) {
final result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
}
// The List factory constructor redirects to this one so that we can change
// length's default value from the one in the SDK's implementation.
factory List._internal([int length = _GROWABLE_ARRAY_MARKER]) {
if (length == _GROWABLE_ARRAY_MARKER) {
return new _GrowableList<E>(0);
}
// All error handling on the length parameter is done at the implementation
// of new _List.
return new _List<E>(length);
}
// Factory constructing a mutable List from a parser generated List literal.
// [elements] contains elements that are already type checked.
factory List._fromLiteral(List elements) {
if (elements.isEmpty) {
return new _GrowableList<E>(0);
}
var result = new _GrowableList<E>.withData(elements);
result._setLength(elements.length);
return result;
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
@patch
class bool {
@patch
const factory bool.fromEnvironment(String name, {bool defaultValue: false})
native "Bool_fromEnvironment";
@patch
int get hashCode => this ? 1231 : 1237;
int get _identityHashCode => this ? 1231 : 1237;
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
// VM implementation of DateTime.
@patch
class DateTime {
// Natives.
// The natives have been moved up here to work around Issue 10401.
static int _getCurrentMicros() native "DateTime_currentTimeMicros";
static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch)
native "DateTime_timeZoneName";
static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
native "DateTime_timeZoneOffsetInSeconds";
static int _localTimeZoneAdjustmentInSeconds()
native "DateTime_localTimeZoneAdjustmentInSeconds";
static const _MICROSECOND_INDEX = 0;
static const _MILLISECOND_INDEX = 1;
static const _SECOND_INDEX = 2;
static const _MINUTE_INDEX = 3;
static const _HOUR_INDEX = 4;
static const _DAY_INDEX = 5;
static const _WEEKDAY_INDEX = 6;
static const _MONTH_INDEX = 7;
static const _YEAR_INDEX = 8;
List __parts;
@patch
DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
{bool isUtc: false})
: this._withValue(
millisecondsSinceEpoch * Duration.MICROSECONDS_PER_MILLISECOND,
isUtc: isUtc);
@patch
DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
{bool isUtc: false})
: this._withValue(microsecondsSinceEpoch, isUtc: isUtc);
@patch
DateTime._internal(int year, int month, int day, int hour, int minute,
int second, int millisecond, int microsecond, bool isUtc)
: this.isUtc = isUtc,
this._value = _brokenDownDateToValue(year, month, day, hour, minute,
second, millisecond, microsecond, isUtc) {
if (_value == null) throw new ArgumentError();
if (isUtc == null) throw new ArgumentError();
}
@patch
DateTime._now()
: isUtc = false,
_value = _getCurrentMicros() {}
@patch
String get timeZoneName {
if (isUtc) return "UTC";
return _timeZoneName(microsecondsSinceEpoch);
}
@patch
Duration get timeZoneOffset {
if (isUtc) return new Duration();
int offsetInSeconds = _timeZoneOffsetInSeconds(microsecondsSinceEpoch);
return new Duration(seconds: offsetInSeconds);
}
/** The first list contains the days until each month in non-leap years. The
* second list contains the days in leap years. */
static const List<List<int>> _DAYS_UNTIL_MONTH = const [
const [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
const [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
];
static List _computeUpperPart(int localMicros) {
const int DAYS_IN_4_YEARS = 4 * 365 + 1;
const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
const int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1;
const int DAYS_1970_TO_2000 = 30 * 365 + 7;
const int DAYS_OFFSET =
1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS - DAYS_1970_TO_2000;
const int YEARS_OFFSET = 400000;
int resultYear = 0;
int resultMonth = 0;
int resultDay = 0;
// Always round down.
final int daysSince1970 =
_flooredDivision(localMicros, Duration.MICROSECONDS_PER_DAY);
int days = daysSince1970;
days += DAYS_OFFSET;
resultYear = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET;
days = days.remainder(DAYS_IN_400_YEARS);
days--;
int yd1 = days ~/ DAYS_IN_100_YEARS;
days = days.remainder(DAYS_IN_100_YEARS);
resultYear += 100 * yd1;
days++;
int yd2 = days ~/ DAYS_IN_4_YEARS;
days = days.remainder(DAYS_IN_4_YEARS);
resultYear += 4 * yd2;
days--;
int yd3 = days ~/ 365;
days = days.remainder(365);
resultYear += yd3;
bool isLeap = (yd1 == 0 || yd2 != 0) && yd3 == 0;
if (isLeap) days++;
List<int> daysUntilMonth = _DAYS_UNTIL_MONTH[isLeap ? 1 : 0];
for (resultMonth = 12;
daysUntilMonth[resultMonth - 1] > days;
resultMonth--) {
// Do nothing.
}
resultDay = days - daysUntilMonth[resultMonth - 1] + 1;
int resultMicrosecond = localMicros % Duration.MICROSECONDS_PER_MILLISECOND;
int resultMillisecond =
_flooredDivision(localMicros, Duration.MICROSECONDS_PER_MILLISECOND) %
Duration.MILLISECONDS_PER_SECOND;
int resultSecond =
_flooredDivision(localMicros, Duration.MICROSECONDS_PER_SECOND) %
Duration.SECONDS_PER_MINUTE;
int resultMinute =
_flooredDivision(localMicros, Duration.MICROSECONDS_PER_MINUTE);
resultMinute %= Duration.MINUTES_PER_HOUR;
int resultHour =
_flooredDivision(localMicros, Duration.MICROSECONDS_PER_HOUR);
resultHour %= Duration.HOURS_PER_DAY;
// In accordance with ISO 8601 a week
// starts with Monday. Monday has the value 1 up to Sunday with 7.
// 1970-1-1 was a Thursday.
int resultWeekday = ((daysSince1970 + DateTime.THURSDAY - DateTime.MONDAY) %
DateTime.DAYS_PER_WEEK) +
DateTime.MONDAY;
List list = new List(_YEAR_INDEX + 1);
list[_MICROSECOND_INDEX] = resultMicrosecond;
list[_MILLISECOND_INDEX] = resultMillisecond;
list[_SECOND_INDEX] = resultSecond;
list[_MINUTE_INDEX] = resultMinute;
list[_HOUR_INDEX] = resultHour;
list[_DAY_INDEX] = resultDay;
list[_WEEKDAY_INDEX] = resultWeekday;
list[_MONTH_INDEX] = resultMonth;
list[_YEAR_INDEX] = resultYear;
return list;
}
get _parts {
if (__parts == null) {
__parts = _computeUpperPart(_localDateInUtcMicros);
}
return __parts;
}
@patch
DateTime add(Duration duration) {
return new DateTime._withValue(_value + duration.inMicroseconds,
isUtc: isUtc);
}
@patch
DateTime subtract(Duration duration) {
return new DateTime._withValue(_value - duration.inMicroseconds,
isUtc: isUtc);
}
@patch
Duration difference(DateTime other) {
return new Duration(microseconds: _value - other._value);
}
@patch
int get millisecondsSinceEpoch =>
_value ~/ Duration.MICROSECONDS_PER_MILLISECOND;
@patch
int get microsecondsSinceEpoch => _value;
@patch
int get microsecond => _parts[_MICROSECOND_INDEX];
@patch
int get millisecond => _parts[_MILLISECOND_INDEX];
@patch
int get second => _parts[_SECOND_INDEX];
@patch
int get minute => _parts[_MINUTE_INDEX];
@patch
int get hour => _parts[_HOUR_INDEX];
@patch
int get day => _parts[_DAY_INDEX];
@patch
int get weekday => _parts[_WEEKDAY_INDEX];
@patch
int get month => _parts[_MONTH_INDEX];
@patch
int get year => _parts[_YEAR_INDEX];
/**
* Returns the amount of microseconds in UTC that represent the same values
* as [this].
*
* Say `t` is the result of this function, then
* * `this.year == new DateTime.fromMicrosecondsSinceEpoch(t, true).year`,
* * `this.month == new DateTime.fromMicrosecondsSinceEpoch(t, true).month`,
* * `this.day == new DateTime.fromMicrosecondsSinceEpoch(t, true).day`,
* * `this.hour == new DateTime.fromMicrosecondsSinceEpoch(t, true).hour`,
* * ...
*
* Daylight savings is computed as if the date was computed in [1970..2037].
* If [this] lies outside this range then it is a year with similar
* properties (leap year, weekdays) is used instead.
*/
int get _localDateInUtcMicros {
int micros = _value;
if (isUtc) return micros;
int offset =
_timeZoneOffsetInSeconds(micros) * Duration.MICROSECONDS_PER_SECOND;
return micros + offset;
}
static int _flooredDivision(int a, int b) {
return (a - (a < 0 ? b - 1 : 0)) ~/ b;
}
// Returns the days since 1970 for the start of the given [year].
// [year] may be before epoch.
static int _dayFromYear(int year) {
return 365 * (year - 1970) +
_flooredDivision(year - 1969, 4) -
_flooredDivision(year - 1901, 100) +
_flooredDivision(year - 1601, 400);
}
static bool _isLeapYear(y) {
// (y % 16 == 0) matches multiples of 400, and is faster than % 400.
return (y % 4 == 0) && ((y % 16 == 0) || (y % 100 != 0));
}
/// Converts the given broken down date to microseconds.
@patch
static int _brokenDownDateToValue(int year, int month, int day, int hour,
int minute, int second, int millisecond, int microsecond, bool isUtc) {
// Simplify calculations by working with zero-based month.
--month;
// Deal with under and overflow.
if (month >= 12) {
year += month ~/ 12;
month = month % 12;
} else if (month < 0) {
int realMonth = month % 12;
year += (month - realMonth) ~/ 12;
month = realMonth;
}
// First compute the seconds in UTC, independent of the [isUtc] flag. If
// necessary we will add the time-zone offset later on.
int days = day - 1;
days += _DAYS_UNTIL_MONTH[_isLeapYear(year) ? 1 : 0][month];
days += _dayFromYear(year);
int microsecondsSinceEpoch = days * Duration.MICROSECONDS_PER_DAY +
hour * Duration.MICROSECONDS_PER_HOUR +
minute * Duration.MICROSECONDS_PER_MINUTE +
second * Duration.MICROSECONDS_PER_SECOND +
millisecond * Duration.MICROSECONDS_PER_MILLISECOND +
microsecond;
// Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
// the valid range we do a preliminary test that weeds out values that can
// not become valid even with timezone adjustments.
// The timezone adjustment is always less than a day, so adding a security
// margin of one day should be enough.
if (microsecondsSinceEpoch.abs() >
_MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) {
return null;
}
if (!isUtc) {
// Note that we can't literally follow the ECMAScript spec (which this
// code is based on), because it leads to incorrect computations at
// the DST transition points.
//
// See V8's comment here:
// https://github.com/v8/v8/blob/089dd7d2447d6eaf57c8ba6d8f37957f3a269777/src/date.h#L118
// We need to remove the local timezone adjustment before asking for the
// correct zone offset.
int adjustment = _localTimeZoneAdjustmentInSeconds() *
Duration.MICROSECONDS_PER_SECOND;
// The adjustment is independent of the actual date and of the daylight
// saving time. It is positive east of the Prime Meridian and negative
// west of it, e.g. -28800 sec for America/Los_Angeles timezone.
// We remove one hour to ensure that we have the correct offset at
// DST transitioning points. This is a temporary solution and only
// correct in timezones that shift for exactly one hour.
adjustment += Duration.MICROSECONDS_PER_HOUR;
int zoneOffset =
_timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment);
// The zoneOffset depends on the actual date and reflects any daylight
// saving time and/or historical deviation relative to UTC time.
// It is positive east of the Prime Meridian and negative west of it,
// e.g. -25200 sec for America/Los_Angeles timezone during DST.
microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND;
// The resulting microsecondsSinceEpoch value is therefore the calculated
// UTC value decreased by a (positive if east of GMT) timezone adjustment
// and decreased by typically one hour if DST is in effect.
}
if (microsecondsSinceEpoch.abs() >
_MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) {
return null;
}
return microsecondsSinceEpoch;
}
static int _weekDay(y) {
// 1/1/1970 was a Thursday.
return (_dayFromYear(y) + 4) % 7;
}
/**
* Returns a year in the range 2008-2035 matching
* * leap year, and
* * week day of first day.
*
* Leap seconds are ignored.
* Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
*/
static int _equivalentYear(int year) {
// Returns year y so that _weekDay(y) == _weekDay(year).
// _weekDay returns the week day (in range 0 - 6).
// 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
// 1/1/1967 was a Sunday (i.e. weekday 0).
// Without leap years a subsequent year has a week day + 1 (for example
// 1/1/1968 was a Monday). With leap-years it jumps over one week day
// (e.g. 1/1/1957 was a Tuesday).
// After 12 years the weekdays have advanced by 12 days + 3 leap days =
// 15 days. 15 % 7 = 1. So after 12 years the week day has always
// (now independently of leap-years) advanced by one.
// weekDay * 12 gives thus a year starting with the wanted weekDay.
int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12);
// Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
// leap years, 7 for the weekdays).
// Find the year in the range 2008..2037 that is equivalent mod 28.
return 2008 + (recentYear - 2008) % 28;
}
/**
* Returns the UTC year for the corresponding [secondsSinceEpoch].
* It is relatively fast for values in the range 0 to year 2098.
*
* Code is adapted from V8.
*/
static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) {
const int DAYS_IN_4_YEARS = 4 * 365 + 1;
const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
const int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY;
if (days > 0 && days < DAYS_YEAR_2098) {
// According to V8 this fast case works for dates from 1970 to 2099.
return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
}
int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND;
return _computeUpperPart(micros)[_YEAR_INDEX];
}
/**
* Returns a date in seconds that is equivalent to the given
* date in microseconds [microsecondsSinceEpoch]. An equivalent
* date has the same fields (`month`, `day`, etc.) as the given
* date, but the `year` is in the range [1901..2038].
*
* * The time since the beginning of the year is the same.
* * If the given date is in a leap year then the returned
* seconds are in a leap year, too.
* * The week day of given date is the same as the one for the
* returned date.
*/
static int _equivalentSeconds(int microsecondsSinceEpoch) {
const int CUT_OFF_SECONDS = 0x7FFFFFFF;
int secondsSinceEpoch = _flooredDivision(
microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
if (secondsSinceEpoch.abs() > CUT_OFF_SECONDS) {
int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch);
int days = _dayFromYear(year);
int equivalentYear = _equivalentYear(year);
int equivalentDays = _dayFromYear(equivalentYear);
int diffDays = equivalentDays - days;
secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY;
}
return secondsSinceEpoch;
}
static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) {
int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch);
return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds);
}
static String _timeZoneName(int microsecondsSinceEpoch) {
int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch);
return _timeZoneNameForClampedSeconds(equivalentSeconds);
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
//class _Double implements double {
//}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
// VM implementation of double.
@patch
@patchExtends
class double {
int get hashCode native "Double_hashCode";
int get _identityHashCode native "Double_hashCode";
@patch double operator +(double other) native "Double_add";
@patch double operator -(double other) native "Double_sub";
@patch double operator *(double other) native "Double_mul";
@patch int operator ~/(double other) native "Double_trunc_div";
@patch double operator /(double other) native "Double_div";
@patch double operator %(double other) native "Double_modulo";
@patch double remainder(double other) native "Double_remainder";
@patch double operator -() native "Double_flipSignBit";
bool operator ==(double other) native "Double_equal";
bool operator >(double other) native "Double_greaterThan";
bool operator <(double other) {
return other > this;
}
bool operator >=(double other) {
return (this == other) || (this > other);
}
bool operator <=(double other) {
return (this == other) || (this < other);
}
bool get isNegative native "Double_getIsNegative";
bool get isInfinite native "Double_getIsInfinite";
bool get isNaN native "Double_getIsNaN";
bool get isFinite => !isInfinite && !isNaN; // Can be optimized.
@patch
double abs() {
// Handle negative 0.0.
if (this == 0.0) return 0.0;
return this < 0.0 ? -this : this;
}
@patch
double get sign {
if (this > 0.0) return 1.0;
if (this < 0.0) return -1.0;
return this; // +/-0.0 or NaN.
}
@patch int round() => roundToDouble().toInt();
@patch int floor() => floorToDouble().toInt();
@patch int ceil() => ceilToDouble().toInt();
@patch int truncate() => truncateToDouble().toInt();
@patch double roundToDouble() native "Double_round";
@patch double floorToDouble() native "Double_floor";
@patch double ceilToDouble() native "Double_ceil";
@patch double truncateToDouble() native "Double_truncate";
double clamp(double lowerLimit, double upperLimit) {
if (lowerLimit.compareTo(upperLimit) > 0) {
throw new ArgumentError(lowerLimit);
}
if (lowerLimit.isNaN) return lowerLimit;
if (this.compareTo(lowerLimit) < 0) return lowerLimit;
if (this.compareTo(upperLimit) > 0) return upperLimit;
return this;
}
int toInt() native "Double_toInt";
double toDouble() {
return this;
}
static const int CACHE_SIZE_LOG2 = 3;
static const int CACHE_LENGTH = 1 << (CACHE_SIZE_LOG2 + 1);
static const int CACHE_MASK = CACHE_LENGTH - 1;
// Each key (double) followed by its toString result.
static final List _cache = new List(CACHE_LENGTH);
static int _cacheEvictIndex = 0;
String _toString() native "Double_toString";
@patch
String toString() {
if (0.0 == this) {
return "0.0";
}
return _toString();
}
String toStringAsFixed(int fractionDigits) {
// See ECMAScript-262, 15.7.4.5 for details.
if (fractionDigits is! int) {
throw new ArgumentError.value(
fractionDigits, "fractionDigits", "not an integer");
}
// Step 2.
if (fractionDigits < 0 || fractionDigits > 20) {
throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
}
// Step 3.
double x = this;
// Step 4.
if (isNaN) return "NaN";
// Step 5 and 6 skipped. Will be dealt with by native function.
// Step 7.
if (x >= 1e21 || x <= -1e21) {
return x.toString();
}
return _toStringAsFixed(fractionDigits);
}
String _toStringAsFixed(int fractionDigits) native "Double_toStringAsFixed";
String toStringAsExponential([int fractionDigits]) {
// See ECMAScript-262, 15.7.4.6 for details.
// The EcmaScript specification checks for NaN and Infinity before looking
// at the fractionDigits. In Dart we are consistent with toStringAsFixed and
// look at the fractionDigits first.
// Step 7.
if (fractionDigits != null) {
if (fractionDigits is! int) {
throw new ArgumentError.value(
fractionDigits, "fractionDigits", "not an integer");
}
if (fractionDigits < 0 || fractionDigits > 20) {
throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
}
}
if (isNaN) return "NaN";
if (this == double.INFINITY) return "Infinity";
if (this == -double.INFINITY) return "-Infinity";
// The dart function prints the shortest representation when fractionDigits
// equals null. The native function wants -1 instead.
fractionDigits = (fractionDigits == null) ? -1 : fractionDigits;
return _toStringAsExponential(fractionDigits);
}
String _toStringAsExponential(int fractionDigits)
native "Double_toStringAsExponential";
String toStringAsPrecision(int precision) {
// See ECMAScript-262, 15.7.4.7 for details.
// The EcmaScript specification checks for NaN and Infinity before looking
// at the fractionDigits. In Dart we are consistent with toStringAsFixed and
// look at the fractionDigits first.
if (precision is! int) {
throw new ArgumentError.value(precision, "precision", "not an integer");
}
// Step 8.
if (precision < 1 || precision > 21) {
throw new RangeError.range(precision, 1, 21, "precision");
}
if (isNaN) return "NaN";
if (this == double.INFINITY) return "Infinity";
if (this == -double.INFINITY) return "-Infinity";
return _toStringAsPrecision(precision);
}
String _toStringAsPrecision(int fractionDigits)
native "Double_toStringAsPrecision";
// Order is: NaN > Infinity > ... > 0.0 > -0.0 > ... > -Infinity.
int compareTo(double other) {
const int EQUAL = 0, LESS = -1, GREATER = 1;
if (this < other) {
return LESS;
} else if (this > other) {
return GREATER;
} else if (this == other) {
if (this == 0.0) {
bool thisIsNegative = isNegative;
bool otherIsNegative = other.isNegative;
if (thisIsNegative == otherIsNegative) {
return EQUAL;
}
return thisIsNegative ? LESS : GREATER;
} else {
return EQUAL;
}
} else if (isNaN) {
return other.isNaN ? EQUAL : GREATER;
} else {
// Other is NaN.
return LESS;
}
}
static double _nativeParse(String str, int start, int end)
native "Double_parse";
static double _tryParseDouble(var str, var start, var end) {
assert(start < end);
const int _DOT = 0x2e; // '.'
const int _ZERO = 0x30; // '0'
const int _MINUS = 0x2d; // '-'
const int _N = 0x4e; // 'N'
const int _a = 0x61; // 'a'
const int _I = 0x49; // 'I'
const int _e = 0x65; // 'e'
int exponent = 0;
// Set to non-zero if a digit is seen. Avoids accepting ".".
bool digitsSeen = false;
// Added to exponent for each digit. Set to -1 when seeing '.'.
int exponentDelta = 0;
double doubleValue = 0.0;
double sign = 1.0;
int firstChar = str.codeUnitAt(start);
if (firstChar == _MINUS) {
sign = -1.0;
start++;
if (start == end) return null;
firstChar = str.codeUnitAt(start);
}
if (firstChar == _I) {
if (end == start + 8 && str.startsWith("nfinity", start + 1)) {
return sign * double.INFINITY;
}
return null;
}
if (firstChar == _N) {
if (end == start + 3 &&
str.codeUnitAt(start + 1) == _a &&
str.codeUnitAt(start + 2) == _N) {
return double.NAN;
}
return null;
}
int firstDigit = firstChar ^ _ZERO;
if (firstDigit <= 9) {
start++;
doubleValue = firstDigit.toDouble();
digitsSeen = true;
}
for (int i = start; i < end; i++) {
int c = str.codeUnitAt(i);
int digit = c ^ _ZERO; // '0'-'9' characters are now 0-9 integers.
if (digit <= 9) {
doubleValue = 10.0 * doubleValue + digit;
// Doubles at or above this value (2**53) might have lost precission.
const double MAX_EXACT_DOUBLE = 9007199254740992.0;
if (doubleValue >= MAX_EXACT_DOUBLE) return null;
exponent += exponentDelta;
digitsSeen = true;
} else if (c == _DOT && exponentDelta == 0) {
exponentDelta = -1;
} else if ((c | 0x20) == _e) {
i++;
if (i == end) return null;
// int._tryParseSmi treats its end argument as inclusive.
int expPart = int._tryParseSmi(str, i, end - 1);
if (expPart == null) return null;
exponent += expPart;
break;
} else {
return null;
}
}
if (!digitsSeen) return null; // No digits.
if (exponent == 0) return sign * doubleValue;
const P10 = POWERS_OF_TEN; // From shared library
if (exponent < 0) {
int negExponent = -exponent;
if (negExponent >= P10.length) return null;
return sign * (doubleValue / P10[negExponent]);
}
if (exponent >= P10.length) return null;
return sign * (doubleValue * P10[exponent]);
}
static double _parse(var str) {
int len = str.length;
int start = str._firstNonWhitespace();
if (start == len) return null; // All whitespace.
int end = str._lastNonWhitespace() + 1;
assert(start < end);
var result = _tryParseDouble(str, start, end);
if (result != null) return result;
return _nativeParse(str, start, end);
}
@patch
static double parse(String source, [double onError(String source)]) {
var result = _parse(source);
if (result == null) {
if (onError == null) throw new FormatException("Invalid double", source);
return onError(source);
}
return result;
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
@patch
class Error {
@patch
static String _objectToString(Object object) {
return Object._toString(object);
}
@patch
static String _stringToSafeString(String string) {
return string;
}
@patch
StackTrace get stackTrace => _stackTrace;
StackTrace _stackTrace;
}
class _AssertionError extends Error implements AssertionError {
_AssertionError._create(
this._failedAssertion, this._url, this._line, this._column, this.message);
// AssertionError_throwNew in errors.cc fishes the assertion source code
// out of the script. It expects a Dart stack frame from class
// _AssertionError. Thus we need a Dart stub that calls the native code.
static _throwNew(int assertionStart, int assertionEnd, Object message) {
_doThrowNew(assertionStart, assertionEnd, message);
}
static _doThrowNew(int assertionStart, int assertionEnd, Object message)
native "AssertionError_throwNew";
static _evaluateAssertion(condition) {
if (identical(condition, true) || identical(condition, false)) {
return condition;
}
if (condition is _Closure) {
return condition();
}
if (condition is Function) {
condition = condition();
}
return condition;
}
String get _messageString {
if (message == null) return "is not true.";
if (message is String) return message;
return Error.safeToString(message);
}
String toString() {
if (_url == null) {
if (message == null) return _failedAssertion?.trim();
return "'${_failedAssertion?.trim()}': $_messageString";
}
var columnInfo = "";
if (_column > 0) {
// Only add column information if it is valid.
columnInfo = " pos $_column";
}
return "'$_url': Failed assertion: line $_line$columnInfo: "
"'$_failedAssertion': $_messageString";
}
final String _failedAssertion;
final String _url;
final int _line;
final int _column;
final Object message;
}
class _TypeError extends _AssertionError implements TypeError {
_TypeError._create(String url, int line, int column, String errorMsg)
: super._create("is assignable", url, line, column, errorMsg);
static _throwNew(int location, Object src_value, _Type dst_type,
String dst_name, String bound_error_msg) native "TypeError_throwNew";
static _throwNewIfNotLoaded(
_LibraryPrefix prefix,
int location,
Object src_value,
_Type dst_type,
String dst_name,
String bound_error_msg) {
if (!prefix.isLoaded()) {
_throwNew(location, src_value, dst_type, dst_name, bound_error_msg);
}
}
String toString() => super.message;
}
class _CastError extends Error implements CastError {
_CastError._create(this._url, this._line, this._column, this._errorMsg);
// A CastError is allocated by TypeError._throwNew() when dst_name equals
// Symbols::InTypeCast().
String toString() => _errorMsg;
// Fields _url, _line, and _column are only used for debugging purposes.
final String _url;
final int _line;
final int _column;
final String _errorMsg;
}
@patch
class FallThroughError {
@patch
FallThroughError._create(String url, int line)
: _url = url,
_line = line;
static _throwNew(int case_clause_pos) native "FallThroughError_throwNew";
@patch
String toString() {
return "'$_url': Switch case fall-through at line $_line.";
}
// These new fields cannot be declared final, because a constructor exists
// in the original version of this patched class.
String _url;
int _line;
}
class _InternalError {
const _InternalError(this._msg);
String toString() => "InternalError: '${_msg}'";
final String _msg;
}
@patch
class UnsupportedError {
static _throwNew(String msg) {
throw new UnsupportedError(msg);
}
}
@patch
class CyclicInitializationError {
static _throwNew(String variableName) {
throw new CyclicInitializationError(variableName);
}
}
@patch
class AbstractClassInstantiationError {
AbstractClassInstantiationError._create(
this._className, this._url, this._line);
static _throwNew(int case_clause_pos, String className)
native "AbstractClassInstantiationError_throwNew";
@patch
String toString() {
return "Cannot instantiate abstract class $_className: "
"_url '$_url' line $_line";
}
// These new fields cannot be declared final, because a constructor exists
// in the original version of this patched class.
String _url;
int _line;
}
@patch
class NoSuchMethodError {
// TODO(regis): Move _receiver declaration here:
// final Object _receiver;
final _InvocationMirror _invocation;
@patch
NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
: _receiver = receiver,
_invocation = invocation as _InvocationMirror;
// The compiler emits a call to _throwNew when it cannot resolve a static
// method at compile time. The receiver is actually the literal class of the
// unresolved method.
static void _throwNew(Object receiver, String memberName, int invocation_type,
Object typeArguments, List arguments, List argumentNames) {
throw new NoSuchMethodError._withType(receiver, memberName, invocation_type,
typeArguments, arguments, argumentNames);
}
static void _throwNewIfNotLoaded(
_LibraryPrefix prefix,
Object receiver,
String memberName,
int invocation_type,
Object typeArguments,
List arguments,
List argumentNames) {
if (!prefix.isLoaded()) {
_throwNew(receiver, memberName, invocation_type, typeArguments, arguments,
argumentNames);
}
}
// TODO(regis): Deprecated member still used by dart2js to be removed.
// Remember the type from the invocation mirror or static compilation
// analysis when thrown directly with _throwNew. A negative value means
// that no information is available.
final int _invocation_type;
// TODO(regis): Deprecated constructor still used by dart2js to be removed.
@patch
NoSuchMethodError(Object receiver, Symbol memberName,
List positionalArguments, Map<Symbol, dynamic> namedArguments,
[List existingArgumentNames = null])
: _receiver = receiver,
_memberName = memberName,
_arguments = positionalArguments,
_namedArguments = namedArguments,
_existingArgumentNames = existingArgumentNames,
_invocation_type = -1;
// Helper to build a map of named arguments.
static Map<Symbol, dynamic> _NamedArgumentsMap(
List arguments, List argumentNames) {
Map<Symbol, dynamic> namedArguments = new Map<Symbol, dynamic>();
int numPositionalArguments = arguments.length - argumentNames.length;
for (int i = 0; i < argumentNames.length; i++) {
var arg_value = arguments[numPositionalArguments + i];
namedArguments[new Symbol(argumentNames[i])] = arg_value;
}
return namedArguments;
}
// Constructor called from Exceptions::ThrowByType(kNoSuchMethod) and from
// _throwNew above, taking a TypeArguments object rather than an unpacked list
// of types, as well as a list of all arguments and a list of names, rather
// than a separate list of positional arguments and a map of named arguments.
NoSuchMethodError._withType(
this._receiver,
String memberName,
int invocation_type,
Object typeArguments,
List arguments,
List argumentNames)
: this._invocation = new _InvocationMirror._withType(
new Symbol(memberName),
invocation_type,
typeArguments != null
? _InvocationMirror._unpackTypeArguments(typeArguments)
: null,
argumentNames != null
? arguments.sublist(0, arguments.length - argumentNames.length)
: arguments,
argumentNames != null
? _NamedArgumentsMap(arguments, argumentNames)
: null);
static String _existingMethodSignature(Object receiver, String methodName,
int invocationType) native "NoSuchMethodError_existingMethodSignature";
@patch
String toString() {
// TODO(regis): Remove this null check once dart2js is updated.
if (_invocation == null) {
// Use deprecated version of toString.
return _toStringDeprecated();
}
String memberName =
internal.Symbol.getUnmangledName(_invocation.memberName);
var level = (_invocation._type >> _InvocationMirror._LEVEL_SHIFT) &
_InvocationMirror._LEVEL_MASK;
var kind = _invocation._type & _InvocationMirror._KIND_MASK;
if (kind == _InvocationMirror._LOCAL_VAR) {
return "NoSuchMethodError: Cannot assign to final variable '$memberName'";
}
StringBuffer typeArgumentsBuf = null;
var typeArguments = _invocation.typeArguments;
if ((typeArguments != null) && (typeArguments.length > 0)) {
typeArgumentsBuf = new StringBuffer();
typeArgumentsBuf.write("<");
for (int i = 0; i < typeArguments.length; i++) {
if (i > 0) {
typeArgumentsBuf.write(", ");
}
typeArgumentsBuf.write(Error.safeToString(typeArguments[i]));
}
typeArgumentsBuf.write(">");
}
StringBuffer argumentsBuf = new StringBuffer();
var positionalArguments = _invocation.positionalArguments;
int argumentCount = 0;
if (positionalArguments != null) {
for (; argumentCount < positionalArguments.length; argumentCount++) {
if (argumentCount > 0) {
argumentsBuf.write(", ");
}
argumentsBuf
.write(Error.safeToString(positionalArguments[argumentCount]));
}
}
var namedArguments = _invocation.namedArguments;
if (namedArguments != null) {
namedArguments.forEach((Symbol key, var value) {
if (argumentCount > 0) {
argumentsBuf.write(", ");
}
argumentsBuf.write(internal.Symbol.getUnmangledName(key));
argumentsBuf.write(": ");
argumentsBuf.write(Error.safeToString(value));
argumentCount++;
});
}
String existingSig =
_existingMethodSignature(_receiver, memberName, _invocation._type);
String argsMsg = existingSig != null ? " with matching arguments" : "";
String kindBuf;
if (kind >= 0 && kind < 5) {
kindBuf = (const [
"method",
"getter",
"setter",
"getter or setter",
"variable"
])[kind];
}
StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: ");
bool is_type_call = false;
switch (level) {
case _InvocationMirror._DYNAMIC:
{
if (_receiver == null) {
if (existingSig != null) {
msgBuf.writeln("The null object does not have a $kindBuf "
"'$memberName'$argsMsg.");
} else {
msgBuf.writeln("The $kindBuf '$memberName' was called on null.");
}
} else {
if (_receiver is _Closure) {
msgBuf.writeln("Closure call with mismatched arguments: "
"function '$memberName'");
} else if (_receiver is _Type && memberName == "call") {
is_type_call = true;
String name = _receiver.toString();
msgBuf.writeln("Attempted to use type '$name' as a function. "
"Since types do not define a method 'call', this is not "
"possible. Did you intend to call the $name constructor and "
"forget the 'new' operator?");
} else {
msgBuf.writeln("Class '${_receiver.runtimeType}' has no instance "
"$kindBuf '$memberName'$argsMsg.");
}
}
break;
}
case _InvocationMirror._SUPER:
{
msgBuf.writeln("Super class of class '${_receiver.runtimeType}' has "
"no instance $kindBuf '$memberName'$argsMsg.");
memberName = "super.$memberName";
break;
}
case _InvocationMirror._STATIC:
{
msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg "
"declared in class '$_receiver'.");
break;
}
case _InvocationMirror._CONSTRUCTOR:
{
msgBuf.writeln("No constructor '$memberName'$argsMsg declared "
"in class '$_receiver'.");
memberName = "new $memberName";
break;
}
case _InvocationMirror._TOP_LEVEL:
{
msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg "
"declared.");
break;
}
}
if (level == _InvocationMirror._TOP_LEVEL) {
msgBuf.writeln("Receiver: top-level");
} else {
msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}");
}
if (kind == _InvocationMirror._METHOD) {
String m = is_type_call ? "$_receiver" : "$memberName";
msgBuf.write("Tried calling: $m");
if (typeArgumentsBuf != null) {
msgBuf.write(typeArgumentsBuf);
}
msgBuf.write("($argumentsBuf)");
} else if (argumentCount == 0) {
msgBuf.write("Tried calling: $memberName");
} else if (kind == _InvocationMirror._SETTER) {
msgBuf.write("Tried calling: $memberName$argumentsBuf");
} else {
msgBuf.write("Tried calling: $memberName = $argumentsBuf");
}
if (existingSig != null) {
msgBuf.write("\nFound: $memberName$existingSig");
}
return msgBuf.toString();
}
// TODO(regis): Remove this function once dart2js is updated.
String _toStringDeprecated() {
var level = (_invocation_type >> _InvocationMirror._LEVEL_SHIFT) &
_InvocationMirror._LEVEL_MASK;
var type = _invocation_type & _InvocationMirror._KIND_MASK;
String memberName = (_memberName == null)
? ""
: internal.Symbol.getUnmangledName(_memberName);
if (type == _InvocationMirror._LOCAL_VAR) {
return "NoSuchMethodError: Cannot assign to final variable '$memberName'";
}
StringBuffer arguments = new StringBuffer();
int argumentCount = 0;
if (_arguments != null) {
for (; argumentCount < _arguments.length; argumentCount++) {
if (argumentCount > 0) {
arguments.write(", ");
}
arguments.write(Error.safeToString(_arguments[argumentCount]));
}
}
if (_namedArguments != null) {
_namedArguments.forEach((Symbol key, var value) {
if (argumentCount > 0) {
arguments.write(", ");
}
arguments.write(internal.Symbol.getUnmangledName(key));
arguments.write(": ");
arguments.write(Error.safeToString(value));
argumentCount++;
});
}
bool args_mismatch = _existingArgumentNames != null;
String args_message = args_mismatch ? " with matching arguments" : "";
String type_str;
if (type >= 0 && type < 5) {
type_str = (const [
"method",
"getter",
"setter",
"getter or setter",
"variable"
])[type];
}
StringBuffer msg_buf = new StringBuffer("NoSuchMethodError: ");
bool is_type_call = false;
switch (level) {
case _InvocationMirror._DYNAMIC:
{
if (_receiver == null) {
if (args_mismatch) {
msg_buf.writeln("The null object does not have a $type_str "
"'$memberName'$args_message.");
} else {
msg_buf
.writeln("The $type_str '$memberName' was called on null.");
}
} else {
if (_receiver is _Closure) {
msg_buf.writeln("Closure call with mismatched arguments: "
"function '$memberName'");
} else if (_receiver is _Type && memberName == "call") {
is_type_call = true;
String name = _receiver.toString();
msg_buf.writeln("Attempted to use type '$name' as a function. "
"Since types do not define a method 'call', this is not "
"possible. Did you intend to call the $name constructor and "
"forget the 'new' operator?");
} else {
msg_buf
.writeln("Class '${_receiver.runtimeType}' has no instance "
"$type_str '$memberName'$args_message.");
}
}
break;
}
case _InvocationMirror._SUPER:
{
msg_buf.writeln("Super class of class '${_receiver.runtimeType}' has "
"no instance $type_str '$memberName'$args_message.");
memberName = "super.$memberName";
break;
}
case _InvocationMirror._STATIC:
{
msg_buf.writeln("No static $type_str '$memberName'$args_message "
"declared in class '$_receiver'.");
break;
}
case _InvocationMirror._CONSTRUCTOR:
{
msg_buf.writeln("No constructor '$memberName'$args_message declared "
"in class '$_receiver'.");
memberName = "new $memberName";
break;
}
case _InvocationMirror._TOP_LEVEL:
{
msg_buf.writeln("No top-level $type_str '$memberName'$args_message "
"declared.");
break;
}
}
if (level == _InvocationMirror._TOP_LEVEL) {
msg_buf.writeln("Receiver: top-level");
} else {
msg_buf.writeln("Receiver: ${Error.safeToString(_receiver)}");
}
if (type == _InvocationMirror._METHOD) {
String m = is_type_call ? "$_receiver" : "$memberName";
msg_buf.write("Tried calling: $m($arguments)");
} else if (argumentCount == 0) {
msg_buf.write("Tried calling: $memberName");
} else if (type == _InvocationMirror._SETTER) {
msg_buf.write("Tried calling: $memberName$arguments");
} else {
msg_buf.write("Tried calling: $memberName = $arguments");
}
if (args_mismatch) {
StringBuffer formalParameters = new StringBuffer();
for (int i = 0; i < _existingArgumentNames.length; i++) {
if (i > 0) {
formalParameters.write(", ");
}
formalParameters.write(_existingArgumentNames[i]);
}
msg_buf.write("\nFound: $memberName($formalParameters)");
}
return msg_buf.toString();
}
}
class _CompileTimeError extends Error {
final String _errorMsg;
_CompileTimeError(this._errorMsg);
String toString() => _errorMsg;
}
dynamic _classRangeAssert(int position, dynamic instance, _Type type, int cid,
int lowerLimit, int upperLimit) {
if ((cid < lowerLimit || cid > upperLimit) && instance != null) {
_TypeError._throwNew(position, instance, type, " in type cast", null);
}
return instance;
}
dynamic _classIdEqualsAssert(
int position, dynamic instance, _Type type, int cid, int otherCid) {
if (cid != otherCid && instance != null) {
_TypeError._throwNew(position, instance, type, " in type cast", null);
}
return instance;
}
/// Used by Fasta to report a runtime error when a final field with an
/// initializer is also initialized in a generative constructor.
///
/// Note: in strong mode, this is a compile-time error and this class becomes
/// obsolete.
class _DuplicatedFieldInitializerError extends Error {
final String _name;
_DuplicatedFieldInitializerError(this._name);
toString() => "Error: field '$_name' is already initialized.";
}
@patch
class _ConstantExpressionError {
@patch
_throw(error) => throw error;
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
@patch
class Expando<T> {
@patch
Expando([String name])
: name = 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 mask = _size - 1;
var idx = object._identityHashCode & 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;
}
idx = (idx + 1) & mask;
wp = _data[idx];
}
return null;
}
@patch
void operator []=(Object object, T value) {
_checkType(object);
var mask = _size - 1;
var idx = object._identityHashCode & 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.
}
}
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++;
}
}
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;
}
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) {
// Ensure that the entry.key is not cleared between checking for it and
// inserting it into the new table.
var val = entry.value;
var key = entry.key;
if (key != null) {
this[key] = val;
}
}
}
}
static _checkType(object) {
if ((object == null) ||
(object is bool) ||
(object is num) ||
(object is String)) {
throw new ArgumentError.value(object,
"Expandos are not allowed on strings, numbers, booleans or null");
}
}
get _size => _data.length;
get _limit => (3 * (_size ~/ 4));
List _data;
int _used; // Number of used (active and deleted) slots.
}
// Copyright (c) 2013, 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.
// part of "core_patch.dart";
class _Closure implements Function {
bool operator ==(other) native "Closure_equals";
int get hashCode {
if (_hash == null) {
_hash = _computeHash();
}
return _hash;
}
_Closure get call => this;
_Closure _clone() native "Closure_clone";
int _computeHash() native "Closure_computeHash";
// No instance fields should be declared before the following 4 fields whose
// offsets must be identical in Dart and C++.
// The following fields are declared both in raw_object.h (for direct access
// from C++ code) and also here so that the offset-to-field map used by
// deferred objects is properly initialized.
// Caution: These fields are not Dart instances, but VM objects. Their Dart
// names do not need to match the C++ names, but they must be private.
var _instantiator_type_arguments;
var _function_type_arguments;
var _function;
var _context;
// Note: _Closure objects are created by VM "magically", without invoking
// constructor. So, _Closure default constructor is never compiled and
// detection of default-initialized fields is not performed.
// As a consequence, VM incorrectly assumes that _hash field is not
// nullable and may incorrectly remove 'if (_hash == null)' in get:hashCode.
// This initializer makes _hash field nullable even without constructor
// compilation.
var _hash = null;
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
@patch
class Function {
// TODO(regis): Pass type arguments to generic functions. Wait for API spec.
static _apply(List arguments, List names) native "Function_apply";
@patch
static apply(Function function, List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
int numPositionalArguments = 1 + // Function is first implicit argument.
(positionalArguments != null ? positionalArguments.length : 0);
int numNamedArguments = namedArguments != null ? namedArguments.length : 0;
int numArguments = numPositionalArguments + numNamedArguments;
List arguments = new List(numArguments);
arguments[0] = function;
arguments.setRange(1, numPositionalArguments, positionalArguments);
List names = new List(numNamedArguments);
int argumentIndex = numPositionalArguments;
int nameIndex = 0;
if (numNamedArguments > 0) {
namedArguments.forEach((name, value) {
arguments[argumentIndex++] = value;
names[nameIndex++] = internal.Symbol.getName(name);
});
}
return _apply(arguments, names);
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
class _GrowableList<T> extends ListBase<T> {
void insert(int index, T element) {
if ((index < 0) || (index > length)) {
throw new RangeError.range(index, 0, length);
}
if (index == this.length) {
add(element);
return;
}
int oldLength = this.length;
// We are modifying the length just below the is-check. Without the check
// Array.copy could throw an exception, leaving the list in a bad state
// (with a length that has been increased, but without a new element).
if (index is! int) throw new ArgumentError(index);
this.length++;
Lists.copy(this, index, this, index + 1, oldLength - index);
_data[index] = element;
}
T removeAt(int index) {
var result = _data[index];
int newLength = this.length - 1;
if (index < newLength) {
Lists.copy(this, index + 1, this, index, newLength - index);
}
this.length = newLength;
return result;
}
bool remove(Object element) {
for (int i = 0; i < this.length; i++) {
if (_data[i] == element) {
removeAt(i);
return true;
}
}
return false;
}
void insertAll(int index, Iterable<T> iterable) {
if (index < 0 || index > length) {
throw new RangeError.range(index, 0, length);
}
// TODO(floitsch): we can probably detect more cases.
if (iterable is! List && iterable is! Set && iterable is! SubListIterable) {
iterable = iterable.toList();
}
int insertionLength = iterable.length;
// There might be errors after the length change, in which case the list
// will end up being modified but the operation not complete. Unless we
// always go through a "toList" we can't really avoid that.
this.length += insertionLength;
setRange(index + insertionLength, this.length, this, index);
setAll(index, iterable);
}
void setAll(int index, Iterable<T> iterable) {
if (iterable is List) {
setRange(index, index + iterable.length, iterable);
} else {
for (T element in iterable) {
_data[index++] = element;
}
}
}
void removeRange(int start, int end) {
RangeError.checkValidRange(start, end, this.length);
Lists.copy(this, end, this, start, this.length - end);
this.length = this.length - (end - start);
}
List<T> sublist(int start, [int end]) {
end = RangeError.checkValidRange(start, end, this.length);
int length = end - start;
if (length == 0) return <T>[];
List list = new _List(length);
for (int i = 0; i < length; i++) {
list[i] = _data[start + i];
}
var result = new _GrowableList<T>.withData(list);
result._setLength(length);
return result;
}
factory _GrowableList(int length) {
var data = _allocateData(length);
var result = new _GrowableList<T>.withData(data);
if (length > 0) {
result._setLength(length);
}
return result;
}
factory _GrowableList.withCapacity(int capacity) {
var data = _allocateData(capacity);
return new _GrowableList<T>.withData(data);
}
factory _GrowableList.withData(_List data) native "GrowableList_allocate";
int get _capacity native "GrowableList_getCapacity";
int get length native "GrowableList_getLength";
void set length(int new_length) {
int old_capacity = _capacity;
int new_capacity = new_length;
if (new_capacity > old_capacity) {
_grow(new_capacity);
_setLength(new_length);
return;
}
// We are shrinking. Pick the method which has fewer writes.
// In the shrink-to-fit path, we write |new_capacity + new_length| words
// (null init + copy).
// In the non-shrink-to-fit path, we write |length - new_length| words
// (null overwrite).
final bool shouldShrinkToFit =
(new_capacity + new_length) < (length - new_length);
if (shouldShrinkToFit) {
_shrink(new_capacity, new_length);
} else {
for (int i = new_length; i < length; i++) {
_data[i] = null;
}
}
_setLength(new_length);
}
void _setLength(int new_length) native "GrowableList_setLength";
void _setData(_List array) native "GrowableList_setData";
_List get _data native "GrowableList_getData";
T operator [](int index) native "GrowableList_getIndexed";
void operator []=(int index, T value) native "GrowableList_setIndexed";
void add(T value) {
var len = length;
if (len == _capacity) {
_grow(_nextCapacity(len));
}
_setLength(len + 1);
_data[len] = value;
}
void addAll(Iterable<T> iterable) {
var len = length;
final cid = ClassID.getID(iterable);
final isVMList = (cid == ClassID.cidArray) ||
(cid == ClassID.cidGrowableObjectArray) ||
(cid == ClassID.cidImmutableArray);
if (isVMList || (iterable is EfficientLengthIterable)) {
var cap = _capacity;
// Pregrow if we know iterable.length.
var iterLen = iterable.length;
var newLen = len + iterLen;
if (newLen > cap) {
do {
cap = _nextCapacity(cap);
} while (newLen > cap);
_grow(cap);
}
if (isVMList) {
if (identical(iterable, this)) {
throw new ConcurrentModificationError(this);
}
this._setLength(newLen);
final ListBase<T> iterableAsList = iterable;
for (int i = 0; i < iterLen; i++) {
_data[len++] = iterableAsList[i];
}
return;
}
}
Iterator it = iterable.iterator;
if (!it.moveNext()) return;
do {
while (len < _capacity) {
int newLen = len + 1;
this._setLength(newLen);
_data[len] = it.current;
if (!it.moveNext()) return;
if (this.length != newLen) throw new ConcurrentModificationError(this);
len = newLen;
}
_grow(_nextCapacity(_capacity));
} while (true);
}
T removeLast() {
var len = length - 1;
var elem = _data[len];
this.length = len;
return elem;
}
T get first {
if (length > 0) return _data[0];
throw IterableElementError.noElement();
}
T get last {
if (length > 0) return _data[length - 1];
throw IterableElementError.noElement();
}
T get single {
if (length == 1) return _data[0];
if (length == 0) throw IterableElementError.noElement();
throw IterableElementError.tooMany();
;
}
// Shared array used as backing for new empty growable arrays.
static final _List _emptyList = new _List(0);
static _List _allocateData(int capacity) {
if (capacity == 0) {
// Use shared empty list as backing.
return _emptyList;
}
// Round up size to the next odd number, since this is free
// because of alignment requirements of the GC.
return new _List(capacity | 1);
}
// Grow from 0 to 3, and then double + 1.
int _nextCapacity(int old_capacity) => (old_capacity * 2) | 3;
void _grow(int new_capacity) {
final _List newData = _allocateData(new_capacity);
// This is a work-around for dartbug.com/30090: array-bound-check
// generalization causes excessive deoptimizations because it
// hoists CheckArrayBound(i, ...) out of the loop below and turns it
// into CheckArrayBound(length - 1, ...). Which deoptimizes
// if length == 0. However the loop itself does not execute
// if length == 0.
if (length > 0) {
for (int i = 0; i < length; i++) {
newData[i] = this[i];
}
}
_setData(newData);
}
void _shrink(int new_capacity, int new_length) {
final _List newData = _allocateData(new_capacity);
// This is a work-around for dartbug.com/30090. See the comment in _grow.
if (new_length > 0) {
for (int i = 0; i < new_length; i++) {
newData[i] = this[i];
}
}
_setData(newData);
}
// Iterable interface.
void forEach(f(T element)) {
int initialLength = length;
for (int i = 0; i < length; i++) {
f(_data[i]);
if (length != initialLength) throw new ConcurrentModificationError(this);
}
}
String join([String separator = ""]) {
final int length = this.length;
if (length == 0) return "";
if (length == 1) return "${_data[0]}";
if (separator.isNotEmpty) return _joinWithSeparator(separator);
var i = 0;
var codeUnitCount = 0;
while (i < length) {
final element = this[i];
// While list contains one-byte strings.
if (element is _OneByteString) {
codeUnitCount += element.length;
i++;
// Loop back while strings are one-byte strings.
continue;
}
// Otherwise, never loop back to the outer loop, and
// handle the remaining strings below.
// Loop while elements are strings,
final int firstNonOneByteStringLimit = i;
var nextElement = element;
while (nextElement is String) {
i++;
if (i == length) {
return _StringBase._concatRangeNative(this, 0, length);
}
nextElement = _data[i];
}
// Not all elements are strings, so allocate a new backing array.
final list = new _List(length);
for (int copyIndex = 0; copyIndex < i; copyIndex++) {
list[copyIndex] = _data[copyIndex];
}
// Is non-zero if list contains a non-onebyte string.
var onebyteCanary = i - firstNonOneByteStringLimit;
while (true) {
final String elementString = "$nextElement";
onebyteCanary |=
(ClassID.getID(elementString) ^ ClassID.cidOneByteString);
list[i] = elementString;
codeUnitCount += elementString.length;
i++;
if (i == length) break;
nextElement = _data[i];
}
if (onebyteCanary == 0) {
// All elements returned a one-byte string from toString.
return _OneByteString._concatAll(list, codeUnitCount);
}
return _StringBase._concatRangeNative(list, 0, length);
}
// All elements were one-byte strings.
return _OneByteString._concatAll(this, codeUnitCount);
}
String _joinWithSeparator(String separator) {
StringBuffer buffer = new StringBuffer();
buffer.write(_data[0]);
for (int i = 1; i < this.length; i++) {
buffer.write(separator);
buffer.write(_data[i]);
}
return buffer.toString();
}
T elementAt(int index) {
return _data[index];
}
bool get isEmpty {
return this.length == 0;
}
bool get isNotEmpty => !isEmpty;
void clear() {
this.length = 0;
}
String toString() => ListBase.listToString(this);
Iterator<T> get iterator {
return new ListIterator<T>(this);
}
List<T> toList({bool growable: true}) {
var length = this.length;
if (length > 0) {
List list = growable ? new _List(length) : new _List<T>(length);
for (int i = 0; i < length; i++) {
list[i] = _data[i];
}
if (!growable) return list;
var result = new _GrowableList<T>.withData(list);
result._setLength(length);
return result;
}
return growable ? <T>[] : new List<T>(0);
}
Set<T> toSet() {
return new Set<T>.from(this);
}
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
@patch
bool identical(Object a, Object b) native "Identical_comparison";
@patch
int identityHashCode(Object object) => object._identityHashCode;
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
/// Immutable map class for compiler generated map literals.
class _ImmutableMap<K, V> implements Map<K, V> {
final _ImmutableList _kvPairs;
const _ImmutableMap._create(_ImmutableList keyValuePairs)
: _kvPairs = keyValuePairs;
V operator [](Object key) {
// To preserve the key-value order of the map literal, the keys are
// not sorted. Need to do linear search or implement an additional
// lookup table.
for (int i = 0; i < _kvPairs.length - 1; i += 2) {
if (key == _kvPairs[i]) {
return _kvPairs[i + 1];
}
}
return null;
}
bool get isEmpty {
return _kvPairs.length == 0;
}
bool get isNotEmpty => !isEmpty;
int get length {
return _kvPairs.length ~/ 2;
}
void forEach(void f(K key, V value)) {
for (int i = 0; i < _kvPairs.length; i += 2) {
f(_kvPairs[i], _kvPairs[i + 1]);
}
}
Iterable<K> get keys {
return new _ImmutableMapKeyIterable<K>(this);
}
Iterable<V> get values {
return new _ImmutableMapValueIterable<V>(this);
}
bool containsKey(Object key) {
for (int i = 0; i < _kvPairs.length; i += 2) {
if (key == _kvPairs[i]) {
return true;
}
}
return false;
}
bool containsValue(Object value) {
for (int i = 1; i < _kvPairs.length; i += 2) {
if (value == _kvPairs[i]) {
return true;
}
}
return false;
}
void operator []=(K key, V value) {
throw new UnsupportedError("Cannot set value in unmodifiable Map");
}
V putIfAbsent(K key, V ifAbsent()) {
throw new UnsupportedError("Cannot set value in unmodifiable Map");
}
void clear() {
throw new UnsupportedError("Cannot clear unmodifiable Map");
}
V remove(Object key) {
throw new UnsupportedError("Cannot remove from unmodifiable Map");
}
String toString() {
return Maps.mapToString(this);
}
}
class _ImmutableMapKeyIterable<E> extends EfficientLengthIterable<E> {
final _ImmutableMap _map;
_ImmutableMapKeyIterable(this._map);
Iterator<E> get iterator {
return new _ImmutableMapKeyIterator<E>(_map);
}
int get length => _map.length;
}
class _ImmutableMapValueIterable<E> extends EfficientLengthIterable<E> {
final _ImmutableMap _map;
_ImmutableMapValueIterable(this._map);
Iterator<E> get iterator {
return new _ImmutableMapValueIterator<E>(_map);
}
int get length => _map.length;
}
class _ImmutableMapKeyIterator<E> implements Iterator<E> {
_ImmutableMap _map;
int _index = -1;
E _current;
_ImmutableMapKeyIterator(this._map);
bool moveNext() {
int newIndex = _index + 1;
if (newIndex < _map.length) {
_index = newIndex;
_current = _map._kvPairs[newIndex * 2];
return true;
}
_current = null;
_index = _map.length;
return false;
}
E get current => _current;
}
class _ImmutableMapValueIterator<E> implements Iterator<E> {
_ImmutableMap _map;
int _index = -1;
E _current;
_ImmutableMapValueIterator(this._map);
bool moveNext() {
int newIndex = _index + 1;
if (newIndex < _map.length) {
_index = newIndex;
_current = _map._kvPairs[newIndex * 2 + 1];
return true;
}
_current = null;
_index = _map.length;
return false;
}
E get current => _current;
}
// Copyright (c) 2012, 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.
// part of "core_patch.dart";
/// VM implementation of int.
@patch
@patchExtends
class int {
@patch