1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2021 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
#if !COLLECTIONS_SINGLE_MODULE
import InternalCollectionsUtilities
#endif
extension BitArray {
/// An unsafe-unowned bitarray view over `UInt` storage, providing bit array
/// primitives.
@usableFromInline
@frozen
internal struct _UnsafeHandle {
@usableFromInline
internal typealias _BitPosition = _UnsafeBitSet.Index
@usableFromInline
internal let _words: UnsafeBufferPointer<_Word>
@usableFromInline
internal var _count: UInt
#if DEBUG
/// True when this handle does not support table mutations.
/// (This is only checked in debug builds.)
@usableFromInline
internal let _mutable: Bool
#endif
@inline(__always)
internal func ensureMutable() {
#if DEBUG
assert(_mutable)
#endif
}
internal var _mutableWords: UnsafeMutableBufferPointer<_Word> {
ensureMutable()
return UnsafeMutableBufferPointer(mutating: _words)
}
@inlinable
@inline(__always)
internal init(
words: UnsafeBufferPointer<_Word>,
count: UInt,
mutable: Bool
) {
assert(count <= words.count * _Word.capacity)
assert(count > (words.count - 1) * _Word.capacity)
self._words = words
self._count = count
#if DEBUG
self._mutable = mutable
#endif
}
@inlinable
@inline(__always)
internal init(
words: UnsafeMutableBufferPointer<_Word>,
count: UInt,
mutable: Bool
) {
self.init(
words: UnsafeBufferPointer(words),
count: count,
mutable: mutable)
}
}
}
extension BitArray._UnsafeHandle {
internal var count: Int {
Int(_count)
}
internal var end: _BitPosition {
_BitPosition(_count)
}
internal func set(at position: Int) {
ensureMutable()
assert(position >= 0 && position < _count)
let (word, bit) = _BitPosition(UInt(position)).split
_mutableWords[word].insert(bit)
}
internal func clear(at position: Int) {
ensureMutable()
assert(position >= 0 && position < _count)
let (word, bit) = _BitPosition(UInt(position)).split
_mutableWords[word].remove(bit)
}
internal subscript(position: Int) -> Bool {
get {
assert(position >= 0 && position < _count)
let (word, bit) = _BitPosition(UInt(position)).split
return _words[word].contains(bit)
}
set {
ensureMutable()
assert(position >= 0 && position < _count)
let (word, bit) = _BitPosition(UInt(position)).split
if newValue {
_mutableWords[word].insert(bit)
} else {
_mutableWords[word].remove(bit)
}
}
}
}
extension BitArray._UnsafeHandle {
internal mutating func fill(in range: Range<Int>) {
ensureMutable()
precondition(
range.lowerBound >= 0 && range.upperBound <= count,
"Range out of bounds")
guard range.count > 0 else { return }
let (lw, lb) = _BitPosition(range.lowerBound).split
let (uw, ub) = _BitPosition(range.upperBound).endSplit
let words = _mutableWords
guard lw != uw else {
words[lw].formUnion(_Word(from: lb, to: ub))
return
}
words[lw].formUnion(_Word(upTo: lb).complement())
for w in lw + 1 ..< uw {
words[w] = _Word.allBits
}
words[uw].formUnion(_Word(upTo: ub))
}
internal mutating func clear(in range: Range<Int>) {
ensureMutable()
precondition(
range.lowerBound >= 0 && range.upperBound <= count,
"Range out of bounds")
guard range.count > 0 else { return }
let (lw, lb) = _BitPosition(range.lowerBound).split
let (uw, ub) = _BitPosition(range.upperBound).endSplit
let words = _mutableWords
guard lw != uw else {
words[lw].subtract(_Word(from: lb, to: ub))
return
}
words[lw].subtract(_Word(upTo: lb).complement())
for w in lw + 1 ..< uw {
words[w] = _Word.empty
}
words[uw].subtract(_Word(upTo: ub))
}
}
|