-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GroupSet provides a view of the union of a set of sets. SetGroup provides an easy way to manage a GroupSet in a class context. R=floitsch@google.com, lrn@google.com Review URL: https://codereview.chromium.org//1873373002 .
- Loading branch information
Showing
7 changed files
with
409 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:collection'; | ||
|
||
import 'unmodifiable_wrappers.dart'; | ||
|
||
/// A single set that provides a view of the union over a set of sets. | ||
/// | ||
/// Since this is just a view, it reflects all changes in the underlying sets. | ||
/// | ||
/// If an element is in multiple sets and the outer set is ordered, the version | ||
/// in the earliest inner set is preferred. Component sets are assumed to use | ||
/// `==` and `hashCode` for equality. | ||
class UnionSet<E> extends SetBase<E> with UnmodifiableSetMixin<E> { | ||
/// The set of sets that this provides a view of. | ||
final Set<Set<E>> _sets; | ||
|
||
/// Whether the sets in [_sets] are guaranteed to be disjoint. | ||
final bool _disjoint; | ||
|
||
/// Creates a new set that's a view of the union of all sets in [sets]. | ||
/// | ||
/// If any sets in [sets] change, this [UnionSet] reflects that change. If a | ||
/// new set is added to [sets], this [UnionSet] reflects that as well. | ||
/// | ||
/// If [disjoint] is `true`, then all component sets must be disjoint. That | ||
/// is, that they contain no elements in common. This makes many operations | ||
/// including [length] more efficient. If the component sets turn out not to | ||
/// be disjoint, some operations may behave inconsistently. | ||
UnionSet(this._sets, {bool disjoint: false}) : _disjoint = disjoint; | ||
|
||
/// Creates a new set that's a view of the union of all sets in [sets]. | ||
/// | ||
/// If any sets in [sets] change, this [UnionSet] reflects that change. | ||
/// However, unlike [new UnionSet], this creates a copy of its parameter, so | ||
/// changes in [sets] aren't reflected in this [UnionSet]. | ||
/// | ||
/// If [disjoint] is `true`, then all component sets must be disjoint. That | ||
/// is, that they contain no elements in common. This makes many operations | ||
/// including [length] more efficient. If the component sets turn out not to | ||
/// be disjoint, some operations may behave inconsistently. | ||
UnionSet.from(Iterable<Set<E>> sets, {bool disjoint: false}) | ||
: this(sets.toSet(), disjoint: disjoint); | ||
|
||
int get length => _disjoint | ||
? _sets.fold(0, (length, set) => length + set.length) | ||
: _iterable.length; | ||
|
||
Iterator<E> get iterator => _iterable.iterator; | ||
|
||
/// Returns an iterable over the contents of all the sets in [this]. | ||
Iterable<E> get _iterable => | ||
_disjoint ? _sets.expand((set) => set) : _dedupIterable; | ||
|
||
/// Returns an iterable over the contents of all the sets in [this] that | ||
/// de-duplicates elements. | ||
/// | ||
/// If the sets aren't guaranteed to be disjoint, this keeps track of the | ||
/// elements we've already emitted so that we can de-duplicate them. | ||
Iterable<E> get _dedupIterable { | ||
var seen = new Set<E>(); | ||
return _sets.expand((set) => set).where((element) { | ||
if (seen.contains(element)) return false; | ||
seen.add(element); | ||
return true; | ||
}); | ||
} | ||
|
||
bool contains(Object element) => _sets.any((set) => set.contains(element)); | ||
|
||
E lookup(Object element) { | ||
if (element == null) return null; | ||
|
||
return _sets | ||
.map((set) => set.lookup(element)) | ||
.firstWhere((result) => result != null, orElse: () => null); | ||
} | ||
|
||
Set<E> toSet() { | ||
var result = new Set<E>(); | ||
for (var set in _sets) { | ||
result.addAll(set); | ||
} | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (c) 2016, 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 'union_set.dart'; | ||
|
||
/// A controller that exposes a view of the union of a collection of sets. | ||
/// | ||
/// This is a convenience class for creating a [UnionSet] whose contents change | ||
/// over the lifetime of a class. For example: | ||
/// | ||
/// ```dart | ||
/// class Engine { | ||
/// Set<Test> get activeTests => _activeTestsGroup.set; | ||
/// final _activeTestsGroup = new UnionSetController<Test>(); | ||
/// | ||
/// void addSuite(Suite suite) { | ||
/// _activeTestsGroup.add(suite.tests); | ||
/// _runSuite(suite); | ||
/// _activeTestsGroup.remove(suite.tests); | ||
/// } | ||
/// } | ||
/// ``` | ||
class UnionSetController<E> { | ||
/// The [UnionSet] that provides a view of the union of sets in [this]. | ||
UnionSet<E> get set => _set; | ||
UnionSet<E> _set; | ||
|
||
/// The sets whose union is exposed through [set]. | ||
final _sets = new Set<Set<E>>(); | ||
|
||
/// Creates a set of sets that provides a view of the union of those sets. | ||
/// | ||
/// If [disjoint] is `true`, this assumes that all component sets are | ||
/// disjoint—that is, that they contain no elements in common. This makes | ||
/// many operations including [length] more efficient. | ||
UnionSetController({bool disjoint: false}) { | ||
_set = new UnionSet<E>(_sets, disjoint: disjoint); | ||
} | ||
|
||
/// Adds the contents of [component] to [set]. | ||
/// | ||
/// If the contents of [component] change over time, [set] will change | ||
/// accordingly. | ||
void add(Set<E> component) { | ||
_sets.add(component); | ||
} | ||
|
||
/// Removes the contents of [component] to [set]. | ||
/// | ||
/// If another set in [this] has overlapping elements with [component], those | ||
/// elements will remain in [set]. | ||
bool remove(Set<E> component) => _sets.remove(component); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2016, 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:test/test.dart"; | ||
|
||
import "package:collection/collection.dart"; | ||
|
||
void main() { | ||
var controller; | ||
var innerSet; | ||
setUp(() { | ||
innerSet = new Set.from([1, 2, 3]); | ||
controller = new UnionSetController<int>()..add(innerSet); | ||
}); | ||
|
||
test("exposes a union set", () { | ||
expect(controller.set, unorderedEquals([1, 2, 3])); | ||
|
||
controller.add(new Set.from([3, 4, 5])); | ||
expect(controller.set, unorderedEquals([1, 2, 3, 4, 5])); | ||
|
||
controller.remove(innerSet); | ||
expect(controller.set, unorderedEquals([3, 4, 5])); | ||
}); | ||
|
||
test("exposes a disjoint union set", () { | ||
expect(controller.set, unorderedEquals([1, 2, 3])); | ||
|
||
controller.add(new Set.from([4, 5, 6])); | ||
expect(controller.set, unorderedEquals([1, 2, 3, 4, 5, 6])); | ||
|
||
controller.remove(innerSet); | ||
expect(controller.set, unorderedEquals([4, 5, 6])); | ||
}); | ||
} |
Oops, something went wrong.