| //===--- OptionSet.swift --------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| /// Supplies convenient conformance to `SetAlgebraType` for any type |
| /// whose `RawValue` is a `BitwiseOperationsType`. For example: |
| /// |
| /// struct PackagingOptions : OptionSetType { |
| /// let rawValue: Int |
| /// init(rawValue: Int) { self.rawValue = rawValue } |
| /// |
| /// static let Box = PackagingOptions(rawValue: 1) |
| /// static let Carton = PackagingOptions(rawValue: 2) |
| /// static let Bag = PackagingOptions(rawValue: 4) |
| /// static let Satchel = PackagingOptions(rawValue: 8) |
| /// static let BoxOrBag: PackagingOptions = [Box, Bag] |
| /// static let BoxOrCartonOrBag: PackagingOptions = [Box, Carton, Bag] |
| /// } |
| /// |
| /// In the example above, `PackagingOptions.Element` is the same type |
| /// as `PackagingOptions`, and instance `a` subsumes instance `b` if |
| /// and only if `a.rawValue & b.rawValue == b.rawValue`. |
| public protocol OptionSetType : SetAlgebraType, RawRepresentable { |
| // We can't constrain the associated Element type to be the same as |
| // Self, but we can do almost as well with a default and a |
| // constrained extension |
| |
| /// An `OptionSet`'s `Element` type is normally `Self`. |
| typealias Element = Self |
| |
| // FIXME: This initializer should just be the failable init from |
| // RawRepresentable. Unfortunately, current language limitations |
| // that prevent non-failable initializers from forwarding to |
| // failable ones would prevent us from generating the non-failing |
| // default (zero-argument) initializer. Since OptionSetType's main |
| // purpose is to create convenient conformances to SetAlgebraType, |
| // we opt for a non-failable initializer. |
| |
| /// Convert from a value of `RawValue`, succeeding unconditionally. |
| init(rawValue: RawValue) |
| } |
| |
| /// `OptionSetType` requirements for which default implementations |
| /// are supplied. |
| /// |
| /// - Note: A type conforming to `OptionSetType` can implement any of |
| /// these initializers or methods, and those implementations will be |
| /// used in lieu of these defaults. |
| extension OptionSetType { |
| /// Returns the set of elements contained in `self`, in `other`, or in |
| /// both `self` and `other`. |
| @warn_unused_result |
| public func union(other: Self) -> Self { |
| var r: Self = Self(rawValue: self.rawValue) |
| r.unionInPlace(other) |
| return r |
| } |
| |
| /// Returns the set of elements contained in both `self` and `other`. |
| @warn_unused_result |
| public func intersect(other: Self) -> Self { |
| var r = Self(rawValue: self.rawValue) |
| r.intersectInPlace(other) |
| return r |
| } |
| |
| /// Returns the set of elements contained in `self` or in `other`, |
| /// but not in both `self` and `other`. |
| @warn_unused_result |
| public func exclusiveOr(other: Self) -> Self { |
| var r = Self(rawValue: self.rawValue) |
| r.exclusiveOrInPlace(other) |
| return r |
| } |
| } |
| |
| /// `OptionSetType` requirements for which default implementations are |
| /// supplied when `Element == Self`, which is the default. |
| /// |
| /// - Note: A type conforming to `OptionSetType` can implement any of |
| /// these initializers or methods, and those implementations will be |
| /// used in lieu of these defaults. |
| extension OptionSetType where Element == Self { |
| /// Returns `true` if `self` contains `member`. |
| /// |
| /// - Equivalent to `self.intersect([member]) == [member]` |
| @warn_unused_result |
| public func contains(member: Self) -> Bool { |
| return self.isSupersetOf(member) |
| } |
| |
| /// If `member` is not already contained in `self`, insert it. |
| /// |
| /// - Equivalent to `self.unionInPlace([member])` |
| /// - Postcondition: `self.contains(member)` |
| public mutating func insert(member: Element) { |
| self.unionInPlace(member) |
| } |
| |
| /// If `member` is contained in `self`, remove and return it. |
| /// Otherwise, return `nil`. |
| /// |
| /// - Postcondition: `self.intersect([member]).isEmpty` |
| public mutating func remove(member: Element) -> Element? { |
| let r = isSupersetOf(member) ? Optional(member) : nil |
| self.subtractInPlace(member) |
| return r |
| } |
| } |
| |
| /// `OptionSetType` requirements for which default implementations are |
| /// supplied when `RawValue` conforms to `BitwiseOperationsType`, |
| /// which is the usual case. Each distinct bit of an option set's |
| /// `.rawValue` corresponds to a disjoint element of the option set. |
| /// |
| /// - `union` is implemented as a bitwise "or" (`|`) of `rawValue`s |
| /// - `intersection` is implemented as a bitwise "and" (`|`) of `rawValue`s |
| /// - `exclusiveOr` is implemented as a bitwise "exclusive or" (`^`) of `rawValue`s |
| /// |
| /// - Note: A type conforming to `OptionSetType` can implement any of |
| /// these initializers or methods, and those implementations will be |
| /// used in lieu of these defaults. |
| extension OptionSetType where RawValue : BitwiseOperationsType { |
| /// Create an empty instance. |
| /// |
| /// - Equivalent to `[] as Self` |
| public init() { |
| self.init(rawValue: .allZeros) |
| } |
| |
| /// Insert all elements of `other` into `self`. |
| /// |
| /// - Equivalent to replacing `self` with `self.union(other)`. |
| /// - Postcondition: `self.isSupersetOf(other)` |
| public mutating func unionInPlace(other: Self) { |
| self = Self(rawValue: self.rawValue | other.rawValue) |
| } |
| |
| /// Remove all elements of `self` that are not also present in |
| /// `other`. |
| /// |
| /// - Equivalent to replacing `self` with `self.intersect(other)` |
| /// - Postcondition: `self.isSubsetOf(other)` |
| public mutating func intersectInPlace(other: Self) { |
| self = Self(rawValue: self.rawValue & other.rawValue) |
| } |
| |
| /// Replace `self` with a set containing all elements contained in |
| /// either `self` or `other`, but not both. |
| /// |
| /// - Equivalent to replacing `self` with `self.exclusiveOr(other)` |
| public mutating func exclusiveOrInPlace(other: Self) { |
| self = Self(rawValue: self.rawValue ^ other.rawValue) |
| } |
| } |
| |
| @available(*, unavailable, renamed="OptionSetType") |
| public typealias RawOptionSetType = OptionSetType |