swiftoptionsettype

more idiomatic swift test for optionset?


Still getting used to the use of OptionSetType in Swift.

In good ol' C, if I had something like

typedef enum {
    CHAR_PROP_BROADCAST          =0x01,
    CHAR_PROP_READ               =0x02,
    CHAR_PROP_WRITE_WITHOUT_RESP =0x04,
    CHAR_PROP_WRITE              =0x08,
    CHAR_PROP_NOTIFY             =0x10,
    CHAR_PROP_INDICATE           =0x20,
    CHAR_PROP_SIGNED_WRITE       =0x40,
    CHAR_PROP_EXT                =0x80
} CharacteristicProperty;

I could test a set of flags with something simple like:

if ((propertiesMask & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) != 0) ...

The Swift alternative might look like

let properties:CBCharacteristicProperties = [.Write, .Read, .Indicate]
!properties.intersect([.Indicate, .Notify]).isEmpty

Is there a more idiomatic way to do this test? Not a fan of the ! out front. But otherwise, seems straightforward enough, except I'm really interested in when there IS an intersection. This led me to want to add my own.

extension OptionSetType {
    func hasIntersection(other:Self) -> Bool {
        return !self.intersect(other).isEmpty
    }
}

Which then allows me to write

properties.hasIntersection([.Indicate, .Notify])

Is there a better/more idiomatic way to do this? Did I roll my own and miss something?


Solution

  • There's this method from the protocol SetAlgebraType which OptionSetType implements:

    isDisjointWith(_: Self) -> Bool

    Returns true iff self.intersect(other).isEmpty.

    So you could shorten your test to:

    !properties.isDisjointWith([.Indicate, .Notify])
    

    or

    properties.isDisjointWith([.Indicate, .Notify]) == false
    

    You can also compare the raw values with bitwise operators, just as you would do in C:

    (properties.rawValue & (CharacteristicProperties.Notify.rawValue | CharacteristicProperties.Indicate.rawValue)) != 0
    

    Full example code (in a playground):

    struct CBCharacteristicProperties : OptionSetType {
      let rawValue: UInt
      init(rawValue: UInt) { self.rawValue = rawValue }
    
      static let Broadcast          = CBCharacteristicProperties(rawValue:0x01)
      static let Read               = CBCharacteristicProperties(rawValue:0x02)
      static let WriteWithoutResp   = CBCharacteristicProperties(rawValue:0x04)
      static let Write              = CBCharacteristicProperties(rawValue:0x08)
      static let Notify             = CBCharacteristicProperties(rawValue:0x10)
      static let Indicate           = CBCharacteristicProperties(rawValue:0x20)
      static let SignedWrite        = CBCharacteristicProperties(rawValue:0x40)
      static let Ext                = CBCharacteristicProperties(rawValue:0x80)
    }
    
    let properties = CBCharacteristicProperties([.Write, .Read, .Indicate])
    print(!properties.intersect([.Indicate, .Notify]).isEmpty)
    print(!properties.isDisjointWith([.Indicate, .Notify]))
    print(properties.isDisjointWith([.Indicate, .Notify]) == false)
    print((properties.rawValue & (CBCharacteristicProperties.Notify.rawValue | CBCharacteristicProperties.Indicate.rawValue)) != 0)
    

    result:

    "true"
    "true"
    "true"
    "true"