Add missing methods to List and Map implementations.

Optimize FollowedBy when the operands have efficient length.

Change-Id: I0af59240d70b929358c06b8d57a85df2deee6aaf
Reviewed-on: https://dart-review.googlesource.com/43665
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2018-02-28 12:26:53 +00:00 committed by commit-bot@chromium.org
parent 4a11a27b53
commit 9ee735b659
20 changed files with 482 additions and 151 deletions

View file

@ -26,12 +26,14 @@ class InvocationImpl extends Invocation {
namedArguments = _namedArgsToSymbols(namedArguments),
typeArguments = typeArguments == null
? const []
: typeArguments.map(wrapType).toList();
: new List.unmodifiable(typeArguments.map(wrapType));
static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
if (namedArgs == null) return {};
return new Map.fromIterable(getOwnPropertyNames(namedArgs),
key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k));
if (namedArgs == null) return const {};
return new Map.unmodifiable(new Map.fromIterable(
getOwnPropertyNames(namedArgs),
key: _dartSymbol,
value: (k) => JS('', '#[#]', namedArgs, k)));
}
}
@ -206,7 +208,7 @@ _toDisplayName(name) => JS('', '''(() => {
// Names starting with _ are escaped names used to disambiguate Dart and
// JS names.
if ($name[0] === '_') {
// Inverse of
// Inverse of
switch($name) {
case '_get':
return '[]';
@ -293,7 +295,7 @@ _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => {
// Apply type arguments
if ($ftype instanceof $GenericFunctionType) {
let formalCount = $ftype.formalCount;
if ($typeArgs == null) {
$typeArgs = $ftype.instantiateDefaultBounds();
} else if ($typeArgs.length != formalCount) {

View file

@ -598,17 +598,10 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
Type get runtimeType =>
dart.wrapType(JS('', '#(#)', dart.getGenericClass(List), E));
Iterable<E> followedBy(Iterable<E> other) sync* {
yield* this;
yield* other;
}
Iterable<E> followedBy(Iterable<E> other) =>
new FollowedByIterable<E>.firstEfficient(this, other);
Iterable<T> whereType<T>() sync* {
for (var i = 0; i < this.length; i++) {
var element = this[i];
if (element is T) yield element;
}
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
List<E> operator +(List<E> other) {
int totalLength = this.length + other.length;

View file

@ -20,7 +20,7 @@ class _Vector extends core::Object {
}
operator *([@vm.inferred-type.metadata=#lib::_Vector] self::_Vector a) → core::double {
core::double result = 0.0;
for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector::_length] [@vm.inferred-type.metadata=!] this.{self::_Vector::_length}); i = i.{core::num::+}(1))
for (core::int i = 0; i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector::_length] [@vm.inferred-type.metadata=!] this.{self::_Vector::_length}); i = i.{core::num::+}(1))
result = [@vm.direct-call.metadata=dart.core::_Double::+??] [@vm.inferred-type.metadata=dart.core::_Double] result.{core::double::+}([@vm.direct-call.metadata=dart.core::_Double::*] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.direct-call.metadata=#lib::_Vector::[]] [@vm.inferred-type.metadata=dart.core::_Double] this.{self::_Vector::[]}(i).{core::double::*}([@vm.direct-call.metadata=#lib::_Vector::[]] [@vm.inferred-type.metadata=dart.core::_Double] a.{self::_Vector::[]}(i)));
return result;
}
@ -29,7 +29,7 @@ class _Vector extends core::Object {
[@vm.inferred-type.metadata=dart.core::_Double]static field core::double x = 0.0;
static method main(core::List<core::String> args) → dynamic {
core::Stopwatch timer = let final core::Stopwatch #t1 = new core::Stopwatch::•() in let final dynamic #t2 = [@vm.direct-call.metadata=dart.core::Stopwatch::start] #t1.{core::Stopwatch::start}() in #t1;
for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] i.{core::num::<}(100000000); i = i.{core::num::+}(1)) {
for (core::int i = 0; i.{core::num::<}(100000000); i = i.{core::num::+}(1)) {
self::x = [@vm.direct-call.metadata=dart.core::_Double::+] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.inferred-type.metadata=dart.core::_Double] self::x.{core::double::+}([@vm.direct-call.metadata=#lib::_Vector::*] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.inferred-type.metadata=#lib::_Vector] self::v.{self::_Vector::*}([@vm.inferred-type.metadata=#lib::_Vector] self::v));
}
[@vm.direct-call.metadata=dart.core::Stopwatch::stop] timer.{core::Stopwatch::stop}();

View file

@ -8,6 +8,9 @@
// whether a parameter was passed.
class _GrowableArrayMarker implements int {
const _GrowableArrayMarker();
noSuchMethod(_) {
throw new UnimplementedError();
}
}
const _GROWABLE_ARRAY_MARKER = const _GrowableArrayMarker();

View file

@ -1863,7 +1863,7 @@ class _Bigint extends _IntegerImplementation {
}
// Interface for modular reduction.
class _Reduction {
abstract class _Reduction {
// Return the number of digits used by r_digits.
int _convert(_Bigint x, Uint32List r_digits);
int _mul(Uint32List x_digits, int x_used, Uint32List y_digits, int y_used,

View file

@ -5,12 +5,21 @@
// part of "core_patch.dart";
/// Immutable map class for compiler generated map literals.
// TODO(lrn): Extend MapBase with UnmodifiableMapMixin when mixins
// support forwarding const constructors.
class _ImmutableMap<K, V> implements Map<K, V> {
final _ImmutableList _kvPairs;
const _ImmutableMap._create(_ImmutableList keyValuePairs)
: _kvPairs = keyValuePairs;
Map<K2, V2> cast<K2, V2>() {
Map<Object, Object> self = this;
return (self is Map<K2, V2>) ? self : this.retype<K2, V2>();
}
Map<K2, V2> retype<K2, V2>() => Map.castFrom<K, V, K2, V2>(this);
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
@ -69,6 +78,10 @@ class _ImmutableMap<K, V> implements Map<K, V> {
throw new UnsupportedError("Cannot set value in unmodifiable Map");
}
void addAll(Map<K, V> other) {
throw new UnsupportedError("Cannot set value in unmodifiable Map");
}
V putIfAbsent(K key, V ifAbsent()) {
throw new UnsupportedError("Cannot set value in unmodifiable Map");
}

View file

@ -12,6 +12,7 @@ import "dart:_internal"
ClassID,
CodeUnits,
ExpandIterable,
FollowedByIterable,
IterableElementError,
ListMapView,
Lists,
@ -23,6 +24,7 @@ import "dart:_internal"
SubListIterable,
TakeWhileIterable,
WhereIterable,
WhereTypeIterable,
patch;
import "dart:collection" show ListBase;
@ -112,6 +114,11 @@ abstract class _IntListMixin implements List<int> {
List<int> _createList(int length);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<int> followedBy(Iterable<int> other) =>
new FollowedByIterable<int>.firstEfficient(this, other);
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : List.castFrom<int, R>(this);
@ -466,6 +473,11 @@ abstract class _DoubleListMixin implements List<double> {
List<double> _createList(int length);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<double> followedBy(Iterable<double> other) =>
new FollowedByIterable<double>.firstEfficient(this, other);
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : List.castFrom<double, R>(this);
@ -823,6 +835,11 @@ abstract class _Float32x4ListMixin implements List<Float32x4> {
List<Float32x4> _createList(int length);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<Float32x4> followedBy(Iterable<Float32x4> other) =>
new FollowedByIterable<Float32x4>.firstEfficient(this, other);
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : List.castFrom<Float32x4, R>(this);
@ -1184,6 +1201,11 @@ abstract class _Int32x4ListMixin implements List<Int32x4> {
List<Int32x4> _createList(int length);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<Int32x4> followedBy(Iterable<Int32x4> other) =>
new FollowedByIterable<Int32x4>.firstEfficient(this, other);
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : List.castFrom<Int32x4, R>(this);
@ -1544,6 +1566,11 @@ abstract class _Float64x2ListMixin implements List<Float64x2> {
List<Float64x2> _createList(int length);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<Float64x2> followedBy(Iterable<Float64x2> other) =>
new FollowedByIterable<Float64x2>.firstEfficient(this, other);
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : List.castFrom<Float64x2, R>(this);

View file

@ -635,17 +635,10 @@ class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
return new ListMapView<E>(this);
}
Iterable<E> followedBy(Iterable<E> other) sync* {
yield* this;
yield* other;
}
Iterable<E> followedBy(Iterable<E> other) =>
new FollowedByIterable<E>.firstEfficient(this, other);
Iterable<T> whereType<T>() sync* {
for (var i = 0; i < this.length; i++) {
var element = this[i];
if (element is T) yield element;
}
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
List<E> operator +(List<E> other) {
int totalLength = this.length + other.length;

View file

@ -26,18 +26,19 @@ abstract class IterableMixin<E> implements Iterable<E> {
Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
Iterable<T> whereType<T>() sync* {
for (Object element in this) if (element is T) yield element;
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<T> expand<T>(Iterable<T> f(E element)) =>
new ExpandIterable<E, T>(this, f);
Iterable<E> followedBy(Iterable<E> other) sync* {
// TODO(lrn): Optimize this (some operations can be more efficient,
// and the concatenation has efficient length if the source iterables do).
yield* this;
yield* other;
Iterable<E> followedBy(Iterable<E> other) {
// Type workaround because IterableMixin<E> doesn't promote
// to EfficientLengthIterable<E>.
Iterable<E> self = this;
if (self is EfficientLengthIterable<E>) {
return new FollowedByIterable<E>.firstEfficient(self, other);
}
return new FollowedByIterable<E>(this, other);
}
bool contains(Object element) {

View file

@ -59,12 +59,8 @@ abstract class ListMixin<E> implements List<E> {
E elementAt(int index) => this[index];
Iterable<E> followedBy(Iterable<E> other) sync* {
for (var i = 0; i < length; i++) {
yield this[i];
}
yield* other;
}
Iterable<E> followedBy(Iterable<E> other) =>
new FollowedByIterable<E>.firstEfficient(this, other);
void forEach(void action(E element)) {
int length = this.length;
@ -195,9 +191,7 @@ abstract class ListMixin<E> implements List<E> {
Iterable<E> where(bool test(E element)) => new WhereIterable<E>(this, test);
Iterable<T> whereType<T>() sync* {
for (var element in this) if (element is T) yield (element as T);
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
Iterable<T> map<T>(T f(E element)) => new MappedListIterable<E, T>(this, f);

View file

@ -58,16 +58,10 @@ abstract class SetMixin<E> implements Set<E> {
Set<R> retype<R>() => Set.castFrom<E, R>(this);
Iterable<E> followedBy(Iterable<E> other) sync* {
// TODO(lrn): Optimize this (some operations can be more efficient,
// and the concatenation has efficient length if the source iterables do).
yield* this;
yield* other;
}
Iterable<E> followedBy(Iterable<E> other) =>
new FollowedByIterable<E>.firstEfficient(this, other);
Iterable<T> whereType<T>() sync* {
for (Object element in this) if (element is T) yield element;
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
void clear() {
removeAll(toList());

View file

@ -186,11 +186,11 @@ abstract class Iterable<E> {
* and, after that, the elements of [other], in the same order as in the
* original iterables.
*/
Iterable<E> followedBy(Iterable<E> other) sync* {
// TODO(lrn): Optimize this (some operations can be more efficient,
// and the concatenation has efficient length if the source iterables do).
yield* this;
yield* other;
Iterable<E> followedBy(Iterable<E> other) {
if (this is EfficientLengthIterable<E>) {
return new FollowedByIterable<E>.firstEfficient(this, other);
}
return new FollowedByIterable<E>(this, other);
}
/**
@ -236,9 +236,7 @@ abstract class Iterable<E> {
* the returned [Iterable] may yield different results,
* if the underlying elements change between iterations.
*/
Iterable<T> whereType<T>() sync* {
for (var element in this) if (element is T) yield (element as T);
}
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
/**
* Expands each element of this [Iterable] into zero or more elements.

View file

@ -767,6 +767,125 @@ class EmptyIterator<E> implements Iterator<E> {
E get current => null;
}
class FollowedByIterable<E> extends Iterable<E> {
final Iterable<E> _first;
final Iterable<E> _second;
FollowedByIterable(this._first, this._second);
factory FollowedByIterable.firstEfficient(
EfficientLengthIterable<E> first, Iterable<E> second) {
if (second is EfficientLengthIterable<E>) {
return new EfficientLengthFollowedByIterable<E>(first, second);
}
return new FollowedByIterable<E>(first, second);
}
Iterator<E> get iterator => new FollowedByIterator(_first, _second);
int get length => _first.length + _second.length;
bool get isEmpty => _first.isEmpty && _second.isEmpty;
bool get isNotEmpty => _first.isNotEmpty || _second.isNotEmpty;
// May be more efficient if either iterable is a Set.
bool contains(Object value) =>
_first.contains(value) || _second.contains(value);
E get first {
var iterator = _first.iterator;
if (iterator.moveNext()) return iterator.current;
return _second.first;
}
E get last {
var iterator = _second.iterator;
if (iterator.moveNext()) {
E last = iterator.current;
while (iterator.moveNext()) last = iterator.current;
return last;
}
return _first.last;
}
// If linear sequences of `followedBy` becomes an issue, we can flatten
// into a list of iterables instead of a tree or spine.
}
class EfficientLengthFollowedByIterable<E> extends FollowedByIterable<E>
implements EfficientLengthIterable<E> {
EfficientLengthFollowedByIterable(
EfficientLengthIterable<E> first, EfficientLengthIterable<E> second)
: super(first, second);
Iterable<E> skip(int count) {
int firstLength = _first.length;
if (count >= firstLength) return _second.skip(count - firstLength);
return new EfficientLengthFollowedByIterable<E>(
_first.skip(count), _second);
}
Iterable<E> take(int count) {
int firstLength = _first.length;
if (count <= firstLength) return _first.take(count);
return new EfficientLengthFollowedByIterable<E>(
_first, _second.take(count - firstLength));
}
E elementAt(int index) {
int firstLength = _first.length;
if (index < firstLength) return _first.elementAt(index);
return _second.elementAt(index - firstLength);
}
E get first {
if (_first.isNotEmpty) return _first.first;
return _second.first;
}
E get last {
if (_second.isNotEmpty) return _second.last;
return _first.last;
}
}
class FollowedByIterator<E> implements Iterator<E> {
Iterator<E> _currentIterator;
Iterable<E> _nextIterable;
FollowedByIterator(Iterable<E> first, this._nextIterable)
: _currentIterator = first.iterator;
bool moveNext() {
if (_currentIterator.moveNext()) return true;
if (_nextIterable != null) {
_currentIterator = _nextIterable.iterator;
_nextIterable = null;
return _currentIterator.moveNext();
}
return false;
}
E get current => _currentIterator.current;
}
class WhereTypeIterable<T> extends Iterable<T> {
final Iterable<Object> _source;
WhereTypeIterable(this._source);
Iterator<T> get iterator => new WhereTypeIterator<T>(_source.iterator);
}
class WhereTypeIterator<T> implements Iterator<T> {
final Iterator<Object> _source;
WhereTypeIterator(this._source);
bool moveNext() {
while (_source.moveNext()) {
if (_source.current is T) return true;
}
return false;
}
T get current => _source.current;
}
/**
* Creates errors throw by [Iterable] when the element count is wrong.
*/

View file

@ -18,25 +18,7 @@ import 'package:async_helper/async_helper.dart';
* the error/warning message in the list of white-listings for each file.
*/
// TODO(johnniwinther): Support canonical URIs as keys.
const Map<String, List<String>> WHITE_LIST = const {
"sdk/lib/_internal/js_runtime/lib/js_array.dart": const [
"Method type variables do not have a runtime value.",
],
"sdk/lib/collection/iterable.dart": const [
"Method type variables do not have a runtime value.",
],
"sdk/lib/collection/list.dart": const [
"Method type variables do not have a runtime value.",
"Method type variables are treated as `dynamic` in `as` expressions.",
],
"sdk/lib/collection/set.dart": const [
"Method type variables do not have a runtime value.",
],
"sdk/lib/core/iterable.dart": const [
"Method type variables do not have a runtime value.",
"Method type variables are treated as `dynamic` in `as` expressions.",
],
};
const Map<String, List<String>> WHITE_LIST = const {};
void main() {
var uriList = new List<Uri>();

View file

@ -28,12 +28,6 @@ void main() {
"memory:library.dart:41:47:'hest' is defined here.:info",
"MessageKind.DUPLICATE_IMPORT:"
"memory:main.dart:86:92:Duplicate import of 'hest'.:warning",
"MessageKind.HIDDEN_WARNINGS:"
"null:null:null:1 warning(s) suppressed in dart:_interceptors.:hint",
"MessageKind.HIDDEN_WARNINGS_HINTS:"
"null:null:null:1 warning(s) and 1 hint(s) suppressed in dart:core.:hint",
"MessageKind.HIDDEN_WARNINGS_HINTS:"
"null:null:null:3 warning(s) and 1 hint(s) suppressed in dart:collection.:hint",
"MessageKind.IMPORTED_HERE:"
"memory:main.dart:0:22:'hest' is imported here.:info",
"MessageKind.IMPORTED_HERE:"

View file

@ -14,7 +14,7 @@ import '../memory_compiler.dart';
void check(String kind, Iterable<CollectedMessage> messages,
List<MessageKind> expectedMessageKinds) {
Expect.equals(messages.length, expectedMessageKinds.length,
Expect.equals(expectedMessageKinds.length, messages.length,
"Unexpected $kind count: $messages");
int i = 0;
messages.forEach((CollectedMessage message) {
@ -56,11 +56,7 @@ library lib.foo;
"""
}, warnings: [
MessageKind.DUPLICATED_LIBRARY_RESOURCE
], hints: [
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
], hints: []);
await test({
'main.dart': """
@ -79,11 +75,7 @@ library lib.bar;
"""
}, warnings: [
MessageKind.DUPLICATED_LIBRARY_RESOURCE
], hints: [
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
], hints: []);
await test({
'main.dart': """
@ -102,11 +94,7 @@ library lib.baz;
"""
}, warnings: [
MessageKind.DUPLICATED_LIBRARY_RESOURCE
], hints: [
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
], hints: []);
await test({
'main.dart': """
@ -130,11 +118,7 @@ library lib.boz;
"""
}, warnings: [
MessageKind.DUPLICATED_LIBRARY_RESOURCE
], hints: [
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
], hints: []);
await test({
'main.dart': """
@ -148,9 +132,6 @@ import 'pkg/lib/qux.dart';
"""
}, hints: [
MessageKind.DUPLICATED_RESOURCE,
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
await test({
@ -169,9 +150,5 @@ library lib;
}, warnings: [
MessageKind.DUPLICATED_LIBRARY_NAME,
MessageKind.DUPLICATED_LIBRARY_NAME
], hints: [
MessageKind.HIDDEN_WARNINGS,
MessageKind.HIDDEN_WARNINGS_HINTS,
MessageKind.HIDDEN_WARNINGS_HINTS,
]);
], hints: []);
}

View file

@ -8,6 +8,9 @@ int_parse_radix_bad_handler_test: MissingCompileTimeError
iterable_element_at_test/static: Pass
num_sign_test: Crash, Pass # Issue 31768
[ $compiler == dart2js ]
iterable_where_type_test: RuntimeError # issue 31718
[ $compiler != dartdevc ]
error_stack_trace_test/static: MissingCompileTimeError

View file

@ -0,0 +1,102 @@
// Copyright (c) 2018, 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.
import "dart:collection" show Queue;
import "dart:typed_data" show Int32List;
import "package:expect/expect.dart";
// Tests behavior of result of an operation on a followedBy iterable.
test(List expects, Iterable iterable, [String name]) {
try {
Expect.isFalse(iterable is List, "$name is! List");
Expect.isFalse(iterable is Set, "$name is! Set");
Expect.isFalse(iterable is Queue, "$name is! Queue");
if (expects.isNotEmpty) {
Expect.equals(expects.first, iterable.first, "$name: first");
Expect.equals(expects.last, iterable.last, "$name: last");
} else {
Expect.throwsStateError(() => iterable.first, "$name: first");
Expect.throwsStateError(() => iterable.last, "$name: last");
}
var it = iterable.iterator;
for (int index = 0; index < expects.length; index++) {
Expect.isTrue(it.moveNext(), "$name: has element $index");
var expect = expects[index];
Expect.equals(expect, it.current, "$name at $index");
Expect.equals(
expect, iterable.elementAt(index), "$name: elementAt($index)");
Expect.isTrue(iterable.contains(expect), "$name:contains $index");
}
Expect.isFalse(it.moveNext(),
"$name: extra element at ${expects.length}: ${it.current}");
} on Error {
print("Failed during: $name");
rethrow;
}
}
// Tests various operations on the a followedBy iterable.
tests(List<int> expects, Iterable<int> follow, [String name]) {
int length = expects.length;
test(expects, follow, name);
for (int i = 0; i <= length; i++) {
test(expects.sublist(i), follow.skip(i), "$name.skip($i)");
}
for (int i = 0; i <= length; i++) {
test(expects.sublist(0, i), follow.take(i), "$name.take($i)");
}
for (int i = 0; i <= length; i++) {
for (int j = 0; j <= length - i; j++) {
test(expects.sublist(i, i + j), follow.skip(i).take(j),
"$name.skiptake($i,${i+j})");
test(expects.sublist(i, i + j), follow.take(i + j).skip(i),
"$name.takeskip($i,${i+j})");
}
}
}
// Tests various different types of iterables as first and second operand.
types(List expects, List<int> first, List<int> second, [String name]) {
var conversions = <String, Iterable<int> Function(List<int>)>{
"const": toConst,
"list": toList,
"unmod": toUnmodifiable,
"set": toSet,
"queue": toQueue,
"eff-len-iter": toELIter,
"non-eff-iter": toNEIter,
"typed": toTyped,
"keys": toKeys,
"values": toValues,
};
conversions.forEach((n1, c1) {
conversions.forEach((n2, c2) {
tests(expects, c1(first).followedBy(c2(second)), "$name:$n1/$n2");
});
});
}
List<int> toConst(List<int> elements) => elements;
List<int> toList(List<int> elements) => elements.toList();
List<int> toUnmodifiable(List<int> elements) =>
new List<int>.unmodifiable(elements);
Set<int> toSet(List<int> elements) => elements.toSet();
Queue<int> toQueue(List<int> elements) => new Queue<int>.from(elements);
// Creates an efficient-length iterable.
Iterable<int> toELIter(List<int> elements) => elements.map<int>((x) => x);
// Creates a non-efficient-length iterable.
Iterable<int> toNEIter(List<int> elements) => elements.where((x) => true);
List<int> toTyped(List<int> elements) => new Int32List.fromList(elements);
Iterable<int> toKeys(List<int> elements) =>
new Map<int, int>.fromIterables(elements, elements).keys;
Iterable<int> toValues(List<int> elements) =>
new Map<int, int>.fromIterables(elements, elements).values;
main() {
types(<int>[], const <int>[], const <int>[], "0+0");
types(<int>[1, 2, 3, 4], const <int>[], const <int>[1, 2, 3, 4], "0+4");
types(<int>[1, 2, 3, 4], const <int>[1, 2], const <int>[3, 4], "2+2");
types(<int>[1, 2, 3, 4], const <int>[1, 2, 3, 4], const <int>[], "4+0");
}

View file

@ -0,0 +1,105 @@
// Copyright (c) 2018, 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.
import "dart:collection" show Queue;
import "dart:typed_data" show Int32List;
import "package:expect/expect.dart";
// Tests behavior of result of an operation on a followedBy iterable.
test(List expects, Iterable iterable, [String name]) {
try {
Expect.isFalse(iterable is List, "$name is! List");
Expect.isFalse(iterable is Set, "$name is! Set");
Expect.isFalse(iterable is Queue, "$name is! Queue");
if (expects.isNotEmpty) {
Expect.equals(expects.first, iterable.first, "$name: first");
Expect.equals(expects.last, iterable.last, "$name: last");
} else {
Expect.throwsStateError(() => iterable.first, "$name: first");
Expect.throwsStateError(() => iterable.last, "$name: last");
}
var it = iterable.iterator;
for (int index = 0; index < expects.length; index++) {
Expect.isTrue(it.moveNext(), "$name: has element $index");
var expect = expects[index];
Expect.equals(expect, it.current, "$name at $index");
Expect.equals(
expect, iterable.elementAt(index), "$name: elementAt($index)");
Expect.isTrue(iterable.contains(expect), "$name:contains $index");
}
Expect.isFalse(it.moveNext(),
"$name: extra element at ${expects.length}: ${it.current}");
} on Error {
print("Failed during: $name");
rethrow;
}
}
main() {
var conversions = <String, Iterable<int> Function(List<int>)>{
"const": toConst,
"list": toList,
"unmod": toUnmodifiable,
"set": toSet,
"queue": toQueue,
"eff-len-iter": toELIter,
"non-eff-iter": toNEIter,
"typed": toTyped,
"keys": toKeys,
"values": toValues,
};
for (var data in [
const <int>[],
const <int>[1],
const <int>[1, 2, 3]
]) {
conversions.forEach((name, c) {
test(data, c(data).whereType<int>(), "$name#${data.length}.wt<int>");
test(data, c(data).whereType<num>(), "$name#${data.length}.wt<num>");
test([], c(data).whereType<Null>(), "$name#${data.length}.wt<Null>");
});
}
test([1, 0.1], ["a", 1, new Object(), 0.1, null].whereType<num>(), "mixed");
var o = new Object();
var a = new A();
var b = new B();
var c = new C();
var d = new D();
var n = null;
test([o, a, b, c, d, n], [o, a, b, c, d, n].whereType<Object>(), "Object");
test([a, b, c, d], [o, a, b, c, d, n].whereType<A>(), "A");
test([b, d], [o, a, b, c, d, n].whereType<B>(), "B");
test([c, d], [o, a, b, c, d, n].whereType<C>(), "C");
test([d], [o, a, b, c, d, n].whereType<D>(), "D");
test([n], [o, a, b, c, d, n].whereType<Null>(), "Null");
test([d], <B>[d].whereType<C>(), "Unrelated");
}
class A {}
class B implements A {}
class C implements A {}
class D implements B, C {}
List<int> toConst(List<int> elements) => elements; // Argument is const.
List<int> toList(List<int> elements) => elements.toList();
List<int> toUnmodifiable(List<int> elements) =>
new List<int>.unmodifiable(elements);
Set<int> toSet(List<int> elements) => elements.toSet();
Queue<int> toQueue(List<int> elements) => new Queue<int>.from(elements);
// Creates an efficient-length iterable.
Iterable<int> toELIter(List<int> elements) => elements.map<int>((x) => x);
// Creates a non-efficient-length iterable.
Iterable<int> toNEIter(List<int> elements) => elements.where((x) => true);
List<int> toTyped(List<int> elements) => new Int32List.fromList(elements);
Iterable<int> toKeys(List<int> elements) =>
new Map<int, int>.fromIterables(elements, elements).keys;
Iterable<int> toValues(List<int> elements) =>
new Map<int, int>.fromIterables(elements, elements).values;

View file

@ -8,45 +8,76 @@ import "package:expect/expect.dart";
import 'dart:collection';
void main() {
test(const {1: 37});
test(new UnmodifiableMapView({1: 37}));
testNum(const {1: 37}, "const");
testNum(const <num, num>{1: 37}.cast<int, int>(), "const.cast");
testNum(const <num, num>{1: 37}.retype<int, int>(), "const.retype");
test(new UnmodifiableMapView<num, num>(<num, num>{1: 37}));
test(new UnmodifiableMapView<num, num>(<int, int>{1: 37}));
testNum(new UnmodifiableMapView({1: 37}), "unmod");
testNum(new UnmodifiableMapView<num, num>(<num, num>{1: 37}), "unmod.cast");
testNum(new UnmodifiableMapView<num, num>(<int, int>{1: 37}), "unmod.retype");
test(new UnmodifiableMapView<num, num>(<num, num>{1: 37}).cast<int, int>());
test(new UnmodifiableMapView<num, num>(<int, int>{1: 37}).cast<int, int>());
test(new UnmodifiableMapView<Object, Object>(<num, num>{1: 37})
.cast<int, int>());
test(new UnmodifiableMapView<Object, Object>(<int, int>{1: 37})
.cast<num, num>());
testNum(new UnmodifiableMapView<num, num>(<num, num>{1: 37}).cast<int, int>(),
"unmodView<num>.cast<int>");
testNum(new UnmodifiableMapView<num, num>(<int, int>{1: 37}).cast<int, int>(),
"unmodView<int>.cast<int>");
testNum(
new UnmodifiableMapView<Object, Object>(<num, num>{1: 37})
.cast<int, int>(),
"unmodView<Object>(num).cast<int>");
testNum(
new UnmodifiableMapView<Object, Object>(<int, int>{1: 37})
.cast<num, num>(),
"unmodView<Object>(int).cast<num>");
test(new UnmodifiableMapView<num, num>(<num, num>{1: 37}).retype<int, int>());
test(new UnmodifiableMapView<num, num>(<int, int>{1: 37}).retype<int, int>());
test(new UnmodifiableMapView<Object, Object>(<num, num>{1: 37})
.retype<int, int>());
test(new UnmodifiableMapView<Object, Object>(<int, int>{1: 37})
.retype<num, num>());
testNum(
new UnmodifiableMapView<num, num>(<num, num>{1: 37}).retype<int, int>(),
"unmodView<num>(num).retype<int>");
testNum(
new UnmodifiableMapView<num, num>(<int, int>{1: 37}).retype<int, int>(),
"unmodView<num>(int).retype<int>");
testNum(
new UnmodifiableMapView<Object, Object>(<num, num>{1: 37})
.retype<int, int>(),
"unmodView<Object>(num).retype<int>");
testNum(
new UnmodifiableMapView<Object, Object>(<int, int>{1: 37})
.retype<num, num>(),
"unmodView<Object>(int).retype<num>");
var m2 = new Map<num, num>.unmodifiable({1: 37});
test(m2);
test(m2.cast<int, int>());
testNum(m2, "Map<num>.unmod");
testNum(m2.cast<int, int>(), "Map<num>.unmod.cast<int>");
Map<Symbol, dynamic> nsm = new NsmMap().foo(a: 0);
test(nsm, #a, 0, "nsm");
test(nsm.cast<Object, int>(), #a, 0, "nsm.cast");
test(nsm.retype<Object, int>(), #a, 0, "nsm.retype");
}
void test(Map map) {
Expect.isTrue(map.containsKey(1));
Expect.equals(1, map.length);
Expect.equals(1, map.keys.first);
Expect.equals(37, map.values.first);
Expect.throws(map.clear);
Expect.throws(() {
map.remove(1);
});
Expect.throws(() {
map[2] = 42;
});
Expect.throws(() {
map.addAll(<int, int>{2: 42});
});
void testNum(Map<Object, Object> map, String name) {
test(map, 1, 37, name);
}
void test(
Map<Object, Object> map, Object firstKey, Object firstValue, String name) {
Expect.isTrue(map.containsKey(firstKey), "$name.containsKey");
Expect.equals(1, map.length, "$name.length");
Expect.equals(firstKey, map.keys.first, "$name.keys.first");
Expect.equals(firstValue, map.values.first, "$name.values.first");
Expect.throwsUnsupportedError(map.clear, "$name.clear");
Expect.throwsUnsupportedError(() {
map.remove(firstKey);
}, "$name.remove");
Expect.throwsUnsupportedError(() {
map[null] = null;
}, "$name[]=");
Expect.throwsUnsupportedError(() {
map.addAll(<Null, Null>{null: null});
}, "$name.addAll");
}
class NsmMap {
noSuchMethod(i) => i.namedArguments;
foo({a, b, c, d});
}