Add static list methods.

Change-Id: I40574d695826a3ed038c7c756ce980fae001325d
Reviewed-on: https://dart-review.googlesource.com/43040
Reviewed-by: Leaf Petersen <leafp@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2018-02-26 11:34:43 +00:00 committed by commit-bot@chromium.org
parent 790a34b9f0
commit 8d38d94ddb
4 changed files with 254 additions and 1 deletions

View file

@ -90,7 +90,8 @@ the assignment to `y`.
`whereType`.
* `Iterable.singleWhere` added `orElse` parameter.
* `List` added `+` operator, `first` and `last` setters, and `indexWhere`
and `lastIndexWhere` methods.
and `lastIndexWhere` methods, and static `copyRange` and `writeIterable`
methods.
* `Map` added `fromEntries` constructor.
* `Map` added `addEntries`, `cast`, `entries`, `map`, `removeWhere`,
`retype`, `update` and `updateAll` members.

View file

@ -171,6 +171,68 @@ abstract class List<E> implements EfficientLengthIterable<E> {
*/
static List<T> castFrom<S, T>(List<S> source) => new CastList<S, T>(source);
/**
* Copy a range of one list into another list.
*
* This is a utility function that can be used to implement methods like
* [setRange].
*
* The range from [start] to [end] must be a valid range of [source],
* and there must be room for `end - start` elements from position [at].
* If [start] is omitted, it defaults to zero.
* If [end] is omitted, it defaults to [source.length].
*
* If [source] and [target] is the same list, overlapping source and target
* ranges are respected so that the target range ends up containing the
* initial content of the source range.
* Otherwise the order of element copying is not guaranteed.
*/
static void copyRange<T>(List<T> target, int at, List<T> source,
[int start, int end]) {
start ??= 0;
end = RangeError.checkValidRange(start, end, source.length);
int length = end - start;
if (target.length < at + length) {
throw new ArgumentError.value(target, "target",
"Not big enough to hold $length elements at position $at");
}
if (!identical(source, target) || start >= at) {
for (int i = 0; i < length; i++) {
target[at + i] = source[start + i];
}
} else {
for (int i = length; --i >= 0;) {
target[at + i] = source[start + i];
}
}
}
/**
* Write the elements of an iterable into a list.
*
* This is a utility function that can be used to implement methods like
* [setAll].
*
* The elements of [source] are written into [target] from position [at].
* The [source] must not contain more elements after writing the last
* position of [target].
*
* If the source is a list, the [copyRange] function is likely to be more
* efficient.
*/
static void writeIterable<T>(List<T> target, int at, Iterable<T> source) {
RangeError.checkValueInInterval(at, 0, target.length, "at");
int index = at;
int targetLength = target.length;
for (var element in source) {
if (index == targetLength) {
throw new IndexError(targetLength, target);
}
target[index] = element;
index++;
}
}
/**
* Returns a view of this list as a list of [R] instances, if necessary.
*

View file

@ -0,0 +1,115 @@
// 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:typed_data";
import "package:expect/expect.dart";
// Tests of List.copyRange.
void main() {
var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
List.copyRange(list, 3, [10, 11, 12, 13], 0, 4);
Expect.listEquals([0, 1, 2, 10, 11, 12, 13, 7, 8, 9], list);
List.copyRange(list, 6, [20, 21, 22, 23], 1, 3);
Expect.listEquals([0, 1, 2, 10, 11, 12, 21, 22, 8, 9], list);
// Empty ranges won't change anything.
List.copyRange(list, 7, [30, 31, 32, 33], 3, 3);
List.copyRange(list, list.length, [30, 31, 32, 33], 3, 3);
Expect.listEquals([0, 1, 2, 10, 11, 12, 21, 22, 8, 9], list);
List.copyRange(list, 0, [40, 41, 42, 43], 0, 2);
Expect.listEquals([40, 41, 2, 10, 11, 12, 21, 22, 8, 9], list);
// Overlapping self-ranges
List.copyRange(list, 2, list, 0, 4);
Expect.listEquals([40, 41, 40, 41, 2, 10, 21, 22, 8, 9], list);
List.copyRange(list, 4, list, 6, 10);
Expect.listEquals([40, 41, 40, 41, 21, 22, 8, 9, 8, 9], list);
// Invalid source ranges.
Expect.throwsArgumentError(() {
List.copyRange(list, 0, [0, 0, 0], -1, 1);
});
Expect.throwsArgumentError(() {
List.copyRange(list, 0, [0, 0, 0], 0, 4);
});
Expect.throwsArgumentError(() {
List.copyRange(list, 0, [0, 0, 0], 2, 1);
});
Expect.throwsArgumentError(() {
List.copyRange(list, 0, [], 1, 1);
});
// Invalid target range.
Expect.throwsArgumentError(() {
List.copyRange(list, list.length - 3, [0, 0, 0, 0], 0, 4);
});
// Invalid target range.
Expect.throwsArgumentError(() {
List.copyRange(list, list.length + 1, [0, 0, 0, 0], 0, 0);
});
// Argument errors throw before changing anything, so list is unchanged.
Expect.listEquals([40, 41, 40, 41, 21, 22, 8, 9, 8, 9], list);
// Omitting start/end (or passing null).
List.copyRange(list, 2, [1, 2, 3]);
Expect.listEquals([40, 41, 1, 2, 3, 22, 8, 9, 8, 9], list);
List.copyRange(list, 5, [1, 2, 3], 1);
Expect.listEquals([40, 41, 1, 2, 3, 2, 3, 9, 8, 9], list);
// Other kinds of lists.
var listu8 = new Uint8List.fromList([1, 2, 3, 4]);
var list16 = new Int16List.fromList([11, 12, -13, -14]);
List.copyRange(listu8, 2, list16, 1, 3);
Expect.listEquals([1, 2, 12, 256 - 13], listu8);
var clist = const <int>[1, 2, 3, 4];
var flist = new List<int>(4)..setAll(0, [10, 11, 12, 13]);
List.copyRange(flist, 1, clist, 1, 3);
Expect.listEquals([10, 2, 3, 13], flist);
// Invoking with a type parameter that is a supertype of the list types
// is valid and useful.
List<int> ilist = <int>[1, 2, 3, 4];
List<num> nlist = <num>[11, 12, 13, 14];
List.copyRange<num>(ilist, 1, nlist, 1, 3);
Expect.listEquals([1, 12, 13, 4], ilist);
List.copyRange<Object>(ilist, 1, nlist, 0, 2);
Expect.listEquals([1, 11, 12, 4], ilist);
List.copyRange<dynamic>(ilist, 1, nlist, 2, 4);
Expect.listEquals([1, 13, 14, 4], ilist);
var d = new D();
List<B> bdlist = <B>[d];
List<C> cdlist = <C>[null];
List.copyRange<Object>(cdlist, 0, bdlist, 0, 1);
Expect.identical(d, cdlist[0]);
}
class B {}
class C {}
class D implements B, C {}

View file

@ -0,0 +1,75 @@
// 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:typed_data";
import "package:expect/expect.dart";
void main() {
test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]);
test([1, 2, 3, 4], [5, 6], 0, [5, 6, 3, 4]);
test([1, 2, 3, 4], [5, 6], 1, [1, 5, 6, 4]);
test([1, 2, 3, 4], [], 2, [1, 2, 3, 4]);
test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]);
test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]);
test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]);
test([], [], 0, []);
test([1], [2], 0, [2]);
// Other (non-list) iterables.
test([1, 2, 3, 4], new Iterable.generate(2, (x) => x + 7), 1, [1, 7, 8, 4]);
test([1, 2, 3, 4], [9, 9, 5, 6].skip(2), 1, [1, 5, 6, 4]);
test([1, 2, 3, 4], [5, 6, 9, 9].take(2), 1, [1, 5, 6, 4]);
test([1, 2, 3, 4], [9, 5, 9, 6, 9, 9].where((x) => x != 9), 1, [1, 5, 6, 4]);
test([1, 2, 3, 4], new Set.from([5, 6]), 1, [1, 5, 6, 4]);
// Other types of lists.
test(new Uint8List(4), [5, 6], 1, [0, 5, 6, 0]);
test(new Uint8List(4), [-5, 6], 1, [0, 256 - 5, 6, 0]);
// Over-long iterables. Updates until end, then throws.
testThrows([], [1], 0);
testThrows([2], [1], 1);
testThrows([2], [1], 1);
testThrows([1, 2, 3, 4], [5, 6, 7, 8], 2, [1, 2, 5, 6]);
// Throwing iterable.
Expect.throws(() {
Iterable<int> throwingIterable() sync* {
yield 1;
throw "2";
}
List.writeIterable([1, 2, 3], 1, throwingIterable());
}, (e) => e == "2");
// Bad start index.
testThrows([1, 2], [1], -1);
testThrows([1, 2], [1], 2);
// Working at a supertype is practical and useful.
test<Object>(<int>[1, 2, 3, 4], <num>[5, 6], 1, [1, 5, 6, 4]);
var d = new D();
test<Object>(<B>[null], <C>[d], 0, [d]);
}
testThrows<T>(list, iterable, start, [expect]) {
Expect.throws(() {
List.writeIterable<T>(list, start, iterable);
});
if (expect != null) {
Expect.listEquals(expect, list);
}
}
test<T>(List<T> list, Iterable<T> iterable, int start, List expect) {
List.writeIterable<T>(list, start, iterable);
Expect.listEquals(expect, list);
}
class B {}
class C {}
class D implements B, C {}