https://github.com/apple/swift/blob/master/stdlib/public/core/OptionSet.swift
主要實(shí)現(xiàn)了三個(gè)方法
@inlinable//generic-performance
publicmutatingfuncformUnion(_other:Self) {
self=Self(rawValue:self.rawValue|other.rawValue)
? }
@inlinable//generic-performance
publicmutatingfuncformIntersection(_other:Self) {
self=Self(rawValue:self.rawValue&other.rawValue)
? }
@inlinable//generic-performance
publicmutatingfuncformSymmetricDifference(_other:Self) {
self=Self(rawValue:self.rawValue^other.rawValue)
? }
其中涉及到代理
FixedWidthInteger
RawRepresentable
SetAlgebra
A type that presents a mathematical set interface to a bit set.
///You use the `OptionSet` protocol to represent bitset types, where
///individual bits represent members of a set. Adopting this protocol in
///your custom types lets you perform set-related operations such as
///membership tests, unions, and intersections on those types. What's more,
///when implemented using specific criteria, adoption of this protocol
///requires no extra work on your part.
///When creating an option set, include a `rawValue` property in your type
///declaration. For your type to automatically receive default implementations
///for set-related operations, the `rawValue` property must be of a type that
///conforms to the `FixedWidthInteger` protocol, such as `Int` or `UInt8`.
///Next, create unique options as static properties of your custom type using
///unique powers of two (1, 2, 4, 8, 16, and so forth) for each individual
///property's raw value so that each property can be represented by a single
///bit of the type's raw value.
///For example, consider a custom type called `ShippingOptions` that is an
///option set of the possible ways to ship a customer's purchase.
///`ShippingOptions` includes a `rawValue` property of type `Int` that stores
///the bit mask of available shipping options. The static members `nextDay`,
///`secondDay`, `priority`, and `standard` are unique, individual options.
///struct ShippingOptions: OptionSet {
///let rawValue: Int
///
///static let nextDay? ? = ShippingOptions(rawValue: 1 << 0)
///static let secondDay? = ShippingOptions(rawValue: 1 << 1)
///static let priority? = ShippingOptions(rawValue: 1 << 2)
///static let standard? = ShippingOptions(rawValue: 1 << 3)
///
///static let express: ShippingOptions = [.nextDay, .secondDay]
///static let all: ShippingOptions = [.express, .priority, .standard]
///}
///
///Declare additional preconfigured option set values as static properties
///initialized with an array literal containing other option values. In the
///example, because the `express` static property is assigned an array
///literal with the `nextDay` and `secondDay` options, it will contain those
///two elements.
/// Using an Option Set Type
///When you need to create an instance of an option set, assign one of the
///type's static members to your variable or constant. Alternatively, to
///create an option set instance with multiple members, assign an array
///literal with multiple static members of the option set. To create an empty
///instance, assign an empty array literal to your variable.
publicprotocolOptionSet:SetAlgebra,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
///The element type of the option set.
///
///To inherit all the default implementations from the `OptionSet` protocol,
///the `Element` type must be `Self`, the default.
associatedtypeElement=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 OptionSet's main
//purpose is to create convenient conformances to SetAlgebra,
//we opt for a non-failable initializer.
///Creates a new option set from the given raw value.
///
///This initializer always succeeds, even if the value passed as `rawValue`
///exceeds the static properties declared as part of the option set. This
///example creates an instance of `ShippingOptions` with a raw value beyond
///the highest element, with a bit mask that effectively contains all the
///declared static members.
///
///let extraOptions = ShippingOptions(rawValue: 255)
///print(extraOptions.isStrictSuperset(of: .all))
///// Prints "true"
///
///- Parameter rawValue: The raw value of the option set to create. Each bit
///of `rawValue` potentially represents an element of the option set,
///though raw values may include bits that are not defined as distinct
///values of the `OptionSet` type.
init(rawValue:RawValue)
}
///`OptionSet` requirements for which default implementations
///are supplied.
///- Note: A type conforming to `OptionSet` can implement any of
///these initializers or methods, and those implementations will be
///used in lieu of these defaults.
extensionOptionSet{
///Returns a new option set of the elements contained in this set, in the
///given set, or in both.
///
///This example uses the `union(_:)` method to add two more shipping options
///to the default set.
///
///let defaultShipping = ShippingOptions.standard
///let memberShipping = defaultShipping.union([.secondDay, .priority])
///print(memberShipping.contains(.priority))
///// Prints "true"
///
///- Parameter other: An option set.
///- Returns: A new option set made up of the elements contained in this
///set, in `other`, or in both.
@inlinable//generic-performance
publicfuncunion(_other:Self)->Self{
varr:Self=Self(rawValue:self.rawValue)
r.formUnion(other)
returnr
? }
///Returns a new option set with only the elements contained in both this
///set and the given set.
///
///This example uses the `intersection(_:)` method to limit the available
///shipping options to what can be used with a PO Box destination.
///
///// Can only ship standard or priority to PO Boxes
///let poboxShipping: ShippingOptions = [.standard, .priority]
///let memberShipping: ShippingOptions =
///[.standard, .priority, .secondDay]
///
///let availableOptions = memberShipping.intersection(poboxShipping)
///print(availableOptions.contains(.priority))
///// Prints "true"
///print(availableOptions.contains(.secondDay))
///// Prints "false"
///- Parameter other: An option set.
///- Returns: A new option set with only the elements contained in both this
///set and `other`.
@inlinable//generic-performance
publicfuncintersection(_other:Self)->Self{
varr=Self(rawValue:self.rawValue)
r.formIntersection(other)
returnr
? }
///Returns a new option set with the elements contained in this set or in
///the given set, but not in both.
///
///- Parameter other: An option set.
///- Returns: A new option set with only the elements contained in either
///this set or `other`, but not in both.
@inlinable//generic-performance
publicfuncsymmetricDifference(_other:Self)->Self{
varr=Self(rawValue:self.rawValue)
r.formSymmetricDifference(other)
returnr
? }
}
///`OptionSet` requirements for which default implementations are
///supplied when `Element == Self`, which is the default.
///
///- Note: A type conforming to `OptionSet` can implement any of
///these initializers or methods, and those implementations will be
///used in lieu of these defaults
extensionOptionSetwhereElement==Self{
///Returns a Boolean value that indicates whether a given element is a
///member of the option set.
///
///This example uses the `contains(_:)` method to check whether next-day
///shipping is in the `availableOptions` instance.
///
///let availableOptions = ShippingOptions.express
///if availableOptions.contains(.nextDay) {
///print("Next day shipping available")
///}
///// Prints "Next day shipping available"
///
///- Parameter member: The element to look for in the option set.
///- Returns: `true` if the option set contains `member`; otherwise,
///`false`.
@inlinable//generic-performance
publicfunccontains(_member:Self)->Bool{
returnself.isSuperset(of: member)
? }
///Adds the given element to the option set if it is not already a member.
///
///In the following example, the `.secondDay` shipping option is added to
///the `freeOptions` option set if `purchasePrice` is greater than 50.0. For
///the `ShippingOptions` declaration, see the `OptionSet` protocol
///discussion.
///
///let purchasePrice = 87.55
///
///var freeOptions: ShippingOptions = [.standard, .priority]
///if purchasePrice > 50 {
///freeOptions.insert(.secondDay)
///}
///print(freeOptions.contains(.secondDay))
///// Prints "true"
///
///- Parameter newMember: The element to insert.
///- Returns: `(true, newMember)` if `newMember` was not contained in
///`self`. Otherwise, returns `(false, oldMember)`, where `oldMember` is
///the member of the set equal to `newMember`.
@inlinable//generic-performance
@discardableResult
publicmutatingfuncinsert(
_newMember:Element
)->(inserted:Bool, memberAfterInsert:Element) {
letoldMember=self.intersection(newMember)
letshouldInsert=oldMember!=newMember
letresult=(
inserted: shouldInsert,
memberAfterInsert: shouldInsert?newMember:oldMember)
ifshouldInsert {
self.formUnion(newMember)
? ? }
returnresult
///In the next example, the `.express` element is passed to `remove(_:)`.
///Although `.express` is not a member of `options`, `.express` subsumes
///the remaining `.secondDay` element of the option set. Therefore,
///`options` is emptied and the intersection between `.express` and
///`options` is returned.
///
///let expressOption = options.remove(.express)
///print(expressOption == .express)
///// Prints "false"
///print(expressOption == .secondDay)
///// Prints "true"
///
///- Parameter member: The element of the set to remove.
///- Returns: The intersection of `[member]` and the set, if the
///intersection was nonempty; otherwise, `nil`.
///Inserts the given element into the set.
///
///If `newMember` is not contained in the set but subsumes current members
///of the set, the subsumed members are returned.
///
///var options: ShippingOptions = [.secondDay, .priority]
///let replaced = options.update(with: .express)
///print(replaced == .secondDay)
///// Prints "true"
///
///- Returns: The intersection of `[newMember]` and the set if the
///intersection was nonempty; otherwise, `nil`.
@inlinable//generic-performance
@discardableResult
publicmutatingfuncupdate(withnewMember:Element)->Element?{
letr=self.intersection(newMember)
self.formUnion(newMember)
returnr.isEmpty?nil:r
? }
}
///`OptionSet` requirements for which default implementations are
///supplied when `RawValue` conforms to `FixedWidthInteger`,
///which is the usual case.? Each distinct bit of an option set's
///`.rawValue` corresponds to a disjoint value of the `OptionSet`.
///
///- `union` is implemented as a bitwise "or" (`|`) of `rawValue`s
///- `intersection` is implemented as a bitwise "and" (`&`) of
///`rawValue`s
///- `symmetricDifference` is implemented as a bitwise "exclusive or"
///(`^`) of `rawValue`s
///
///- Note: A type conforming to `OptionSet` can implement any of
///these initializers or methods, and those implementations will be
///used in lieu of these defaults.
///`OptionSet` requirements for which default implementations are
///supplied when `RawValue` conforms to `FixedWidthInteger`,
///which is the usual case.? Each distinct bit of an option set's
///`.rawValue` corresponds to a disjoint value of the `OptionSet`.
///
///- `union` is implemented as a bitwise "or" (`|`) of `rawValue`s
///- `intersection` is implemented as a bitwise "and" (`&`) of
///`rawValue`s
///- `symmetricDifference` is implemented as a bitwise "exclusive or"
///(`^`) of `rawValue`s
///- Note: A type conforming to `OptionSet` can implement any of
///these initializers or methods, and those implementations will be
///used in lieu of these defaults.
extensionOptionSetwhereRawValue:FixedWidthInteger{
///Creates an empty option set.
///
///This initializer creates an option set with a raw value of zero.
@inlinable//generic-performance
publicinit() {
self.init(rawValue:0)
? }
///Inserts the elements of another set into this option set.
///
///This method is implemented as a `|` (bitwise OR) operation on the
///two sets' raw values.
///
///- Parameter other: An option set.
@inlinable//generic-performance
publicmutatingfuncformUnion(_other:Self) {
self=Self(rawValue:self.rawValue|other.rawValue)
? }
///Removes all elements of this option set that are not
///also present in the given set.
///
///This method is implemented as a `&` (bitwise AND) operation on the
///two sets' raw values.
///
///- Parameter other: An option set.
@inlinable//generic-performance
publicmutatingfuncformIntersection(_other:Self) {
self=Self(rawValue:self.rawValue&other.rawValue)
? }
///Replaces this set with a new set containing all elements
///contained in either this set or the given set, but not in both.
///
///This method is implemented as a `^` (bitwise XOR) operation on the two
///sets' raw values.
///
///- Parameter other: An option set.
@inlinable//generic-performance
publicmutatingfuncformSymmetricDifference(_other:Self) {
self=Self(rawValue:self.rawValue^other.rawValue)
? }
}