mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:39:19 +00:00
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:
parent
790a34b9f0
commit
8d38d94ddb
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
115
tests/corelib_2/list_copy_range_test.dart
Normal file
115
tests/corelib_2/list_copy_range_test.dart
Normal 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 {}
|
75
tests/corelib_2/list_write_elements_test.dart
Normal file
75
tests/corelib_2/list_write_elements_test.dart
Normal 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 {}
|
Loading…
Reference in a new issue