Make Iterable be the default implementation of itself.
Makes `Iterable` a mixin class with a `const` constructor, and `IterableBase` and `IterableMixin` (to-be-deprecated) aliases for it. Combining everything in one place avoids (some) code duplication. Also gave the methods a quick overhaul for formatting, removing uses of `late` and unnecessary element accesses, and some general tweaks. CoreLibraryReviewExempt: Refactoring of redundant types. Tested: Refactoring. If existing tests work, it works. Change-Id: Ie49a88f713d386d2d118c53606a71bdd50e1eb11 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287600 Reviewed-by: Brian Quinlan <bquinlan@google.com> Reviewed-by: Nate Bosch <nbosch@google.com>
This commit is contained in:
committed by
Lasse Nielsen
parent
23b73d7ca4
commit
5573ce7b84
+3
-1
@@ -21,7 +21,9 @@
|
||||
- **Breaking Change**: Non-`mixin` classes in the platform libraries
|
||||
can no longer be mixed in, unless they are explicitly marked as `mixin class`.
|
||||
The following existing classes have been made mixin classes:
|
||||
* `IterableMixin`
|
||||
* `Iterable`
|
||||
* `IterableMixin` (now alias for `Iterable`)
|
||||
* `IterableBase` (now alias for `Iterable`)
|
||||
* `ListMixin`
|
||||
* `SetMixin`
|
||||
* `MapMixin`
|
||||
|
||||
@@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
return <core::int>[].{core::Iterable::iterator}{core::Iterator<core::int>};
|
||||
@@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int};
|
||||
}
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
return <core::String>[].{core::Iterable::iterator}{core::Iterator<core::String>};
|
||||
@@ -383,7 +383,6 @@ constants {
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///const_collections.dart:
|
||||
- CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9)
|
||||
- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart)
|
||||
- Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
|
||||
- WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9)
|
||||
|
||||
+5
-6
@@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
return core::_GrowableList::•<core::int>(0).{core::Iterable::iterator}{core::Iterator<core::int>};
|
||||
@@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
return o is{ForNonNullableByDefault} self::WithEquals && o{self::WithEquals}.{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int};
|
||||
}
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
return core::_GrowableList::•<core::String>(0).{core::Iterable::iterator}{core::Iterator<core::String>};
|
||||
@@ -383,7 +383,6 @@ constants {
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///const_collections.dart:
|
||||
- CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9)
|
||||
- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart)
|
||||
- Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
|
||||
- WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9)
|
||||
|
||||
@@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
return <core::int>[].{core::Iterable::iterator}{core::Iterator<core::int>};
|
||||
@@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int};
|
||||
}
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
return <core::String>[].{core::Iterable::iterator}{core::Iterator<core::String>};
|
||||
@@ -383,7 +383,6 @@ constants {
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///const_collections.dart:
|
||||
- CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9)
|
||||
- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart)
|
||||
- Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
|
||||
- WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9)
|
||||
|
||||
+5
-6
@@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
return <core::int>[].{core::Iterable::iterator}{core::Iterator<core::int>};
|
||||
@@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int};
|
||||
}
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
return <core::String>[].{core::Iterable::iterator}{core::Iterator<core::String>};
|
||||
@@ -383,7 +383,6 @@ constants {
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///const_collections.dart:
|
||||
- CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9)
|
||||
- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart)
|
||||
- Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
|
||||
- WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9)
|
||||
|
||||
+4
-5
@@ -37,14 +37,13 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
;
|
||||
@@ -57,9 +56,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
operator ==(core::Object o) → core::bool
|
||||
;
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
;
|
||||
|
||||
+5
-6
@@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/;
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:collection" as col;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
class ConstIterable extends col::IterableBase<core::int> /*hasConstConstructor*/ {
|
||||
class ConstIterable extends core::Iterable<core::int> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::ConstIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::int>
|
||||
return core::_GrowableList::•<core::int>(0).{core::Iterable::iterator}{core::Iterator<core::int>};
|
||||
@@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ {
|
||||
return o is{ForNonNullableByDefault} self::WithEquals && o{self::WithEquals}.{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int};
|
||||
}
|
||||
}
|
||||
class CustomIterable extends col::IterableBase<core::String> /*hasConstConstructor*/ {
|
||||
class CustomIterable extends core::Iterable<core::String> /*hasConstConstructor*/ {
|
||||
const constructor •() → self::CustomIterable
|
||||
: super col::IterableBase::•()
|
||||
: super core::Iterable::•()
|
||||
;
|
||||
get iterator() → core::Iterator<core::String>
|
||||
return core::_GrowableList::•<core::String>(0).{core::Iterable::iterator}{core::Iterator<core::String>};
|
||||
@@ -383,7 +383,6 @@ constants {
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///const_collections.dart:
|
||||
- CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9)
|
||||
- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart)
|
||||
- Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
|
||||
- WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9)
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// class C extends Iterable<Object> {
|
||||
// ^
|
||||
// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here.
|
||||
// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here.
|
||||
// Iterator<E> get iterator;
|
||||
// ^^^^^^^^
|
||||
//
|
||||
|
||||
@@ -514,7 +514,7 @@ library from "org-dartlang-test:///main.dart" as main {
|
||||
return dart.core::Comparable::compare(a as{ForNonNullableByDefault} dart.core::Comparable<dynamic>, b as{ForNonNullableByDefault} dart.core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(dart.core::List<dart.core::Object?> list) → dart.core::String
|
||||
return dart.collection::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return dart.core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class WithListMixin extends main::_WithListMixin&Object&ListMixin {
|
||||
field dart.core::int length = 2;
|
||||
|
||||
@@ -514,7 +514,7 @@ library from "org-dartlang-test:///main.dart" as main {
|
||||
return dart.core::Comparable::compare(a as{ForNonNullableByDefault} dart.core::Comparable<dynamic>, b as{ForNonNullableByDefault} dart.core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(dart.core::List<dart.core::Object?> list) → dart.core::String
|
||||
return dart.collection::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return dart.core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class WithListMixin extends main::_WithListMixin&Object&ListMixin {
|
||||
field dart.core::int length = 2;
|
||||
|
||||
@@ -589,7 +589,7 @@ abstract class _CustomList&Object&ListMixin<E extends core::Object? = dynamic> e
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class CustomList<E extends core::Object? = dynamic> extends cac::_CustomList&Object&ListMixin<cac::CustomList::E%> {
|
||||
final field core::List<cac::CustomList::E%> list;
|
||||
|
||||
@@ -589,7 +589,7 @@ abstract class _CustomList&Object&ListMixin<E extends core::Object? = dynamic> e
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class CustomList<E extends core::Object? = dynamic> extends cac::_CustomList&Object&ListMixin<cac::CustomList::E%> {
|
||||
final field core::List<cac::CustomList::E%> list;
|
||||
|
||||
@@ -2,6 +2,7 @@ library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
@@ -134,12 +135,12 @@ abstract class _MyMap&Object&MapMixin<K extends core::Object? = dynamic, V exten
|
||||
method /* from org-dartlang-sdk:///sdk/lib/collection/maps.dart */ toString() → core::String
|
||||
return col::MapBase::mapToString(this);
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/maps.dart */ mapToString(core::Map<core::Object?, core::Object?> m) → core::String {
|
||||
if(col::_isToStringVisiting(m)) {
|
||||
if(_in::isToStringVisiting(m)) {
|
||||
return "{...}";
|
||||
}
|
||||
core::StringBuffer result = new core::StringBuffer::•();
|
||||
try {
|
||||
col::_toStringVisiting.{core::List::add}(m){(core::Object) → void};
|
||||
_in::toStringVisiting.{core::List::add}(m){(core::Object) → void};
|
||||
result.{core::StringBuffer::write}("{"){(core::Object?) → void};
|
||||
core::bool first = true;
|
||||
m.{core::Map::forEach}((core::Object? k, core::Object? v) → void {
|
||||
@@ -154,8 +155,8 @@ abstract class _MyMap&Object&MapMixin<K extends core::Object? = dynamic, V exten
|
||||
result.{core::StringBuffer::write}("}"){(core::Object?) → void};
|
||||
}
|
||||
finally {
|
||||
assert(core::identical(col::_toStringVisiting.{core::Iterable::last}{core::Object}, m));
|
||||
col::_toStringVisiting.{core::List::removeLast}(){() → core::Object};
|
||||
assert(core::identical(_in::toStringVisiting.{core::Iterable::last}{core::Object}, m));
|
||||
_in::toStringVisiting.{core::List::removeLast}(){() → core::Object};
|
||||
}
|
||||
return result.{core::StringBuffer::toString}(){() → core::String};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:collection" as col;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:collection";
|
||||
|
||||
@@ -134,12 +135,12 @@ abstract class _MyMap&Object&MapMixin<K extends core::Object? = dynamic, V exten
|
||||
method /* from org-dartlang-sdk:///sdk/lib/collection/maps.dart */ toString() → core::String
|
||||
return col::MapBase::mapToString(this);
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/maps.dart */ mapToString(core::Map<core::Object?, core::Object?> m) → core::String {
|
||||
if(col::_isToStringVisiting(m)) {
|
||||
if(_in::isToStringVisiting(m)) {
|
||||
return "{...}";
|
||||
}
|
||||
core::StringBuffer result = new core::StringBuffer::•();
|
||||
try {
|
||||
col::_toStringVisiting.{core::List::add}(m){(core::Object) → void};
|
||||
_in::toStringVisiting.{core::List::add}(m){(core::Object) → void};
|
||||
result.{core::StringBuffer::write}("{"){(core::Object?) → void};
|
||||
core::bool first = true;
|
||||
m.{core::Map::forEach}((core::Object? k, core::Object? v) → void {
|
||||
@@ -154,8 +155,8 @@ abstract class _MyMap&Object&MapMixin<K extends core::Object? = dynamic, V exten
|
||||
result.{core::StringBuffer::write}("}"){(core::Object?) → void};
|
||||
}
|
||||
finally {
|
||||
assert(core::identical(col::_toStringVisiting.{core::Iterable::last}{core::Object}, m));
|
||||
col::_toStringVisiting.{core::List::removeLast}(){() → core::Object};
|
||||
assert(core::identical(_in::toStringVisiting.{core::Iterable::last}{core::Object}, m));
|
||||
_in::toStringVisiting.{core::List::removeLast}(){() → core::Object};
|
||||
}
|
||||
return result.{core::StringBuffer::toString}(){() → core::String};
|
||||
}
|
||||
|
||||
+1
-1
@@ -518,7 +518,7 @@ abstract class _A&Object&ListMixin extends core::Object implements col::ListBase
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class A extends self::_A&Object&ListMixin {
|
||||
field core::int count = 0;
|
||||
|
||||
+1
-1
@@ -518,7 +518,7 @@ abstract class _A&Object&ListMixin extends core::Object implements col::ListBase
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class A extends self::_A&Object&ListMixin {
|
||||
field core::int count = 0;
|
||||
|
||||
@@ -518,7 +518,7 @@ abstract class _NegativeLengthList&Object&ListMixin<E extends core::Object? = dy
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class NegativeLengthList<E extends core::Object? = dynamic> extends self::_NegativeLengthList&Object&ListMixin<self::NegativeLengthList::E%> {
|
||||
final field core::List<self::NegativeLengthList::E%> _list;
|
||||
|
||||
@@ -518,7 +518,7 @@ abstract class _NegativeLengthList&Object&ListMixin<E extends core::Object? = dy
|
||||
return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable<dynamic>, b as{ForNonNullableByDefault} core::Comparable<dynamic>);
|
||||
}
|
||||
static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List<core::Object?> list) → core::String
|
||||
return col::IterableBase::iterableToFullString(list, "[", "]");
|
||||
return core::Iterable::iterableToFullString(list, "[", "]");
|
||||
}
|
||||
class NegativeLengthList<E extends core::Object? = dynamic> extends self::_NegativeLengthList&Object&ListMixin<self::NegativeLengthList::E%> {
|
||||
final field core::List<self::NegativeLengthList::E%> _list;
|
||||
|
||||
@@ -36,7 +36,7 @@ List<String> stops = [];
|
||||
// THIS TEST DEPENDS ON SPECIFIC LINE NUMBERS IN UNRELATED PLATFORM LIBRARIES
|
||||
// STAYING FIXED. VERY FRAGILE. SHOULD BE FIXED OR REMOVED.
|
||||
List<String> expected = [
|
||||
"set.dart:142:23 (sdk_break_with_mixin_test.dart:20:5)",
|
||||
"set.dart:142:21 (sdk_break_with_mixin_test.dart:20:5)",
|
||||
];
|
||||
|
||||
var tests = <IsolateTest>[
|
||||
|
||||
@@ -35,7 +35,7 @@ class MySet extends Object with SetMixin {
|
||||
|
||||
List<String> stops = [];
|
||||
List<String> expected = [
|
||||
"set.dart:142:23 (sdk_break_with_mixin_test.dart:21:5)",
|
||||
"set.dart:142:21 (sdk_break_with_mixin_test.dart:21:5)",
|
||||
];
|
||||
|
||||
var tests = <IsolateTest>[
|
||||
|
||||
@@ -53,7 +53,7 @@ class DartIterator<E> implements Iterator<E> {
|
||||
}
|
||||
|
||||
/// Used to compile `sync*`.
|
||||
class SyncIterable<E> extends IterableBase<E> {
|
||||
class SyncIterable<E> extends Iterable<E> {
|
||||
final Function() _initGenerator;
|
||||
SyncIterable(this._initGenerator);
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ class _MatchImplementation implements RegExpMatch {
|
||||
}
|
||||
}
|
||||
|
||||
class _AllMatchesIterable extends IterableBase<RegExpMatch> {
|
||||
class _AllMatchesIterable extends Iterable<RegExpMatch> {
|
||||
final JSSyntaxRegExp _re;
|
||||
final String _string;
|
||||
final int _start;
|
||||
|
||||
@@ -18,8 +18,6 @@ import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
|
||||
|
||||
import 'dart:_async_await_error_codes' as async_error_codes;
|
||||
|
||||
import "dart:collection" show IterableBase;
|
||||
|
||||
@patch
|
||||
class _AsyncRun {
|
||||
@patch
|
||||
@@ -686,7 +684,7 @@ _SyncStarIterable<T> _makeSyncStarIterable<T>(body) {
|
||||
/// An Iterable corresponding to a sync* method.
|
||||
///
|
||||
/// Each invocation of a sync* method will return a new instance of this class.
|
||||
class _SyncStarIterable<T> extends IterableBase<T> {
|
||||
class _SyncStarIterable<T> extends Iterable<T> {
|
||||
// This is a function that will return a helper function that does the
|
||||
// iteration of the sync*.
|
||||
//
|
||||
|
||||
@@ -230,7 +230,7 @@ class _MatchImplementation implements RegExpMatch {
|
||||
}
|
||||
}
|
||||
|
||||
class _AllMatchesIterable extends IterableBase<RegExpMatch> {
|
||||
class _AllMatchesIterable extends Iterable<RegExpMatch> {
|
||||
final JSSyntaxRegExp _re;
|
||||
final String _string;
|
||||
final int _start;
|
||||
|
||||
@@ -42,7 +42,6 @@ import "dart:async" show Completer, DeferredLoadException, Future, Timer, Zone;
|
||||
import "dart:collection"
|
||||
show
|
||||
HashMap,
|
||||
IterableBase,
|
||||
LinkedHashMap,
|
||||
LinkedList,
|
||||
LinkedListEntry,
|
||||
|
||||
@@ -323,7 +323,7 @@ class _RegExp implements RegExp {
|
||||
Int32List(_initialBacktrackingStackSize);
|
||||
}
|
||||
|
||||
class _AllMatchesIterable extends IterableBase<RegExpMatch> {
|
||||
class _AllMatchesIterable extends Iterable<RegExpMatch> {
|
||||
final _RegExp _re;
|
||||
final String _str;
|
||||
final int _start;
|
||||
|
||||
@@ -35,7 +35,6 @@ import 'dart:_js_helper' show JS, JSSyntaxRegExp, quoteStringForRegExp;
|
||||
import "dart:collection"
|
||||
show
|
||||
HashMap,
|
||||
IterableBase,
|
||||
LinkedHashMap,
|
||||
LinkedList,
|
||||
LinkedListEntry,
|
||||
|
||||
@@ -219,7 +219,7 @@ class _MatchImplementation implements RegExpMatch {
|
||||
}
|
||||
}
|
||||
|
||||
class _AllMatchesIterable extends IterableBase<RegExpMatch> {
|
||||
class _AllMatchesIterable extends Iterable<RegExpMatch> {
|
||||
final JSSyntaxRegExp _re;
|
||||
final String _string;
|
||||
final int _start;
|
||||
|
||||
@@ -7,396 +7,12 @@ part of dart.collection;
|
||||
/// This [Iterable] mixin implements all [Iterable] members except `iterator`.
|
||||
///
|
||||
/// All other methods are implemented in terms of `iterator`.
|
||||
abstract mixin class IterableMixin<E> implements Iterable<E> {
|
||||
// This class has methods copied verbatim into:
|
||||
// - IterableBase
|
||||
// - SetMixin
|
||||
// If changing a method here, also change the other copies.
|
||||
|
||||
Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
|
||||
Iterable<T> map<T>(T toElement(E element)) =>
|
||||
MappedIterable<E, T>(this, toElement);
|
||||
|
||||
Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
|
||||
|
||||
Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
|
||||
|
||||
Iterable<T> expand<T>(Iterable<T> toElements(E element)) =>
|
||||
ExpandIterable<E, T>(this, toElements);
|
||||
|
||||
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 FollowedByIterable<E>.firstEfficient(self, other);
|
||||
}
|
||||
return FollowedByIterable<E>(this, other);
|
||||
}
|
||||
|
||||
bool contains(Object? element) {
|
||||
for (E e in this) {
|
||||
if (e == element) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void forEach(void action(E element)) {
|
||||
for (E element in this) action(element);
|
||||
}
|
||||
|
||||
E reduce(E combine(E value, E element)) {
|
||||
Iterator<E> iterator = this.iterator;
|
||||
if (!iterator.moveNext()) {
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
E value = iterator.current;
|
||||
while (iterator.moveNext()) {
|
||||
value = combine(value, iterator.current);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
|
||||
var value = initialValue;
|
||||
for (E element in this) value = combine(value, element);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool every(bool test(E element)) {
|
||||
for (E element in this) {
|
||||
if (!test(element)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String join([String separator = ""]) {
|
||||
Iterator<E> iterator = this.iterator;
|
||||
if (!iterator.moveNext()) return "";
|
||||
StringBuffer buffer = StringBuffer();
|
||||
if (separator == null || separator == "") {
|
||||
do {
|
||||
buffer.write("${iterator.current}");
|
||||
} while (iterator.moveNext());
|
||||
} else {
|
||||
buffer.write("${iterator.current}");
|
||||
while (iterator.moveNext()) {
|
||||
buffer.write(separator);
|
||||
buffer.write("${iterator.current}");
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
bool any(bool test(E element)) {
|
||||
for (E element in this) {
|
||||
if (test(element)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
List<E> toList({bool growable = true}) =>
|
||||
List<E>.from(this, growable: growable);
|
||||
|
||||
Set<E> toSet() => Set<E>.from(this);
|
||||
|
||||
int get length {
|
||||
assert(this is! EfficientLengthIterable);
|
||||
int count = 0;
|
||||
Iterator it = iterator;
|
||||
while (it.moveNext()) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool get isEmpty => !iterator.moveNext();
|
||||
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
|
||||
Iterable<E> take(int count) {
|
||||
return TakeIterable<E>(this, count);
|
||||
}
|
||||
|
||||
Iterable<E> takeWhile(bool test(E value)) {
|
||||
return TakeWhileIterable<E>(this, test);
|
||||
}
|
||||
|
||||
Iterable<E> skip(int count) {
|
||||
return SkipIterable<E>(this, count);
|
||||
}
|
||||
|
||||
Iterable<E> skipWhile(bool test(E value)) {
|
||||
return SkipWhileIterable<E>(this, test);
|
||||
}
|
||||
|
||||
E get first {
|
||||
Iterator<E> it = iterator;
|
||||
if (!it.moveNext()) {
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
return it.current;
|
||||
}
|
||||
|
||||
E get last {
|
||||
Iterator<E> it = iterator;
|
||||
if (!it.moveNext()) {
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
E result;
|
||||
do {
|
||||
result = it.current;
|
||||
} while (it.moveNext());
|
||||
return result;
|
||||
}
|
||||
|
||||
E get single {
|
||||
Iterator<E> it = iterator;
|
||||
if (!it.moveNext()) throw IterableElementError.noElement();
|
||||
E result = it.current;
|
||||
if (it.moveNext()) throw IterableElementError.tooMany();
|
||||
return result;
|
||||
}
|
||||
|
||||
E firstWhere(bool test(E value), {E Function()? orElse}) {
|
||||
for (E element in this) {
|
||||
if (test(element)) return element;
|
||||
}
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
|
||||
E lastWhere(bool test(E value), {E Function()? orElse}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
}
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
|
||||
E singleWhere(bool test(E element), {E Function()? orElse}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
if (foundMatching) {
|
||||
throw IterableElementError.tooMany();
|
||||
}
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
}
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
|
||||
E elementAt(int index) {
|
||||
checkNotNullable(index, "index");
|
||||
RangeError.checkNotNegative(index, "index");
|
||||
int elementIndex = 0;
|
||||
for (E element in this) {
|
||||
if (index == elementIndex) return element;
|
||||
elementIndex++;
|
||||
}
|
||||
throw IndexError.withLength(index, elementIndex,
|
||||
indexable: this, name: "index");
|
||||
}
|
||||
|
||||
String toString() => IterableBase.iterableToShortString(this, '(', ')');
|
||||
}
|
||||
// @Deprecated("Use Iterable instead")
|
||||
typedef IterableMixin<E> = Iterable<E>;
|
||||
|
||||
/// Base class for implementing [Iterable].
|
||||
///
|
||||
/// This class implements all methods of [Iterable], except [Iterable.iterator],
|
||||
/// in terms of `iterator`.
|
||||
abstract class IterableBase<E> extends Iterable<E> {
|
||||
const IterableBase();
|
||||
|
||||
/// Convert an `Iterable` to a string like [IterableBase.toString].
|
||||
///
|
||||
/// Allows using other delimiters than '(' and ')'.
|
||||
///
|
||||
/// Handles circular references where converting one of the elements
|
||||
/// to a string ends up converting [iterable] to a string again.
|
||||
static String iterableToShortString(Iterable iterable,
|
||||
[String leftDelimiter = '(', String rightDelimiter = ')']) {
|
||||
if (_isToStringVisiting(iterable)) {
|
||||
if (leftDelimiter == "(" && rightDelimiter == ")") {
|
||||
// Avoid creating a new string in the "common" case.
|
||||
return "(...)";
|
||||
}
|
||||
return "$leftDelimiter...$rightDelimiter";
|
||||
}
|
||||
List<String> parts = <String>[];
|
||||
_toStringVisiting.add(iterable);
|
||||
try {
|
||||
_iterablePartsToStrings(iterable, parts);
|
||||
} finally {
|
||||
assert(identical(_toStringVisiting.last, iterable));
|
||||
_toStringVisiting.removeLast();
|
||||
}
|
||||
return (StringBuffer(leftDelimiter)
|
||||
..writeAll(parts, ", ")
|
||||
..write(rightDelimiter))
|
||||
.toString();
|
||||
}
|
||||
|
||||
/// Converts an `Iterable` to a string.
|
||||
///
|
||||
/// Converts each elements to a string, and separates the results by ", ".
|
||||
/// Then wraps the result in [leftDelimiter] and [rightDelimiter].
|
||||
///
|
||||
/// Unlike [iterableToShortString], this conversion doesn't omit any
|
||||
/// elements or puts any limit on the size of the result.
|
||||
///
|
||||
/// Handles circular references where converting one of the elements
|
||||
/// to a string ends up converting [iterable] to a string again.
|
||||
static String iterableToFullString(Iterable iterable,
|
||||
[String leftDelimiter = '(', String rightDelimiter = ')']) {
|
||||
if (_isToStringVisiting(iterable)) {
|
||||
return "$leftDelimiter...$rightDelimiter";
|
||||
}
|
||||
StringBuffer buffer = StringBuffer(leftDelimiter);
|
||||
_toStringVisiting.add(iterable);
|
||||
try {
|
||||
buffer.writeAll(iterable, ", ");
|
||||
} finally {
|
||||
assert(identical(_toStringVisiting.last, iterable));
|
||||
_toStringVisiting.removeLast();
|
||||
}
|
||||
buffer.write(rightDelimiter);
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection used to identify cyclic lists during toString() calls.
|
||||
final List<Object> _toStringVisiting = [];
|
||||
|
||||
/// Check if we are currently visiting `o` in a toString call.
|
||||
bool _isToStringVisiting(Object o) {
|
||||
for (int i = 0; i < _toStringVisiting.length; i++) {
|
||||
if (identical(o, _toStringVisiting[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Convert elements of [iterable] to strings and store them in [parts].
|
||||
void _iterablePartsToStrings(Iterable<Object?> iterable, List<String> parts) {
|
||||
/*
|
||||
* This is the complicated part of [iterableToShortString].
|
||||
* It is extracted as a separate function to avoid having too much code
|
||||
* inside the try/finally.
|
||||
*/
|
||||
/// Try to stay below this many characters.
|
||||
const int lengthLimit = 80;
|
||||
|
||||
/// Always at least this many elements at the start.
|
||||
const int headCount = 3;
|
||||
|
||||
/// Always at least this many elements at the end.
|
||||
const int tailCount = 2;
|
||||
|
||||
/// Stop iterating after this many elements. Iterables can be infinite.
|
||||
const int maxCount = 100;
|
||||
// Per entry length overhead. It's for ", " for all after the first entry,
|
||||
// and for "(" and ")" for the initial entry. By pure luck, that's the same
|
||||
// number.
|
||||
const int overhead = 2;
|
||||
const int ellipsisSize = 3; // "...".length.
|
||||
|
||||
int length = 0;
|
||||
int count = 0;
|
||||
Iterator<Object?> it = iterable.iterator;
|
||||
// Initial run of elements, at least headCount, and then continue until
|
||||
// passing at most lengthLimit characters.
|
||||
while (length < lengthLimit || count < headCount) {
|
||||
if (!it.moveNext()) return;
|
||||
String next = "${it.current}";
|
||||
parts.add(next);
|
||||
length += next.length + overhead;
|
||||
count++;
|
||||
}
|
||||
|
||||
String penultimateString;
|
||||
String ultimateString;
|
||||
|
||||
// Find last two elements. One or more of them may already be in the
|
||||
// parts array. Include their length in `length`.
|
||||
if (!it.moveNext()) {
|
||||
if (count <= headCount + tailCount) return;
|
||||
ultimateString = parts.removeLast();
|
||||
penultimateString = parts.removeLast();
|
||||
} else {
|
||||
Object? penultimate = it.current;
|
||||
count++;
|
||||
if (!it.moveNext()) {
|
||||
if (count <= headCount + 1) {
|
||||
parts.add("$penultimate");
|
||||
return;
|
||||
}
|
||||
ultimateString = "$penultimate";
|
||||
penultimateString = parts.removeLast();
|
||||
length += ultimateString.length + overhead;
|
||||
} else {
|
||||
Object? ultimate = it.current;
|
||||
count++;
|
||||
// Then keep looping, keeping the last two elements in variables.
|
||||
assert(count < maxCount);
|
||||
while (it.moveNext()) {
|
||||
penultimate = ultimate;
|
||||
ultimate = it.current;
|
||||
count++;
|
||||
if (count > maxCount) {
|
||||
// If we haven't found the end before maxCount, give up.
|
||||
// This cannot happen in the code above because each entry
|
||||
// increases length by at least two, so there is no way to
|
||||
// visit more than ~40 elements before this loop.
|
||||
|
||||
// Remove any surplus elements until length, including ", ...)",
|
||||
// is at most lengthLimit.
|
||||
while (length > lengthLimit - ellipsisSize - overhead &&
|
||||
count > headCount) {
|
||||
length -= parts.removeLast().length + overhead;
|
||||
count--;
|
||||
}
|
||||
parts.add("...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
penultimateString = "$penultimate";
|
||||
ultimateString = "$ultimate";
|
||||
length += ultimateString.length + penultimateString.length + 2 * overhead;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a gap between the initial run and the last two,
|
||||
// prepare to add an ellipsis.
|
||||
String? elision;
|
||||
if (count > parts.length + tailCount) {
|
||||
elision = "...";
|
||||
length += ellipsisSize + overhead;
|
||||
}
|
||||
|
||||
// If the last two elements were very long, and we have more than
|
||||
// headCount elements in the initial run, drop some to make room for
|
||||
// the last two.
|
||||
while (length > lengthLimit && parts.length > headCount) {
|
||||
length -= parts.removeLast().length + overhead;
|
||||
if (elision == null) {
|
||||
elision = "...";
|
||||
length += ellipsisSize + overhead;
|
||||
}
|
||||
}
|
||||
if (elision != null) {
|
||||
parts.add(elision);
|
||||
}
|
||||
parts.add(penultimateString);
|
||||
parts.add(ultimateString);
|
||||
}
|
||||
// @Deprecated("Use Iterable instead")
|
||||
typedef IterableBase<E> = Iterable<E>;
|
||||
|
||||
@@ -109,14 +109,14 @@ abstract mixin class MapBase<K, V> implements Map<K, V> {
|
||||
String toString() => mapToString(this);
|
||||
|
||||
static String mapToString(Map<Object?, Object?> m) {
|
||||
// Reuses the list in IterableBase for detecting toString cycles.
|
||||
if (_isToStringVisiting(m)) {
|
||||
// Reuses the list used by Iterable for detecting toString cycles.
|
||||
if (isToStringVisiting(m)) {
|
||||
return '{...}';
|
||||
}
|
||||
|
||||
var result = StringBuffer();
|
||||
try {
|
||||
_toStringVisiting.add(m);
|
||||
toStringVisiting.add(m);
|
||||
result.write('{');
|
||||
bool first = true;
|
||||
m.forEach((Object? k, Object? v) {
|
||||
@@ -130,8 +130,8 @@ abstract mixin class MapBase<K, V> implements Map<K, V> {
|
||||
});
|
||||
result.write('}');
|
||||
} finally {
|
||||
assert(identical(_toStringVisiting.last, m));
|
||||
_toStringVisiting.removeLast();
|
||||
assert(identical(toStringVisiting.last, m));
|
||||
toStringVisiting.removeLast();
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
|
||||
@@ -483,7 +483,7 @@ final class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> {
|
||||
return _DoubleLinkedQueueIterator<E>(this);
|
||||
}
|
||||
|
||||
String toString() => IterableBase.iterableToFullString(this, '{', '}');
|
||||
String toString() => Iterable.iterableToFullString(this, '{', '}');
|
||||
}
|
||||
|
||||
class _DoubleLinkedQueueIterator<E> implements Iterator<E> {
|
||||
@@ -803,7 +803,7 @@ final class ListQueue<E> extends ListIterable<E> implements Queue<E> {
|
||||
}
|
||||
}
|
||||
|
||||
String toString() => IterableBase.iterableToFullString(this, "{", "}");
|
||||
String toString() => Iterable.iterableToFullString(this, "{", "}");
|
||||
|
||||
// Queue interface.
|
||||
|
||||
|
||||
+40
-34
@@ -133,6 +133,7 @@ abstract mixin class SetBase<E> implements Set<E> {
|
||||
|
||||
// Copied from Iterable.
|
||||
// Should be inherited if we had multi-level mixins.
|
||||
|
||||
Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
|
||||
|
||||
Iterable<T> expand<T>(Iterable<T> f(E element)) =>
|
||||
@@ -170,17 +171,20 @@ abstract mixin class SetBase<E> implements Set<E> {
|
||||
String join([String separator = ""]) {
|
||||
Iterator<E> iterator = this.iterator;
|
||||
if (!iterator.moveNext()) return "";
|
||||
StringBuffer buffer = StringBuffer();
|
||||
if (separator == null || separator == "") {
|
||||
var first = iterator.current.toString();
|
||||
if (!iterator.moveNext()) return first;
|
||||
var buffer = StringBuffer(first);
|
||||
// TODO(51681): Drop null check when de-supporting pre-2.12 code.
|
||||
if (separator == null || separator.isEmpty) {
|
||||
do {
|
||||
buffer.write(iterator.current);
|
||||
} while (iterator.moveNext());
|
||||
} else {
|
||||
buffer.write(iterator.current);
|
||||
while (iterator.moveNext()) {
|
||||
buffer.write(separator);
|
||||
buffer.write(iterator.current);
|
||||
}
|
||||
do {
|
||||
buffer
|
||||
..write(separator)
|
||||
..write(iterator.current);
|
||||
} while (iterator.moveNext());
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
@@ -237,45 +241,47 @@ abstract mixin class SetBase<E> implements Set<E> {
|
||||
}
|
||||
|
||||
E lastWhere(bool test(E value), {E Function()? orElse}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
var iterator = this.iterator;
|
||||
E result;
|
||||
do {
|
||||
if (!iterator.moveNext()) {
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
result = iterator.current;
|
||||
} while (!test(result));
|
||||
while (iterator.moveNext()) {
|
||||
var current = iterator.current;
|
||||
if (test(current)) result = current;
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
return result;
|
||||
}
|
||||
|
||||
E singleWhere(bool test(E value), {E Function()? orElse}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
if (foundMatching) {
|
||||
throw IterableElementError.tooMany();
|
||||
}
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
var iterator = this.iterator;
|
||||
E result;
|
||||
do {
|
||||
if (!iterator.moveNext()) {
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
result = iterator.current;
|
||||
} while (!test(result));
|
||||
while (iterator.moveNext()) {
|
||||
if (test(iterator.current)) throw IterableElementError.tooMany();
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
return result;
|
||||
}
|
||||
|
||||
E elementAt(int index) {
|
||||
checkNotNullable(index, "index");
|
||||
RangeError.checkNotNegative(index, "index");
|
||||
int elementIndex = 0;
|
||||
for (E element in this) {
|
||||
if (index == elementIndex) return element;
|
||||
elementIndex++;
|
||||
var iterator = this.iterator;
|
||||
var skipCount = index;
|
||||
while (iterator.moveNext()) {
|
||||
if (skipCount == 0) return iterator.current;
|
||||
skipCount--;
|
||||
}
|
||||
throw IndexError.withLength(index, elementIndex,
|
||||
throw IndexError.withLength(index, index - skipCount,
|
||||
indexable: this, name: "index");
|
||||
}
|
||||
|
||||
|
||||
@@ -947,7 +947,7 @@ class _SplayTreeMapEntryIterator<K, V>
|
||||
/// * [HashSet] the order of the objects in the iterations is not guaranteed.
|
||||
/// * [LinkedHashSet] objects stored based on insertion order.
|
||||
final class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeSetNode<E>>
|
||||
with IterableMixin<E>, SetMixin<E> {
|
||||
with Iterable<E>, SetMixin<E> {
|
||||
_SplayTreeSetNode<E>? _root;
|
||||
|
||||
Comparator<E> _compare;
|
||||
@@ -1188,5 +1188,5 @@ final class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeSetNode<E>>
|
||||
|
||||
Set<E> toSet() => _clone();
|
||||
|
||||
String toString() => IterableBase.iterableToFullString(this, '{', '}');
|
||||
String toString() => Iterable.iterableToFullString(this, '{', '}');
|
||||
}
|
||||
|
||||
+264
-76
@@ -81,9 +81,19 @@ part of dart.core;
|
||||
/// For methods like [map] and [where], the returned iterable will execute the
|
||||
/// argument function on every iteration, so those functions should also not
|
||||
/// have side effects.
|
||||
abstract class Iterable<E> {
|
||||
// TODO(lrn): When we allow forwarding const constructors through
|
||||
// mixin applications, make this class implement [IterableMixin].
|
||||
///
|
||||
/// The `Iterable` declaration provides a default implementation,
|
||||
/// which can be extended or mixed in to implement the `Iterable` interface.
|
||||
/// It implements every member other than the [iterator] getter,
|
||||
/// using the [Iterator] provided by [iterator].
|
||||
/// An implementation of the `Iterable` interface should
|
||||
/// provide a more efficient implementation of the members of `Iterable`
|
||||
/// when it can do so.
|
||||
abstract mixin class Iterable<E> {
|
||||
// This class has methods copied verbatim into:
|
||||
// - SetMixin
|
||||
// If changing a method here, also change other copies.
|
||||
|
||||
const Iterable();
|
||||
|
||||
/// Creates an `Iterable` which generates its elements dynamically.
|
||||
@@ -100,7 +110,19 @@ abstract class Iterable<E> {
|
||||
/// As an `Iterable`, `Iterable.generate(n, generator))` is equivalent to
|
||||
/// `const [0, ..., n - 1].map(generator)`.
|
||||
factory Iterable.generate(int count, [E generator(int index)?]) {
|
||||
// Always OK to omit generator when count is zero.
|
||||
if (count <= 0) return EmptyIterable<E>();
|
||||
if (generator == null) {
|
||||
// If generator is omitted, we generate integers.
|
||||
// If `E` does not allow integers, it's an error.
|
||||
Function id = _GeneratorIterable._id;
|
||||
if (id is! E Function(int)) {
|
||||
throw ArgumentError(
|
||||
"Generator must be supplied or element type must allow integers",
|
||||
"generator");
|
||||
}
|
||||
generator = id;
|
||||
}
|
||||
return _GeneratorIterable<E>(count, generator);
|
||||
}
|
||||
|
||||
@@ -119,8 +141,7 @@ abstract class Iterable<E> {
|
||||
static Iterable<T> castFrom<S, T>(Iterable<S> source) =>
|
||||
CastIterable<S, T>(source);
|
||||
|
||||
/// Returns a new `Iterator` that allows iterating the elements of this
|
||||
/// `Iterable`.
|
||||
/// A new `Iterator` that allows iterating the elements of this `Iterable`.
|
||||
///
|
||||
/// Iterable classes may specify the iteration order of their elements
|
||||
/// (for example [List] always iterate in index order),
|
||||
@@ -147,7 +168,7 @@ abstract class Iterable<E> {
|
||||
/// break iteration.
|
||||
Iterator<E> get iterator;
|
||||
|
||||
/// Provides a view of this iterable as an iterable of [R] instances.
|
||||
/// A view of this iterable as an iterable of [R] instances.
|
||||
///
|
||||
/// If this iterable only contains instances of [R], all operations
|
||||
/// will work correctly. If any operation tries to access an element
|
||||
@@ -155,9 +176,9 @@ abstract class Iterable<E> {
|
||||
///
|
||||
/// When the returned iterable creates a new object that depends on
|
||||
/// the type [R], e.g., from [toList], it will have exactly the type [R].
|
||||
Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
|
||||
Iterable<R> cast<R>() => CastIterable<E, R>(this);
|
||||
|
||||
/// Returns the lazy concatenation of this iterable and [other].
|
||||
/// Creates the lazy concatenation of this iterable and [other].
|
||||
///
|
||||
/// The returned iterable will provide the same elements as this iterable,
|
||||
/// and, after that, the elements of [other], in the same order as in the
|
||||
@@ -216,7 +237,7 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
Iterable<T> map<T>(T toElement(E e)) => MappedIterable<E, T>(this, toElement);
|
||||
|
||||
/// Returns a new lazy [Iterable] with all elements that satisfy the
|
||||
/// Creates a new lazy [Iterable] with all elements that satisfy the
|
||||
/// predicate [test].
|
||||
///
|
||||
/// The matching elements have the same order in the returned iterable
|
||||
@@ -238,7 +259,7 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
|
||||
|
||||
/// Returns a new lazy [Iterable] with all elements that have type [T].
|
||||
/// Creates a new lazy [Iterable] with all elements that have type [T].
|
||||
///
|
||||
/// The matching elements have the same order in the returned iterable
|
||||
/// as they have in [iterator].
|
||||
@@ -421,17 +442,20 @@ abstract class Iterable<E> {
|
||||
String join([String separator = ""]) {
|
||||
Iterator<E> iterator = this.iterator;
|
||||
if (!iterator.moveNext()) return "";
|
||||
StringBuffer buffer = StringBuffer();
|
||||
if (separator == null || separator == "") {
|
||||
var first = iterator.current.toString();
|
||||
if (!iterator.moveNext()) return first;
|
||||
var buffer = StringBuffer(first);
|
||||
// TODO(51681): Drop null check when de-supporting pre-2.12 code.
|
||||
if (separator == null || separator.isEmpty) {
|
||||
do {
|
||||
buffer.write(iterator.current.toString());
|
||||
} while (iterator.moveNext());
|
||||
} else {
|
||||
buffer.write(iterator.current.toString());
|
||||
while (iterator.moveNext()) {
|
||||
buffer.write(separator);
|
||||
buffer.write(iterator.current.toString());
|
||||
}
|
||||
do {
|
||||
buffer
|
||||
..write(separator)
|
||||
..write(iterator.current.toString());
|
||||
} while (iterator.moveNext());
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
@@ -466,9 +490,8 @@ abstract class Iterable<E> {
|
||||
/// final valuesList =
|
||||
/// planets.values.toList(growable: false); // [Mercury, Venus, Mars]
|
||||
/// ```
|
||||
List<E> toList({bool growable = true}) {
|
||||
return List<E>.of(this, growable: growable);
|
||||
}
|
||||
List<E> toList({bool growable = true}) =>
|
||||
List<E>.of(this, growable: growable);
|
||||
|
||||
/// Creates a [Set] containing the same elements as this iterable.
|
||||
///
|
||||
@@ -485,15 +508,16 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
Set<E> toSet() => Set<E>.of(this);
|
||||
|
||||
/// Returns the number of elements in [this].
|
||||
/// The number of elements in [this].
|
||||
///
|
||||
/// Counting all elements may involve iterating through all elements and can
|
||||
/// therefore be slow.
|
||||
/// Some iterables have a more efficient way to find the number of elements.
|
||||
/// These *must* override the default implementation of `length`.
|
||||
int get length {
|
||||
assert(this is! EfficientLengthIterable);
|
||||
int count = 0;
|
||||
Iterator it = iterator;
|
||||
Iterator<Object?> it = iterator;
|
||||
while (it.moveNext()) {
|
||||
count++;
|
||||
}
|
||||
@@ -524,7 +548,7 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
|
||||
/// Returns a lazy iterable of the [count] first elements of this iterable.
|
||||
/// Creates a lazy iterable of the [count] first elements of this iterable.
|
||||
///
|
||||
/// The returned `Iterable` may contain fewer than `count` elements, if `this`
|
||||
/// contains fewer than `count` elements.
|
||||
@@ -540,11 +564,9 @@ abstract class Iterable<E> {
|
||||
/// final result = numbers.take(4); // (1, 2, 3, 5)
|
||||
/// final takeAll = numbers.take(100); // (1, 2, 3, 5, 6, 7)
|
||||
/// ```
|
||||
Iterable<E> take(int count) {
|
||||
return TakeIterable<E>(this, count);
|
||||
}
|
||||
Iterable<E> take(int count) => TakeIterable<E>(this, count);
|
||||
|
||||
/// Returns a lazy iterable of the leading elements satisfying [test].
|
||||
/// Creates a lazy iterable of the leading elements satisfying [test].
|
||||
///
|
||||
/// The filtering happens lazily. Every new iterator of the returned
|
||||
/// iterable starts iterating over the elements of `this`.
|
||||
@@ -561,11 +583,9 @@ abstract class Iterable<E> {
|
||||
/// result = numbers.takeWhile((x) => x != 4); // (1, 2, 3, 5, 6, 7)
|
||||
/// result = numbers.takeWhile((x) => x.isOdd); // (1)
|
||||
/// ```
|
||||
Iterable<E> takeWhile(bool test(E value)) {
|
||||
return TakeWhileIterable<E>(this, test);
|
||||
}
|
||||
Iterable<E> takeWhile(bool test(E value)) => TakeWhileIterable<E>(this, test);
|
||||
|
||||
/// Returns an [Iterable] that provides all but the first [count] elements.
|
||||
/// Creates an [Iterable] that provides all but the first [count] elements.
|
||||
///
|
||||
/// When the returned iterable is iterated, it starts iterating over `this`,
|
||||
/// first skipping past the initial [count] elements.
|
||||
@@ -586,11 +606,9 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
///
|
||||
/// The [count] must not be negative.
|
||||
Iterable<E> skip(int count) {
|
||||
return SkipIterable<E>(this, count);
|
||||
}
|
||||
Iterable<E> skip(int count) => SkipIterable<E>(this, count);
|
||||
|
||||
/// Returns an `Iterable` that skips leading elements while [test] is satisfied.
|
||||
/// Creates an `Iterable` that skips leading elements while [test] is satisfied.
|
||||
///
|
||||
/// The filtering happens lazily. Every new [Iterator] of the returned
|
||||
/// iterable iterates over all elements of `this`.
|
||||
@@ -609,11 +627,9 @@ abstract class Iterable<E> {
|
||||
/// result = numbers.skipWhile((x) => x != 4); // ()
|
||||
/// result = numbers.skipWhile((x) => x.isOdd); // (2, 3, 5, 6, 7)
|
||||
/// ```
|
||||
Iterable<E> skipWhile(bool test(E value)) {
|
||||
return SkipWhileIterable<E>(this, test);
|
||||
}
|
||||
Iterable<E> skipWhile(bool test(E value)) => SkipWhileIterable<E>(this, test);
|
||||
|
||||
/// Returns the first element.
|
||||
/// The first element.
|
||||
///
|
||||
/// Throws a [StateError] if `this` is empty.
|
||||
/// Otherwise returns the first element in the iteration order,
|
||||
@@ -626,7 +642,7 @@ abstract class Iterable<E> {
|
||||
return it.current;
|
||||
}
|
||||
|
||||
/// Returns the last element.
|
||||
/// The last element.
|
||||
///
|
||||
/// Throws a [StateError] if `this` is empty.
|
||||
/// Otherwise may iterate through the elements and returns the last one
|
||||
@@ -657,7 +673,7 @@ abstract class Iterable<E> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns the first element that satisfies the given predicate [test].
|
||||
/// The first element that satisfies the given predicate [test].
|
||||
///
|
||||
/// Iterates through elements and returns the first to satisfy [test].
|
||||
///
|
||||
@@ -681,7 +697,7 @@ abstract class Iterable<E> {
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
|
||||
/// Returns the last element that satisfies the given predicate [test].
|
||||
/// The last element that satisfies the given predicate [test].
|
||||
///
|
||||
/// An iterable that can access its elements directly may check its
|
||||
/// elements in any order (for example a list starts by checking the
|
||||
@@ -703,20 +719,25 @@ abstract class Iterable<E> {
|
||||
/// function is returned.
|
||||
/// If [orElse] is omitted, it defaults to throwing a [StateError].
|
||||
E lastWhere(bool test(E element), {E orElse()?}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
var iterator = this.iterator;
|
||||
// Potential result during first loop.
|
||||
E result;
|
||||
do {
|
||||
if (!iterator.moveNext()) {
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
result = iterator.current;
|
||||
} while (!test(result));
|
||||
// Now `result` is actual result, unless a later one is found.
|
||||
while (iterator.moveNext()) {
|
||||
var current = iterator.current;
|
||||
if (test(current)) result = current;
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns the single element that satisfies [test].
|
||||
/// The single element that satisfies [test].
|
||||
///
|
||||
/// Checks elements to see if `test(element)` returns true.
|
||||
/// If exactly one element satisfies [test], that element is returned.
|
||||
@@ -740,20 +761,19 @@ abstract class Iterable<E> {
|
||||
/// result = numbers.singleWhere((element) => element == 2); // Throws Error.
|
||||
/// ```
|
||||
E singleWhere(bool test(E element), {E orElse()?}) {
|
||||
late E result;
|
||||
bool foundMatching = false;
|
||||
for (E element in this) {
|
||||
if (test(element)) {
|
||||
if (foundMatching) {
|
||||
throw IterableElementError.tooMany();
|
||||
}
|
||||
result = element;
|
||||
foundMatching = true;
|
||||
var iterator = this.iterator;
|
||||
E result;
|
||||
do {
|
||||
if (!iterator.moveNext()) {
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
}
|
||||
result = iterator.current;
|
||||
} while (!test(result));
|
||||
while (iterator.moveNext()) {
|
||||
if (test(iterator.current)) throw IterableElementError.tooMany();
|
||||
}
|
||||
if (foundMatching) return result;
|
||||
if (orElse != null) return orElse();
|
||||
throw IterableElementError.noElement();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns the [index]th element.
|
||||
@@ -773,12 +793,13 @@ abstract class Iterable<E> {
|
||||
/// ```
|
||||
E elementAt(int index) {
|
||||
RangeError.checkNotNegative(index, "index");
|
||||
int elementIndex = 0;
|
||||
for (E element in this) {
|
||||
if (index == elementIndex) return element;
|
||||
elementIndex++;
|
||||
var iterator = this.iterator;
|
||||
var skipCount = index;
|
||||
while (iterator.moveNext()) {
|
||||
if (skipCount == 0) return iterator.current;
|
||||
skipCount--;
|
||||
}
|
||||
throw IndexError.withLength(index, elementIndex,
|
||||
throw IndexError.withLength(index, index - skipCount,
|
||||
indexable: this, name: "index");
|
||||
}
|
||||
|
||||
@@ -796,10 +817,69 @@ abstract class Iterable<E> {
|
||||
/// The conversion may omit calling `toString` on some elements if they
|
||||
/// are known to not occur in the output, and it may stop iterating after
|
||||
/// a hundred elements.
|
||||
String toString() => IterableBase.iterableToShortString(this, '(', ')');
|
||||
String toString() => iterableToShortString(this, '(', ')');
|
||||
|
||||
/// Convert an `Iterable` to a string like [Iterable.toString].
|
||||
///
|
||||
/// Allows using other delimiters than '(' and ')'.
|
||||
///
|
||||
/// Handles circular references where converting one of the elements
|
||||
/// to a string ends up converting [iterable] to a string again.
|
||||
static String iterableToShortString(Iterable iterable,
|
||||
[String leftDelimiter = '(', String rightDelimiter = ')']) {
|
||||
if (isToStringVisiting(iterable)) {
|
||||
if (leftDelimiter == "(" && rightDelimiter == ")") {
|
||||
// Avoid creating a new string in the "common" case.
|
||||
return "(...)";
|
||||
}
|
||||
return "$leftDelimiter...$rightDelimiter";
|
||||
}
|
||||
List<String> parts = <String>[];
|
||||
toStringVisiting.add(iterable);
|
||||
try {
|
||||
_iterablePartsToStrings(iterable, parts);
|
||||
} finally {
|
||||
assert(identical(toStringVisiting.last, iterable));
|
||||
toStringVisiting.removeLast();
|
||||
}
|
||||
return (StringBuffer(leftDelimiter)
|
||||
..writeAll(parts, ", ")
|
||||
..write(rightDelimiter))
|
||||
.toString();
|
||||
}
|
||||
|
||||
/// Converts an `Iterable` to a string.
|
||||
///
|
||||
/// Converts each elements to a string, and separates the results by ", ".
|
||||
/// Then wraps the result in [leftDelimiter] and [rightDelimiter].
|
||||
///
|
||||
/// Unlike [iterableToShortString], this conversion doesn't omit any
|
||||
/// elements or puts any limit on the size of the result.
|
||||
///
|
||||
/// Handles circular references where converting one of the elements
|
||||
/// to a string ends up converting [iterable] to a string again.
|
||||
static String iterableToFullString(Iterable iterable,
|
||||
[String leftDelimiter = '(', String rightDelimiter = ')']) {
|
||||
if (isToStringVisiting(iterable)) {
|
||||
return "$leftDelimiter...$rightDelimiter";
|
||||
}
|
||||
StringBuffer buffer = StringBuffer(leftDelimiter);
|
||||
toStringVisiting.add(iterable);
|
||||
try {
|
||||
buffer.writeAll(iterable, ", ");
|
||||
} finally {
|
||||
assert(identical(toStringVisiting.last, iterable));
|
||||
toStringVisiting.removeLast();
|
||||
}
|
||||
buffer.write(rightDelimiter);
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class _GeneratorIterable<E> extends ListIterable<E> {
|
||||
// Methods have efficient implementations from `ListIterable`,
|
||||
// based on `length` and `elementAt`.
|
||||
|
||||
/// The length of the generated iterable.
|
||||
final int length;
|
||||
|
||||
@@ -807,12 +887,7 @@ class _GeneratorIterable<E> extends ListIterable<E> {
|
||||
final E Function(int) _generator;
|
||||
|
||||
/// Creates the generated iterable.
|
||||
///
|
||||
/// If [generator] is `null`, it is checked that `int` is assignable to [E].
|
||||
_GeneratorIterable(this.length, E generator(int index)?)
|
||||
: // The `as` below is used as check to make sure that `int` is assignable
|
||||
// to [E].
|
||||
_generator = generator ?? (_id as E Function(int));
|
||||
_GeneratorIterable(this.length, this._generator);
|
||||
|
||||
E elementAt(int index) {
|
||||
IndexError.check(index, length, indexable: this);
|
||||
@@ -822,3 +897,116 @@ class _GeneratorIterable<E> extends ListIterable<E> {
|
||||
/// Helper function used as default _generator function.
|
||||
static int _id(int n) => n;
|
||||
}
|
||||
|
||||
/// Convert elements of [iterable] to strings and store them in [parts].
|
||||
void _iterablePartsToStrings(Iterable<Object?> iterable, List<String> parts) {
|
||||
// This is the complicated part of [iterableToShortString].
|
||||
// It is extracted as a separate function to avoid having too much code
|
||||
// inside the try/finally.
|
||||
|
||||
// Try to stay below this many characters.
|
||||
const int lengthLimit = 80;
|
||||
|
||||
// Always at least this many elements at the start.
|
||||
const int headCount = 3;
|
||||
|
||||
// Always at least this many elements at the end.
|
||||
const int tailCount = 2;
|
||||
|
||||
// Stop iterating after this many elements. Iterables can be infinite.
|
||||
const int maxCount = 100;
|
||||
// Per entry length overhead. It's for ", " for all after the first entry,
|
||||
// and for "(" and ")" for the initial entry. By pure luck, that's the same
|
||||
// number.
|
||||
const int overhead = 2;
|
||||
const int ellipsisSize = 3; // "...".length.
|
||||
|
||||
int length = 0;
|
||||
int count = 0;
|
||||
Iterator<Object?> it = iterable.iterator;
|
||||
// Initial run of elements, at least headCount, and then continue until
|
||||
// passing at most lengthLimit characters.
|
||||
while (length < lengthLimit || count < headCount) {
|
||||
if (!it.moveNext()) return;
|
||||
String next = "${it.current}";
|
||||
parts.add(next);
|
||||
length += next.length + overhead;
|
||||
count++;
|
||||
}
|
||||
|
||||
String penultimateString;
|
||||
String ultimateString;
|
||||
|
||||
// Find last two elements. One or more of them may already be in the
|
||||
// parts array. Include their length in `length`.
|
||||
if (!it.moveNext()) {
|
||||
if (count <= headCount + tailCount) return;
|
||||
ultimateString = parts.removeLast();
|
||||
penultimateString = parts.removeLast();
|
||||
} else {
|
||||
Object? penultimate = it.current;
|
||||
count++;
|
||||
if (!it.moveNext()) {
|
||||
if (count <= headCount + 1) {
|
||||
parts.add("$penultimate");
|
||||
return;
|
||||
}
|
||||
ultimateString = "$penultimate";
|
||||
penultimateString = parts.removeLast();
|
||||
length += ultimateString.length + overhead;
|
||||
} else {
|
||||
Object? ultimate = it.current;
|
||||
count++;
|
||||
// Then keep looping, keeping the last two elements in variables.
|
||||
assert(count < maxCount);
|
||||
while (it.moveNext()) {
|
||||
penultimate = ultimate;
|
||||
ultimate = it.current;
|
||||
count++;
|
||||
if (count > maxCount) {
|
||||
// If we haven't found the end before maxCount, give up.
|
||||
// This cannot happen in the code above because each entry
|
||||
// increases length by at least two, so there is no way to
|
||||
// visit more than ~40 elements before this loop.
|
||||
|
||||
// Remove any surplus elements until length, including ", ...)",
|
||||
// is at most lengthLimit.
|
||||
while (length > lengthLimit - ellipsisSize - overhead &&
|
||||
count > headCount) {
|
||||
length -= parts.removeLast().length + overhead;
|
||||
count--;
|
||||
}
|
||||
parts.add("...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
penultimateString = "$penultimate";
|
||||
ultimateString = "$ultimate";
|
||||
length += ultimateString.length + penultimateString.length + 2 * overhead;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a gap between the initial run and the last two,
|
||||
// prepare to add an ellipsis.
|
||||
String? elision;
|
||||
if (count > parts.length + tailCount) {
|
||||
elision = "...";
|
||||
length += ellipsisSize + overhead;
|
||||
}
|
||||
|
||||
// If the last two elements were very long, and we have more than
|
||||
// headCount elements in the initial run, drop some to make room for
|
||||
// the last two.
|
||||
while (length > lengthLimit && parts.length > headCount) {
|
||||
length -= parts.removeLast().length + overhead;
|
||||
if (elision == null) {
|
||||
elision = "...";
|
||||
length += ellipsisSize + overhead;
|
||||
}
|
||||
}
|
||||
if (elision != null) {
|
||||
parts.add(elision);
|
||||
}
|
||||
parts.add(penultimateString);
|
||||
parts.add(ultimateString);
|
||||
}
|
||||
|
||||
@@ -1040,3 +1040,16 @@ class DoubleLinkedQueueEntry<E> {
|
||||
/// through scheduled events or timers, which would put the object into
|
||||
/// an inconsistent state if simply being copied.
|
||||
const vmIsolateUnsendable = pragma("vm:isolate-unsendable");
|
||||
|
||||
// Helpers used to detect cycles in collection `toString`s.
|
||||
|
||||
/// A collection used to identify cyclic lists during `toString` calls.
|
||||
final List<Object> toStringVisiting = [];
|
||||
|
||||
/// Check if we are currently visiting [object] in a `toString` call.
|
||||
bool isToStringVisiting(Object object) {
|
||||
for (int i = 0; i < toStringVisiting.length; i++) {
|
||||
if (identical(object, toStringVisiting[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
part of dart._internal;
|
||||
|
||||
/// A rudimentary linked list.
|
||||
class LinkedList<T extends LinkedListEntry<T>> extends IterableBase<T> {
|
||||
class LinkedList<T extends LinkedListEntry<T>> extends Iterable<T> {
|
||||
T get first => _first as T;
|
||||
T? _first;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
part of dart._vmservice;
|
||||
|
||||
/// Set like contains which automatically generated String ids for its items
|
||||
class NamedLookup<E extends Object> extends Object with IterableMixin<E> {
|
||||
class NamedLookup<E extends Object> extends Iterable<E> {
|
||||
final IdGenerator _generator;
|
||||
final _elements = <String, E>{};
|
||||
final _ids = <E, String>{};
|
||||
|
||||
Reference in New Issue
Block a user