|
| 1 | +// RUN: %target-swift-frontend -emit-ir -primary-file %s |
| 2 | + |
| 3 | +private typealias Word = UInt |
| 4 | + |
| 5 | +/// Returns the offset at which the `i`th bit can be found in an array of |
| 6 | +/// `Word`s. |
| 7 | +private func wordOffset(ofBit i: Int) -> Int { |
| 8 | + precondition(i >= 0) |
| 9 | + return i / Word.bitWidth |
| 10 | +} |
| 11 | + |
| 12 | +/// Returns a mask that isolates the `i`th bit within its `Word` in an array of |
| 13 | +/// `Word`s. |
| 14 | +private func wordMask(ofBit i: Int) -> Word { |
| 15 | + precondition(i >= 0) |
| 16 | + return (1 as Word) << (i % Word.bitWidth) |
| 17 | +} |
| 18 | + |
| 19 | +/// An adapter that presents a base instance of `S` as a sequence of bits packed |
| 20 | +/// into `Word`, where `true` and `false` in the base are represented as `1` and |
| 21 | +/// `0` bits in an element of `self`, respectively. |
| 22 | +private struct PackedIntoWords<S: Sequence>: Sequence where S.Element == Bool { |
| 23 | + /// The iteration state of a traversal of a `PackedIntoWords`. |
| 24 | + struct Iterator: IteratorProtocol { |
| 25 | + var base: S.Iterator |
| 26 | + |
| 27 | + mutating func next() -> Word? { |
| 28 | + guard let b = base.next() else { return nil } |
| 29 | + var r: Word = b ? 1 : 0 |
| 30 | + for i in 1..<Word.bitWidth { |
| 31 | + guard let b = base.next() else { return r } |
| 32 | + if b { r |= wordMask(ofBit: i) } |
| 33 | + } |
| 34 | + return r |
| 35 | + } |
| 36 | + } |
| 37 | + /// Returns a new iterator over `self`. |
| 38 | + func makeIterator() -> Iterator { Iterator(base: base.makeIterator()) } |
| 39 | + |
| 40 | + /// Returns a number no greater than the number of elements in `self`. |
| 41 | + var underestimatedCount: Int { |
| 42 | + (base.underestimatedCount + Word.bitWidth - 1) / Word.bitWidth |
| 43 | + } |
| 44 | + |
| 45 | + /// The underlying sequence of `Bool`. |
| 46 | + let base: S |
| 47 | + |
| 48 | + init(_ base: S) { self.base = base } |
| 49 | +} |
| 50 | + |
| 51 | +struct Bits<Base: Sequence>: Sequence |
| 52 | + where Base.Element: FixedWidthInteger |
| 53 | +{ |
| 54 | + public var base: Base |
| 55 | + typealias Element = Bool |
| 56 | + |
| 57 | + func makeIterator() -> Iterator { Iterator(base: base.makeIterator()) } |
| 58 | + |
| 59 | + struct Iterator: IteratorProtocol { |
| 60 | + typealias Element = Bool |
| 61 | + |
| 62 | + var base: Base.Iterator |
| 63 | + var buffer: Base.Element.Magnitude = 0 |
| 64 | + |
| 65 | + mutating func next() -> Bool? { |
| 66 | + let r = buffer & 0x1 != 0 |
| 67 | + buffer >>= 1 |
| 68 | + if buffer != 0 { return r } |
| 69 | + guard let b = base.next() else { return nil } |
| 70 | + let r1 = b & 0x1 != 0 |
| 71 | + buffer = Base.Element.Magnitude(truncatingIfNeeded: b) |
| 72 | + buffer >>= 1 |
| 73 | + buffer |= 1 << (Base.Element.bitWidth - 1) |
| 74 | + return r1 |
| 75 | + } |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +extension Bits: Equatable where Base: Equatable {} |
| 80 | +extension Bits: Hashable where Base: Hashable {} |
| 81 | + |
| 82 | +extension Bits: RandomAccessCollection, BidirectionalCollection, Collection |
| 83 | + where Base: RandomAccessCollection |
| 84 | +{ |
| 85 | +// typealias Index = Int |
| 86 | + var startIndex: Int { return 0 } |
| 87 | + var endIndex: Int { return base.count * Base.Element.bitWidth } |
| 88 | + |
| 89 | + fileprivate func baseIndex(_ i: Int) -> Base.Index { |
| 90 | + base.index(base.startIndex, offsetBy: i / Base.Element.bitWidth) |
| 91 | + } |
| 92 | + |
| 93 | + subscript(i: Int) -> Bool { |
| 94 | + base[baseIndex(i)] & (1 << (i % Base.Element.bitWidth)) != 0 |
| 95 | + } |
| 96 | +} |
| 97 | + |
0 commit comments