Line data Source code
1 : // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'dart:collection'; 6 : 7 : import 'unmodifiable_wrappers.dart'; 8 : 9 : /// A single set that provides a view of the union over a set of sets. 10 : /// 11 : /// Since this is just a view, it reflects all changes in the underlying sets. 12 : /// 13 : /// If an element is in multiple sets and the outer set is ordered, the version 14 : /// in the earliest inner set is preferred. Component sets are assumed to use 15 : /// `==` and `hashCode` for equality. 16 : class UnionSet<E> extends SetBase<E> with UnmodifiableSetMixin<E> { 17 : /// The set of sets that this provides a view of. 18 : final Set<Set<E>> _sets; 19 : 20 : /// Whether the sets in [_sets] are guaranteed to be disjoint. 21 : final bool _disjoint; 22 : 23 : /// Creates a new set that's a view of the union of all sets in [sets]. 24 : /// 25 : /// If any sets in [sets] change, this [UnionSet] reflects that change. If a 26 : /// new set is added to [sets], this [UnionSet] reflects that as well. 27 : /// 28 : /// If [disjoint] is `true`, then all component sets must be disjoint. That 29 : /// is, that they contain no elements in common. This makes many operations 30 : /// including [length] more efficient. If the component sets turn out not to 31 : /// be disjoint, some operations may behave inconsistently. 32 0 : UnionSet(Set<Set<E>> sets, {bool disjoint = false}) 33 : : _sets = sets, 34 : _disjoint = disjoint; 35 : 36 : /// Creates a new set that's a view of the union of all sets in [sets]. 37 : /// 38 : /// If any sets in [sets] change, this [UnionSet] reflects that change. 39 : /// However, unlike [new UnionSet], this creates a copy of its parameter, so 40 : /// changes in [sets] aren't reflected in this [UnionSet]. 41 : /// 42 : /// If [disjoint] is `true`, then all component sets must be disjoint. That 43 : /// is, that they contain no elements in common. This makes many operations 44 : /// including [length] more efficient. If the component sets turn out not to 45 : /// be disjoint, some operations may behave inconsistently. 46 0 : UnionSet.from(Iterable<Set<E>> sets, {bool disjoint = false}) 47 0 : : this(sets.toSet(), disjoint: disjoint); 48 : 49 0 : @override 50 0 : int get length => _disjoint 51 0 : ? _sets.fold(0, (length, set) => length + set.length) 52 0 : : _iterable.length; 53 : 54 0 : @override 55 0 : Iterator<E> get iterator => _iterable.iterator; 56 : 57 : /// An iterable over the contents of all [_sets]. 58 : /// 59 : /// If this is not a [_disjoint] union an extra set is used to deduplicate 60 : /// values. 61 0 : Iterable<E> get _iterable { 62 0 : var allElements = _sets.expand((set) => set); 63 0 : return _disjoint ? allElements : allElements.where(<E>{}.add); 64 : } 65 : 66 0 : @override 67 0 : bool contains(Object? element) => _sets.any((set) => set.contains(element)); 68 : 69 0 : @override 70 : E? lookup(Object? element) { 71 0 : for (var set in _sets) { 72 0 : var result = set.lookup(element); 73 0 : if (result != null || set.contains(null)) return result; 74 : } 75 : return null; 76 : } 77 : 78 0 : @override 79 0 : Set<E> toSet() => <E>{for (var set in _sets) ...set}; 80 : }