metatext-app-ios-iphone-ipad/CodableBloomFilter/Sources/CodableBloomFilter/BitArray.swift

73 lines
1.8 KiB
Swift

// Copyright © 2020 Metabolist. All rights reserved.
// Adapted from https://github.com/dduan/BitArray
import Foundation
struct BitArray {
private var bytes: [UInt8]
init(data: Data) {
bytes = Array(data)
}
}
extension BitArray {
var bitCount: Int { bytes.count * Self.bitsInByte }
var data: Data { Data(bytes) }
subscript(index: Int) -> Bool {
get {
let (byteIndex, bitIndex) = Self.byteAndBitIndices(index: index)
return bytes[byteIndex] & Self.mask(bitIndex: bitIndex) > 0
}
set {
let (byteIndex, bitIndex) = Self.byteAndBitIndices(index: index)
if newValue {
bytes[byteIndex] |= Self.mask(bitIndex: bitIndex)
} else {
bytes[byteIndex] &= ~Self.mask(bitIndex: bitIndex)
}
}
}
}
extension BitArray: Codable {
init(from decoder: Decoder) throws {
bytes = Array(try decoder.singleValueContainer().decode(Data.self))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(Data(bytes))
}
}
private extension BitArray {
static let bitsInByte = 8
static func byteAndBitIndices(index: Int) -> (Int, Int) {
index.quotientAndRemainder(dividingBy: bitsInByte)
}
static func mask(bitIndex: Int) -> UInt8 {
switch bitIndex {
case 0: return 0b00000001
case 1: return 0b00000010
case 2: return 0b00000100
case 3: return 0b00001000
case 4: return 0b00010000
case 5: return 0b00100000
case 6: return 0b01000000
case 7: return 0b10000000
default:
fatalError("Invalid bit index: \(bitIndex)")
}
}
}