I have a huge array that I want to copy only a middle portion of it. I'm trying to use memcpy
for the performance, but can't figure out a way to do so. Below is an example. How do we provide an offset to the source?
var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]
memcpy(&dest[2], source, 5)
print(dest) // [0, 0, 1, 2, 3, 4, 5, 0, 0]
// This works
var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]
memcpy(&dest[2], &source[2], 5)
print(dest) // [0, 0, 3, 0, 0, 0, 0, 0, 0]
// Only `source[2]` is copied
You can use replaceSubrange()
for that purpose:
let source: [UInt8] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
var dest: [UInt8] = [0, 0, 0, 0, 0, 0, 0, 0, 0]
dest.replaceSubrange(2..<(2+5), with: source[2..<(2+5)])
print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]
or simply assign a source slice to a destination slice:
dest[2..<(2+5)] = source[2..<(2+5)]
print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]
on a MacBook Air M2, with the code compiled in Release configuration.
import Foundation
let N = 1_000_000 // Length of source and destination array
let sourceStart = 500
let destinationStart = 2000
let length = 12345
let source: [UInt8] = Array(repeating: 5, count: N)
for _ in 1...10 {
do {
var dest: [UInt8] = Array(repeating: 0, count: N)
let start = Date()
dest[destinationStart..<(destinationStart+length)].withUnsafeMutableBufferPointer { p in
source.copyBytes(to: p, from: sourceStart..<sourceStart + length)
}
let end = Date()
print("copyBytes: ", end.timeIntervalSince(start) * 1000, "ms")
}
do {
var dest: [UInt8] = Array(repeating: 0, count: N)
let start = Date()
source.withUnsafeBytes { sourcePtr in
_ = memcpy(&dest[destinationStart], sourcePtr.baseAddress! + sourceStart, length)
}
let end = Date()
print("memcpy: ", end.timeIntervalSince(start) * 1000, "ms")
}
do {
var dest: [UInt8] = Array(repeating: 0, count: N)
let start = Date()
dest.replaceSubrange(destinationStart..<(destinationStart+length),
with: source[sourceStart..<(sourceStart+length)])
let end = Date()
print("replaceSubrange:", end.timeIntervalSince(start) * 1000, "ms")
}
do {
var dest: [UInt8] = Array(repeating: 0, count: N)
let start = Date()
dest[destinationStart..<(destinationStart+length)]
= source[sourceStart..<(sourceStart+length)]
let end = Date()
print("slicing: ", end.timeIntervalSince(start) * 1000, "ms")
}
print()
}
Results:
copyBytes: 0.010013580322265625 ms
memcpy: 0.0010728836059570312 ms
replaceSubrange: 0.009059906005859375 ms
slicing: 0.010013580322265625 ms