Skip to content

Commit

Permalink
Add performance tests. Small optimisations.
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaRU committed Mar 6, 2024
1 parent 31b6a69 commit 2d545c6
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 39 deletions.
15 changes: 1 addition & 14 deletions Sources/CDRCodable/Decoder/CDRDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ final class DataStore {
}
}

final class _CDRDecoder {
struct _CDRDecoder {
var codingPath: [CodingKey] = []
let userInfo: [CodingUserInfoKey : Any]
fileprivate var container: _CDRDecodingContainer?
var dataStore: DataStore

init(dataStore: DataStore, userInfo: [CodingUserInfoKey : Any]) {
Expand All @@ -75,29 +74,17 @@ final class _CDRDecoder {

extension _CDRDecoder: Decoder {
func container<Key>(keyedBy type: Key.Type) -> KeyedDecodingContainer<Key> where Key : CodingKey {
precondition(self.container == nil)

let container = KeyedContainer<Key>(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return KeyedDecodingContainer(container)
}

func unkeyedContainer() throws -> UnkeyedDecodingContainer {
precondition(self.container == nil)

let container = try UnkeyedContainer(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return container
}

func singleValueContainer() -> SingleValueDecodingContainer {
precondition(self.container == nil)

let container = SingleValueContainer(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return container
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/CDRCodable/Decoder/KeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ extension _CDRDecoder.KeyedContainer: KeyedDecodingContainerProtocol {
}

func superDecoder(forKey key: Key) throws -> Decoder {
let decoder = _CDRDecoder(dataStore: dataStore, userInfo: userInfo)
var decoder = _CDRDecoder(dataStore: dataStore, userInfo: userInfo)
decoder.codingPath = [key]
return decoder
}
Expand Down
21 changes: 4 additions & 17 deletions Sources/CDRCodable/Encoder/CDREncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ final public class CDREncoder {
try dataStore.write(count: value.count)
dataStore.write(data: value)
default:
let encoder: _CDREncoder = _CDREncoder(data: dataStore)
encoder.userInfo = self.userInfo
let encoder: _CDREncoder = _CDREncoder(data: dataStore, userInfo: userInfo)
try value.encode(to: encoder)
}

Expand All @@ -62,7 +61,7 @@ protocol _CDREncodingContainer {
func write(count: Int) throws
}

final class _CDREncoder {
struct _CDREncoder {
final class DataStore {
var data: Data
init(capacity: Int) {
Expand All @@ -72,39 +71,27 @@ final class _CDREncoder {

var codingPath: [CodingKey] = []
var userInfo: [CodingUserInfoKey : Any] = [:]
fileprivate var container: _CDREncodingContainer?
var dataStore: DataStore

init(data: DataStore) {
init(data: DataStore, userInfo: [CodingUserInfoKey : Any]) {
self.dataStore = data
self.userInfo = userInfo
}
}

extension _CDREncoder: Encoder {
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
precondition(self.container == nil)

let container = KeyedContainer<Key>(data: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
self.container = container

return KeyedEncodingContainer(container)
}

func unkeyedContainer() -> UnkeyedEncodingContainer {
precondition(self.container == nil)

let container = UnkeyedContainer(dataStore: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
self.container = container

return container
}

func singleValueContainer() -> SingleValueEncodingContainer {
precondition(self.container == nil)

let container = SingleValueContainer(dataStore: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
self.container = container

return container
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/CDRCodable/Encoder/KeyedEncodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ extension _CDREncoder.KeyedContainer: KeyedEncodingContainerProtocol {
try write(count: value.count)
dataStore.write(data: value)
default:
let encoder = _CDREncoder(data: self.dataStore)
let encoder = _CDREncoder(data: self.dataStore, userInfo: self.userInfo)
try value.encode(to: encoder)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extension _CDREncoder.SingleValueContainer: SingleValueEncodingContainer {
try write(count: data.count)
dataStore.write(data: data)
default:
let encoder = _CDREncoder(data: self.dataStore)
let encoder = _CDREncoder(data: self.dataStore, userInfo: self.userInfo)
try value.encode(to: encoder)
}
}
Expand Down
12 changes: 7 additions & 5 deletions Sources/CDRCodable/Encoder/UnkeyedEncodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ extension _CDREncoder.UnkeyedContainer: UnkeyedEncodingContainer {
func encodeNil() throws {}

mutating func encode<T>(_ value: T) throws where T : Encodable {
guard let count32 = UInt32(exactly: count + 1) else {
let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode data of length \(count + 1).")
throw EncodingError.invalidValue(count + 1, context)
}
let range = index..<index+MemoryLayout<UInt32>.size
self.dataStore.data.replaceSubrange(range, with: count32.bytes)
defer {
count += 1
if let count32 = UInt32(exactly: count) {
let range = index..<index+MemoryLayout<UInt32>.size
self.dataStore.data.replaceSubrange(range, with: count32.bytes)
}
}
let encoder = _CDREncoder(data: self.dataStore)
let encoder = _CDREncoder(data: self.dataStore, userInfo: self.userInfo)
try value.encode(to: encoder)
}

Expand Down
37 changes: 37 additions & 0 deletions Tests/CDRCodableTests/CDRCodablePerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,42 @@ class CDRCodablePerformanceTests: XCTestCase {
}
}
}

func testPerformanceArrayOfStructEncode() {
struct TestStruct: Codable {
struct Internal: Codable {
let x: Int16
let y: Int16
}
let a: [Internal]
}
let testStruct = TestStruct(a: .init(repeating: .init(x: 1, y: 2), count: 1024))

self.measure {
for _ in 1...10 {
let cdrData = try! encoder.encode(testStruct)
XCTAssertEqual(cdrData.count, 4100)
}
}
}

func testPerformanceArrayOfStructDecode() {
struct TestStruct: Codable {
struct Internal: Codable {
let x: Int16
let y: Int16
}
let a: [Internal]
}
let testStruct = TestStruct(a: .init(repeating: .init(x: 1, y: 2), count: 1024))
let cdrData = try! encoder.encode(testStruct)

self.measure {
for _ in 1...10 {
let testStruct1 = try! decoder.decode(TestStruct.self, from: cdrData)
XCTAssertEqual(testStruct1.a[0].x, 1)
}
}
}

}

0 comments on commit 2d545c6

Please sign in to comment.