Skip to content

Commit c837744

Browse files
committed
bit array
1 parent e67a1cc commit c837744

25 files changed

+293
-302
lines changed

Package.resolved

Lines changed: 0 additions & 16 deletions
This file was deleted.

Package.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ let package = Package(
88
products: [
99
.library(name: "Binary", targets: ["Binary"]),
1010
],
11-
dependencies: [
12-
.package(name: "List", url: "[email protected]:spacenation/swift-list.git", .upToNextMajor(from: "1.0.0")),
13-
],
1411
targets: [
15-
.target(name: "Binary", dependencies: ["List"]),
12+
.target(name: "Binary"),
1613
.testTarget(name: "BinaryTests", dependencies: ["Binary"])
1714
]
1815
)

Sources/Binary/Binary.swift

Lines changed: 0 additions & 2 deletions
This file was deleted.

Sources/Binary/Bit.swift

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Foundation
2+
3+
public extension BitArray {
4+
static func +(lhs: BitArray, rhs: BitArray) -> BitArray {
5+
lhs.append(rhs)
6+
}
7+
8+
static func +(lhs: Bool, rhs: BitArray) -> BitArray {
9+
BitArray(bool: lhs).append(rhs)
10+
}
11+
12+
static func +(lhs: BitArray, rhs: Bool) -> BitArray {
13+
lhs.append(BitArray(bool: rhs))
14+
}
15+
16+
func append(byte: UInt8) -> BitArray {
17+
self.append(BitArray(byte: byte))
18+
}
19+
20+
func append(_ other: BitArray) -> BitArray {
21+
guard let lastByte = self.bytes.last else { return other }
22+
guard let nextByte = other.bytes.first else { return self }
23+
24+
let bitsInLastByte = length % 8
25+
let lengthRemainingInNextByte = Swift.min(8, other.length)
26+
27+
switch bitsInLastByte {
28+
/// Aligned append
29+
case 0:
30+
return BitArray(bytes: self.bytes + other.bytes, length: self.length + other.length)
31+
/// New length fits into existing byte
32+
case _ where bitsInLastByte + lengthRemainingInNextByte <= 8:
33+
let modifiedLastByte: UInt8 = lastByte | (nextByte >> UInt8(bitsInLastByte))
34+
let newBytes: [UInt8] = self.bytes.dropLast() + [modifiedLastByte]
35+
return BitArray(bytes: newBytes, length: self.length + other.length)
36+
/// New byte size required
37+
default:
38+
let modifiedLastByte: UInt8 = lastByte | (nextByte >> UInt8(bitsInLastByte))
39+
let newByte: UInt8 = nextByte << (8 - UInt8(bitsInLastByte))
40+
let newBytes: [UInt8] = self.bytes.dropLast() + [modifiedLastByte, newByte]
41+
42+
return BitArray(bytes: newBytes, length: self.length + lengthRemainingInNextByte)
43+
.append(BitArray(bytes: Array(other.bytes.dropFirst()), length: other.length - lengthRemainingInNextByte))
44+
}
45+
}
46+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Foundation
2+
3+
extension BitArray: Collection {
4+
public typealias Index = Int
5+
6+
public var startIndex: Int {
7+
0
8+
}
9+
10+
public var endIndex: Int {
11+
length - 1
12+
}
13+
14+
public subscript(position: Int) -> Bool {
15+
self[safe: position]!
16+
}
17+
18+
public func index(after i: Int) -> Int {
19+
i + 1
20+
}
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Foundation
2+
3+
extension BitArray: Sequence {
4+
public func makeIterator() -> BitArrayIterator {
5+
BitArrayIterator(offset: 0, bitArray: self)
6+
}
7+
}
8+
9+
public struct BitArrayIterator: IteratorProtocol {
10+
public internal(set) var offset: Int
11+
public let bitArray: BitArray
12+
13+
public init(offset: Int, bitArray: BitArray) {
14+
self.offset = offset
15+
self.bitArray = bitArray
16+
}
17+
18+
public mutating func next() -> Bool? {
19+
defer {
20+
offset += 1
21+
}
22+
return bitArray[safe: offset]
23+
}
24+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
2+
public struct BitArray {
3+
4+
public static let empty = BitArray()
5+
6+
public internal(set) var length: Int
7+
public internal(set) var bytes: [UInt8]
8+
9+
10+
public init() {
11+
length = 0
12+
bytes = []
13+
}
14+
15+
public init(bytes: [UInt8], length: Int) {
16+
self.length = length
17+
self.bytes = bytes
18+
}
19+
20+
public init(bytes: [UInt8]) {
21+
length = bytes.count * 8
22+
self.bytes = bytes
23+
}
24+
25+
public init(byte: UInt8) {
26+
length = 8
27+
self.bytes = [byte]
28+
}
29+
30+
public init(byte: UInt8, length: Int) {
31+
self.length = length
32+
self.bytes = [byte]
33+
}
34+
35+
public init(bool: Bool) {
36+
length = 1
37+
switch bool {
38+
case true:
39+
self.bytes = [0b10000000]
40+
case false:
41+
self.bytes = [0]
42+
}
43+
}
44+
45+
public init(bools: [Bool]) {
46+
self = bools.reduce(.empty, +)
47+
}
48+
49+
public var asUInt8: UInt8 {
50+
bytes.first!
51+
}
52+
53+
public subscript(safe index: Int) -> Bool? {
54+
guard index >= 0, index < length else { return nil }
55+
let bitIndex = index % 8
56+
let byteIndex = index / 8
57+
let byte = bytes[byteIndex]
58+
let int = byte >> (8 - (bitIndex + 1)) & 0x0001
59+
return int == 0 ? false : true
60+
}
61+
}
62+
63+
extension BitArray : Hashable {}
64+
extension BitArray : Equatable {}
65+
66+
extension BitArray: ExpressibleByArrayLiteral {
67+
public init(arrayLiteral elements: Bool...) {
68+
self.init(bools: elements)
69+
}
70+
}
71+
72+
73+
extension BitArray: ExpressibleByIntegerLiteral {
74+
public init(integerLiteral value: UInt8) {
75+
self.init(byte: value)
76+
}
77+
}
78+
79+
func boolsToBytes(bools: [Bool]) -> [UInt8] {
80+
let paddedBools = Array(repeating: false, count: max(8 - bools.count, 0)) + bools
81+
let numBits = paddedBools.count
82+
let numBytes = (numBits + 7)/8
83+
var bytes = Array<UInt8>.init(repeating: 0, count: numBytes)
84+
85+
for (index, bit) in paddedBools.enumerated() {
86+
if bit {
87+
bytes[index / 8] += 1 << (7 - index % 8)
88+
}
89+
}
90+
91+
return bytes
92+
}
93+
94+
public extension BitArray {
95+
init(uInt8: UInt8, length: Int = 8) {
96+
self.init(byte: uInt8, length: length)
97+
}
98+
99+
init(uInt16: UInt16, length: Int = 16) {
100+
self.init(bytes: [UInt8(uInt16 & 0xff), UInt8(uInt16 >> 8)], length: length)
101+
}
102+
103+
init(uInt32: UInt32, length: Int = 32) {
104+
self.init(bytes: [UInt8(uInt32 & 0x000000FF), UInt8((uInt32 & 0x0000FF00) >> 8), UInt8((uInt32 & 0x00FF0000) >> 16), UInt8((uInt32 & 0xFF000000) >> 24)], length: length)
105+
}
106+
107+
init(uInt64: UInt64, length: Int = 64) {
108+
self.init(
109+
bytes: [
110+
UInt8(uInt64 & 0x00000000000000FF),
111+
UInt8((uInt64 & 0x000000000000FF00) >> 8),
112+
UInt8((uInt64 & 0x0000000000FF0000) >> 16),
113+
UInt8((uInt64 & 0x00000000FF000000) >> 24),
114+
UInt8((uInt64 & 0x000000FF00000000) >> 32),
115+
UInt8((uInt64 & 0x0000FF0000000000) >> 40),
116+
UInt8((uInt64 & 0x00FF000000000000) >> 48),
117+
UInt8((uInt64 & 0xFF00000000000000) >> 56),
118+
],
119+
length: length
120+
)
121+
}
122+
}

Sources/Binary/BitsExtensionStrategy.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

Sources/Binary/ByteOrder.swift

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)