From dcf0286f5385187a68ce9e66318d3bf19abf454b Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 22 May 2015 10:39:58 +0200 Subject: [PATCH] Add Iterable.empty constructor. Convenience constructor giving an easy/quick way to create an empty iterable. R=sgjesse@google.com Review URL: https://codereview.chromium.org//1152483002 --- sdk/lib/core/iterable.dart | 11 ++++ sdk/lib/internal/iterable.dart | 2 +- tests/corelib/iterable_empty_test.dart | 72 ++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/corelib/iterable_empty_test.dart diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index e435b1e76807..c22283ab4e16 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart @@ -101,6 +101,17 @@ abstract class Iterable { return new _GeneratorIterable(count, generator); } + /** + * Creates an empty iterable. + * + * The empty iterable has no elements, and iterating it always stops + * immediately. + * + * An empty iterable can be used in places where you always that + * the iterable you would otherwise create is empty. + */ + const factory Iterable.empty() = EmptyIterable; + /** * Returns a new `Iterator` that allows iterating the elements of this * `Iterable`. diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart index 0a59b0ea2589..ff03d1a0bb26 100644 --- a/sdk/lib/internal/iterable.dart +++ b/sdk/lib/internal/iterable.dart @@ -658,7 +658,7 @@ class SkipWhileIterator extends Iterator { * The always empty [Iterable]. */ class EmptyIterable extends Iterable - implements EfficientLengthIterable { + implements EfficientLengthIterable { const EmptyIterable(); Iterator get iterator => const EmptyIterator(); diff --git a/tests/corelib/iterable_empty_test.dart b/tests/corelib/iterable_empty_test.dart new file mode 100644 index 000000000000..75adfa7e0052 --- /dev/null +++ b/tests/corelib/iterable_empty_test.dart @@ -0,0 +1,72 @@ +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import "package:expect/expect.dart"; + +main() { + testEmpty(name, it, [depth = 2]) { + Expect.isTrue(it.isEmpty, name); + Expect.isFalse(it.isNotEmpty, name); + Expect.equals(0, it.length, name); + Expect.isFalse(it.contains(null), name); + Expect.isFalse(it.any((x)=>true), name); + Expect.isTrue(it.every((x)=>false), name); + Expect.throws(() => it.first, (e) => e is StateError, name); + Expect.throws(() => it.last, (e) => e is StateError, name); + Expect.throws(() => it.single, (e) => e is StateError, name); + Expect.throws(() => it.elementAt(0), (e) => e is RangeError, name); + Expect.throws(() => it.reduce((a, b) => a), (e) => e is StateError, name); + Expect.throws(() => it.singleWhere((_) => true), + (e) => e is StateError, name); + Expect.equals(42, it.fold(42, (a, b) => "not 42"), name); + Expect.equals(42, it.firstWhere((v) => true, orElse: () => 42), name); + Expect.equals(42, it.lastWhere((v) => true, orElse: () => 42), name); + Expect.equals("", it.join("separator"), name); + Expect.equals("()", it.toString(), name); + Expect.listEquals([], it.toList(), name); + Expect.listEquals([], it.toList(growable: false), name); + Expect.listEquals([], it.toList(growable: true), name); + Expect.equals(0, it.toSet().length, name); + // Doesn't throw: + it.forEach((v) => throw v); + for (var v in it) { + throw v; + } + // Check that returned iterables are also empty. + if (depth > 0) { + testEmpty("$name-map", it.map((x)=>x), depth - 1); + testEmpty("$name-where", it.where((x)=>true), depth - 1); + testEmpty("$name-expand", it.expand((x)=>[x]), depth - 1); + testEmpty("$name-skip", it.skip(1), depth - 1); + testEmpty("$name-take", it.take(2), depth - 1); + testEmpty("$name-skipWhile", it.skipWhile((v) => false), depth - 1); + testEmpty("$name-takeWhile", it.takeWhile((v) => true), depth - 1); + } + } + + testType(name, it, [depth = 2]) { + Expect.isTrue(it is Iterable, name); + Expect.isFalse(it is Iterable, name); + if (depth > 0) { + testType("$name-where", it.where((_)=>true), depth - 1); + testType("$name-skip", it.skip(1), depth - 1); + testType("$name-take", it.take(1), depth - 1); + testType("$name-skipWhile", it.skipWhile((_)=>false), depth - 1); + testType("$name-takeWhile", it.takeWhile((_)=>true), depth - 1); + testType("$name-toList", it.toList(), depth - 1); + testType("$name-toList", it.toList(growable: false), depth - 1); + testType("$name-toList", it.toList(growable: true), depth - 1); + testType("$name-toSet", it.toSet(), depth - 1); + } + } + + test(name, it) { + testEmpty(name, it); + testType(name, it); + } + + test("const", const Iterable.empty()); + test("new", new Iterable.empty()); +} +