An aside from bit-fields, a property-wrapper example, for future consideration

I first came up with this idea while reading the responses to the C bit fields thread. But the idea got pushed back and I may have forgotten some details.

I was thinking of re-proposing after first simplifying the bit-field idea with just fixed-sized arrays of Bool, then I thought about property wrappers again. I read the guide (Swift 5.1 back then, and again for 5.2) and wondered if we could use them here.

 @propertyWrapper
 struct Compacted<Value: [_! ; Bool], Storage: FixedWidthInteger> {
     @constexpr private static let wholeWordCount = Value.count / Storage.bitWidth
     @constexpr private static let partialWordCount = Value.count % Storage.bitWidth == 0 ? 0 : 1
     @constexpr private static let wordCount = wholeWordCount + partialWordCount

     private typealias Words = [wordCount ; Storage]
     private storage: Words

     public var wrappedValue: Value {
         get {
             // All of this could be done better.
             var result: Value
             for r inout result {
                 let (wordIndex, bitIndex) = #indexOf(r)[0].quotientAndRemainder(dividingBy: Storage.bitWidth)
                 r = storage[wordIndex] & (1 << bitIndex) != 0
             }
             return result
         }
         set {
             self = Self(wrappedValue: newValue, into: Storage.self)
         }
     }
     @inlinable public var projectedValue: Self { return self }

     public init(into type: Storage.Type) {
         storage = fill(a: Words.self, with: 0)
     }
     public init(wrappedValue: Value, into type: Storage.Type) {
         self.init(into: type)
         for w inout storage {
             let start = #indexOf(w)[0] * Storage.bitWidth
             for vi in start..<Swift.min(start + Storage.bitWidth, Value.count) {
                 if wrappedValue[vi] {
                     word |= 1 << (vi - start)
                 }
             }
             w = word
         }
     }
 }

 // I don't know if this would be legal for defaulting the storage type.
 extension Compacted where Storage == UInt {
     @inlinable public init(wrappedValue: Value) {
         self.init(wrappedValue: wrappedValue, into: Storage.self)
     }
     @inlinable public init() {
         self.init(into: Storage.self)
     }
 }

 extension Compacted: RandomAccessCollection, MutableCollection {
     @inlinable public startIndex: Int { return 0 }
     @inlinable public endIndex: Int { return Value.count }
     public subscript(position: Int) -> Bool {
         get {
             let (wordIndex, bitIndex) = position.quotientAndRemainder(dividingBy: Storage.bitWidth)
             let mask: Storage = 1 << bitIndex
             return storage[wordIndex] & mask != 0
         }
         set {
             let (wordIndex, bitIndex) = position.quotientAndRemainder(dividingBy: Storage.bitWidth)
             let mask: Storage = 1 << bitIndex
             if newValue {
                 storage[wordIndex] |= mask
             } else {
                 storage[wordIndex] &= ~mask
             }
         }
     }
 }

 // To-Do: Add Equatable/Hashable/etc. support.

where [_! ; Bool] is the protocol-analogue for one-dimensional fixed-size arrays of Bool where the length must be determined by compile-time, and you should be able to guess any other new example features. This ends up simulating C++'s std::bitset. Property wrappers are more amazing than I first thought after reading they've been added to Swift.

Terms of Service

Privacy Policy

Cookie Policy