// 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 extends SetBase with UnmodifiableSetMixin { /// The set of sets that this provides a view of. final Set> _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(Set> sets, {bool disjoint = false}) : _sets = sets, _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 [UnionSet.new], 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> sets, {bool disjoint = false}) : this(sets.toSet(), disjoint: disjoint); @override int get length => _disjoint ? _sets.fold(0, (length, set) => length + set.length) : _iterable.length; @override Iterator get iterator => _iterable.iterator; /// An iterable over the contents of all [_sets]. /// /// If this is not a [_disjoint] union an extra set is used to deduplicate /// values. Iterable get _iterable { var allElements = _sets.expand((set) => set); return _disjoint ? allElements : allElements.where({}.add); } @override bool contains(Object? element) => _sets.any((set) => set.contains(element)); @override E? lookup(Object? element) { for (var set in _sets) { var result = set.lookup(element); if (result != null || set.contains(null)) return result; } return null; } @override Set toSet() => {for (var set in _sets) ...set}; }