Skip to content

Commit

Permalink
Optimize encoding unkeyed arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaRU committed Jan 30, 2024
1 parent e02714e commit d229e7c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
37 changes: 36 additions & 1 deletion Sources/CDRCodable/Encoder/CDREncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,25 @@ final public class CDREncoder {
var encoder: _CDREncoder? = _CDREncoder(data: dataBlock)
encoder!.userInfo = self.userInfo

try value.encode(to: encoder!)
switch value {
case let value as [Int]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Int>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Int8]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Int8>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Int16]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Int16>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Int32]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Int32>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Int64]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Int64>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [UInt]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<UInt>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [UInt8]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<UInt8>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [UInt16]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<UInt16>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [UInt32]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<UInt32>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [UInt64]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<UInt64>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Float]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Float>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as [Double]: try encoder!.encodeNumericArray(count: value.count, size: MemoryLayout<Double>.size, pointer: value.withUnsafeBytes{ $0 })
case let value as Data:
try encoder!.dataStore.write(count: value.count)
encoder!.dataStore.write(data: value)
default:
try value.encode(to: encoder!)
}

encoder = nil // call deinit and finalize dataBlock changes.
// Final data aligment
Expand Down Expand Up @@ -61,6 +79,15 @@ final class _CDREncoder {
init(data: DataStore) {
self.dataStore = data
}
@inline(__always)
func encodeNumericArray(count: Int, size: Int, pointer: UnsafeRawBufferPointer) throws {
guard let uint32 = UInt32(exactly: count) else {
let context = EncodingError.Context(codingPath: [], debugDescription: "Cannot encode data of length \(count).")
throw EncodingError.invalidValue(count, context)
}
dataStore.write(value: uint32)
dataStore.data.append(pointer.baseAddress!.assumingMemoryBound(to: UInt8.self), count: count * size)
}
}

extension _CDREncoder: Encoder {
Expand Down Expand Up @@ -116,6 +143,14 @@ extension _CDREncoder.DataStore {
}
self.data.append(contentsOf: value.bytes)
}

func write(count: Int) throws {
guard let uint32 = UInt32(exactly: count) else {
let context = EncodingError.Context(codingPath: [], debugDescription: "Cannot encode data of length \(count).")
throw EncodingError.invalidValue(count, context)
}
write(value: uint32)
}
}

extension _CDREncodingContainer {
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 @@ -22,7 +22,7 @@ extension _CDREncoder.KeyedContainer: KeyedEncodingContainerProtocol {
@inline(__always)
private func encodeNumericArray(count: Int, size: Int, pointer: UnsafeRawBufferPointer) throws {
try write(count: count)
self.dataStore.data.append(pointer.baseAddress!.assumingMemoryBound(to: UInt8.self), count: count * size)
dataStore.data.append(pointer.baseAddress!.assumingMemoryBound(to: UInt8.self), count: count * size)
}

// Ignoring optionals as having no analog in the CDR protocol
Expand Down
3 changes: 1 addition & 2 deletions Sources/CDRCodable/Encoder/UnkeyedEncodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ extension _CDREncoder {
let count: UInt32 = 0
self.index = dataStore.data.endIndex
dataStore.write(value: count)
self.index = dataStore.data.endIndex
}

deinit {
if let count32 = UInt32(exactly: count) {
let range = index-4..<index
let range = index..<index+MemoryLayout<UInt32>.size
self.dataStore.data.replaceSubrange(range, with: count32.bytes)
}
}
Expand Down

0 comments on commit d229e7c

Please sign in to comment.