Skip to content

Commit c37102b

Browse files
committed
Revert the implementation changes from 1.4.0 release
Unfortunately, it turns out, that UnsafeBufferPointer implementation strategy doesn't work with Swift 5.0.
1 parent 5cdf342 commit c37102b

5 files changed

Lines changed: 500 additions & 134 deletions

File tree

BitByteData.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
06F065761FFAEA8700312A82 /* BitReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F065581FFAEA1F00312A82 /* BitReader.swift */; };
1515
06F065771FFAEA8700312A82 /* ByteReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F065591FFAEA1F00312A82 /* ByteReader.swift */; };
1616
06F065781FFAEA8700312A82 /* MsbBitReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F0655A1FFAEA1F00312A82 /* MsbBitReader.swift */; };
17+
06F065791FFAEA8700312A82 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F0655B1FFAEA1F00312A82 /* Extensions.swift */; };
1718
06F0657A1FFAEA8700312A82 /* MsbBitWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F0655C1FFAEA1F00312A82 /* MsbBitWriter.swift */; };
1819
06F0657B1FFAEA8700312A82 /* BitWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F0655D1FFAEA1F00312A82 /* BitWriter.swift */; };
1920
06F0657C1FFAEA8700312A82 /* LsbBitWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F0655E1FFAEA1F00312A82 /* LsbBitWriter.swift */; };
@@ -61,6 +62,7 @@
6162
06F065581FFAEA1F00312A82 /* BitReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitReader.swift; sourceTree = "<group>"; };
6263
06F065591FFAEA1F00312A82 /* ByteReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ByteReader.swift; sourceTree = "<group>"; };
6364
06F0655A1FFAEA1F00312A82 /* MsbBitReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsbBitReader.swift; sourceTree = "<group>"; };
65+
06F0655B1FFAEA1F00312A82 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
6466
06F0655C1FFAEA1F00312A82 /* MsbBitWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsbBitWriter.swift; sourceTree = "<group>"; };
6567
06F0655D1FFAEA1F00312A82 /* BitWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitWriter.swift; sourceTree = "<group>"; };
6668
06F0655E1FFAEA1F00312A82 /* LsbBitWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LsbBitWriter.swift; sourceTree = "<group>"; };
@@ -119,6 +121,7 @@
119121
06F065561FFAEA1F00312A82 /* Sources */ = {
120122
isa = PBXGroup;
121123
children = (
124+
06F0655B1FFAEA1F00312A82 /* Extensions.swift */,
122125
06F065591FFAEA1F00312A82 /* ByteReader.swift */,
123126
06F065581FFAEA1F00312A82 /* BitReader.swift */,
124127
06F065571FFAEA1F00312A82 /* LsbBitReader.swift */,
@@ -278,6 +281,7 @@
278281
isa = PBXSourcesBuildPhase;
279282
buildActionMask = 2147483647;
280283
files = (
284+
06F065791FFAEA8700312A82 /* Extensions.swift in Sources */,
281285
06F0657A1FFAEA8700312A82 /* MsbBitWriter.swift in Sources */,
282286
06F0657C1FFAEA8700312A82 /* LsbBitWriter.swift in Sources */,
283287
06F0657B1FFAEA8700312A82 /* BitWriter.swift in Sources */,

Sources/ByteReader.swift

Lines changed: 154 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -15,64 +15,50 @@ public class ByteReader {
1515
public let data: Data
1616

1717
/// Offset to the byte in `data` which will be read next.
18-
public var offset: Int {
19-
get {
20-
return self._offset + self.dataStartIndex
21-
}
22-
set {
23-
self._offset = newValue - self.dataStartIndex
24-
}
25-
}
26-
27-
var _offset: Int
28-
29-
/*
30-
Generally speaking, what we are doing here is not really safe: pointer can become invalid if the storage of `data`
31-
is non-contiguous, but (unfortunately, in a way) I was unable to produce an example which would cause any issues.
32-
33-
Despite this, it was still decided to use this implementation strategy because:
34-
1. We cannot use `Data.withUnsafeBytes` because it is ridiculously slow.
35-
2. We cannot use `Data.copyBytes` because, well, it copies bytes.
36-
3. We would like to switch to `UnsafePointer` instead of `Data` to eliminate redundant out of bounds checks
37-
(because we check indices ourselves and can guarantee that they are correct), and, thus, significantly improve
38-
performance.
39-
40-
Finally, it is worth mentioning that `NSData` actually has a convenient property `bytes` which provides access
41-
to the pointer to the storage, but, for some reason, `Data` doesn't have it. We also cannot convert between `Data`
42-
to `NSData` using `as` operator since it is not supposed to work on non-Darwin platforms (but, surprisingly, it
43-
works with Swift 4.2).
44-
*/
45-
final let ptr: UnsafeBufferPointer<UInt8>
46-
private final let dataStartIndex: Int // For efficient (without access to `data`) implementation of `offset`.
18+
public var offset: Int
4719

4820
/**
4921
True, if `offset` points at any position after the last byte in `data`.
5022

5123
- Note: It generally means that all bytes have been read.
5224
*/
5325
public var isFinished: Bool {
54-
return self.size <= self._offset
26+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
27+
return { (data: Data, offset: Int) -> Bool in
28+
return data.endIndex <= offset
29+
} (self.data, self.offset)
30+
#else
31+
return self.data.endIndex <= self.offset
32+
#endif
5533
}
5634

5735
/// Amount of bytes left to read.
5836
public var bytesLeft: Int {
59-
return self.size - self._offset
37+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
38+
return { (data: Data, offset: Int) -> Int in
39+
return data.endIndex - offset
40+
} (self.data, self.offset)
41+
#else
42+
return self.data.endIndex - self.offset
43+
#endif
6044
}
6145

6246
/// Amount of bytes that were already read.
6347
public var bytesRead: Int {
64-
return self._offset
48+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
49+
return { (data: Data, offset: Int) -> Int in
50+
return offset - data.startIndex
51+
} (self.data, self.offset)
52+
#else
53+
return self.offset - self.data.startIndex
54+
#endif
6555
}
6656

6757
/// Creates an instance for reading bytes from `data`.
6858
public init(data: Data) {
6959
self.size = data.count
7060
self.data = data
71-
self._offset = 0
72-
self.ptr = data.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> UnsafeBufferPointer<UInt8> in
73-
return UnsafeBufferPointer<UInt8>(start: ptr, count: data.count)
74-
}
75-
self.dataStartIndex = data.startIndex
61+
self.offset = data.startIndex
7662
}
7763

7864
/**
@@ -81,9 +67,17 @@ public class ByteReader {
8167
- Precondition: There MUST be enough data left.
8268
*/
8369
public func byte() -> UInt8 {
84-
precondition(self._offset < self.size)
85-
defer { self._offset += 1 }
86-
return self.ptr[self._offset]
70+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
71+
return { (data: Data, offset: inout Int) -> UInt8 in
72+
precondition(offset < data.endIndex)
73+
defer { offset += 1 }
74+
return data[offset]
75+
} (self.data, &self.offset)
76+
#else
77+
precondition(self.offset < self.data.endIndex)
78+
defer { self.offset += 1 }
79+
return self.data[self.offset]
80+
#endif
8781
}
8882

8983
/**
@@ -94,14 +88,17 @@ public class ByteReader {
9488
*/
9589
public func bytes(count: Int) -> [UInt8] {
9690
precondition(count >= 0)
97-
precondition(bytesLeft >= count)
98-
var result = [UInt8]()
99-
result.reserveCapacity(count)
100-
for _ in 0..<count {
101-
result.append(self.ptr[self._offset])
102-
self._offset += 1
103-
}
104-
return result
91+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
92+
return { (data: Data, offset: inout Int) -> [UInt8] in
93+
precondition(data.endIndex - offset >= count)
94+
defer { offset += count }
95+
return data[offset..<offset + count].toArray(type: UInt8.self, count: count)
96+
} (self.data, &self.offset)
97+
#else
98+
precondition(bytesLeft >= count)
99+
defer { self.offset += count }
100+
return self.data[self.offset..<self.offset + count].toArray(type: UInt8.self, count: count)
101+
#endif
105102
}
106103

107104
/**
@@ -114,12 +111,25 @@ public class ByteReader {
114111
precondition(count >= 0)
115112
// TODO: If uintX() could be force inlined or something in the future then probably it would make sense
116113
// to use them for `count` == 2, 4 or 8.
117-
var result = 0
118-
for i in 0..<count {
119-
result += Int(truncatingIfNeeded: self.ptr[self._offset]) << (8 * i)
120-
self._offset += 1
121-
}
122-
return result
114+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
115+
return { (data: Data, offset: inout Int) -> Int in
116+
precondition(data.endIndex - offset >= count)
117+
var result = 0
118+
for i in 0..<count {
119+
result += Int(truncatingIfNeeded: data[offset]) << (8 * i)
120+
offset += 1
121+
}
122+
return result
123+
} (self.data, &self.offset)
124+
#else
125+
precondition(bytesLeft >= count)
126+
var result = 0
127+
for i in 0..<count {
128+
result += Int(truncatingIfNeeded: self.data[self.offset]) << (8 * i)
129+
self.offset += 1
130+
}
131+
return result
132+
#endif
123133
}
124134

125135
/**
@@ -128,7 +138,17 @@ public class ByteReader {
128138
- Precondition: There MUST be enough data left.
129139
*/
130140
public func uint64() -> UInt64 {
131-
return self.uint64(fromBytes: 8)
141+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
142+
return { (data: Data, offset: inout Int) -> UInt64 in
143+
precondition(data.endIndex - offset >= 8)
144+
defer { offset += 8 }
145+
return data[offset..<offset + 8].to(type: UInt64.self)
146+
} (self.data, &self.offset)
147+
#else
148+
precondition(bytesLeft >= 8)
149+
defer { self.offset += 8 }
150+
return self.data[self.offset..<self.offset + 8].to(type: UInt64.self)
151+
#endif
132152
}
133153

134154
/**
@@ -142,13 +162,25 @@ public class ByteReader {
142162
*/
143163
public func uint64(fromBytes count: Int) -> UInt64 {
144164
precondition(0...8 ~= count)
145-
precondition(bytesLeft >= count)
146-
var result = 0 as UInt64
147-
for i in 0..<count {
148-
result += UInt64(truncatingIfNeeded: self.ptr[self._offset]) << (8 * i)
149-
self._offset += 1
150-
}
151-
return result
165+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
166+
return { (data: Data, offset: inout Int) -> UInt64 in
167+
precondition(data.endIndex - offset >= count)
168+
var result = 0 as UInt64
169+
for i in 0..<count {
170+
result += UInt64(truncatingIfNeeded: data[offset]) << (8 * i)
171+
offset += 1
172+
}
173+
return result
174+
} (self.data, &self.offset)
175+
#else
176+
precondition(bytesLeft >= count)
177+
var result = 0 as UInt64
178+
for i in 0..<count {
179+
result += UInt64(truncatingIfNeeded: self.data[self.offset]) << (8 * i)
180+
self.offset += 1
181+
}
182+
return result
183+
#endif
152184
}
153185

154186
/**
@@ -157,7 +189,17 @@ public class ByteReader {
157189
- Precondition: There MUST be enough data left.
158190
*/
159191
public func uint32() -> UInt32 {
160-
return self.uint32(fromBytes: 4)
192+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
193+
return { (data: Data, offset: inout Int) -> UInt32 in
194+
precondition(data.endIndex - offset >= 4)
195+
defer { offset += 4 }
196+
return data[offset..<offset + 4].to(type: UInt32.self)
197+
} (self.data, &self.offset)
198+
#else
199+
precondition(bytesLeft >= 4)
200+
defer { self.offset += 4 }
201+
return self.data[self.offset..<self.offset + 4].to(type: UInt32.self)
202+
#endif
161203
}
162204

163205
/**
@@ -171,13 +213,25 @@ public class ByteReader {
171213
*/
172214
public func uint32(fromBytes count: Int) -> UInt32 {
173215
precondition(0...4 ~= count)
174-
precondition(bytesLeft >= count)
175-
var result = 0 as UInt32
176-
for i in 0..<count {
177-
result += UInt32(truncatingIfNeeded: self.ptr[self._offset]) << (8 * i)
178-
self._offset += 1
179-
}
180-
return result
216+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
217+
return { (data: Data, offset: inout Int) -> UInt32 in
218+
precondition(data.endIndex - offset >= count)
219+
var result = 0 as UInt32
220+
for i in 0..<count {
221+
result += UInt32(truncatingIfNeeded: data[offset]) << (8 * i)
222+
offset += 1
223+
}
224+
return result
225+
} (self.data, &self.offset)
226+
#else
227+
precondition(bytesLeft >= count)
228+
var result = 0 as UInt32
229+
for i in 0..<count {
230+
result += UInt32(truncatingIfNeeded: self.data[self.offset]) << (8 * i)
231+
self.offset += 1
232+
}
233+
return result
234+
#endif
181235
}
182236

183237
/**
@@ -186,7 +240,17 @@ public class ByteReader {
186240
- Precondition: There MUST be enough data left.
187241
*/
188242
public func uint16() -> UInt16 {
189-
return self.uint16(fromBytes: 2)
243+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
244+
return { (data: Data, offset: inout Int) -> UInt16 in
245+
precondition(data.endIndex - offset >= 2)
246+
defer { offset += 2 }
247+
return data[offset..<offset + 2].to(type: UInt16.self)
248+
} (self.data, &self.offset)
249+
#else
250+
precondition(bytesLeft >= 2)
251+
defer { self.offset += 2 }
252+
return self.data[self.offset..<self.offset + 2].to(type: UInt16.self)
253+
#endif
190254
}
191255

192256
/**
@@ -200,13 +264,25 @@ public class ByteReader {
200264
*/
201265
public func uint16(fromBytes count: Int) -> UInt16 {
202266
precondition(0...2 ~= count)
203-
precondition(bytesLeft >= count)
204-
var result = 0 as UInt16
205-
for i in 0..<count {
206-
result += UInt16(truncatingIfNeeded: self.ptr[self._offset]) << (8 * i)
207-
self._offset += 1
208-
}
209-
return result
267+
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
268+
return { (data: Data, offset: inout Int) -> UInt16 in
269+
precondition(data.endIndex - offset >= count)
270+
var result = 0 as UInt16
271+
for i in 0..<count {
272+
result += UInt16(truncatingIfNeeded: data[offset]) << (8 * i)
273+
offset += 1
274+
}
275+
return result
276+
} (self.data, &self.offset)
277+
#else
278+
precondition(bytesLeft >= count)
279+
var result = 0 as UInt16
280+
for i in 0..<count {
281+
result += UInt16(truncatingIfNeeded: self.data[self.offset]) << (8 * i)
282+
self.offset += 1
283+
}
284+
return result
285+
#endif
210286
}
211287

212288
}

Sources/Extensions.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2018 Timofey Solomko
2+
// Licensed under MIT License
3+
//
4+
// See LICENSE for license information
5+
6+
import Foundation
7+
8+
extension Data {
9+
10+
@inline(__always)
11+
func to<T>(type: T.Type) -> T {
12+
return self.withUnsafeBytes { $0.pointee }
13+
}
14+
15+
@inline(__always)
16+
func toArray<T>(type: T.Type, count: Int) -> [T] {
17+
return self.withUnsafeBytes {
18+
[T](UnsafeBufferPointer(start: $0, count: count))
19+
}
20+
}
21+
22+
}

0 commit comments

Comments
 (0)