I am trying to understand why the following code works:
import Foundation
// TODO: How to turn these two functions into Array extensions?
func arrayToFile<T>(array: [T], toFile url: URL) throws {
var array = array
/*let data = Data(bytes: &wArray, count: wArray.count * MemoryLayout<Double>.stride)*/
let data = Data(bytesNoCopy: &array, count: array.count * MemoryLayout<T>.stride, deallocator: .none)
try data.write(to: url)
}
func dataFileToArray<T>(url: URL) throws -> [T] {
let data = try Data(contentsOf: url)
let value = data.withUnsafeBytes {
$0.baseAddress?.assumingMemoryBound(to: T.self)
}
return [T](UnsafeBufferPointer(start: value, count: data.count / MemoryLayout<T>.stride))
}
func testArraySaving() {
let url = URL(fileURLWithPath: "./testBinary.data")
let longString = "asldkjfhiasdjkhfakjsdhfaksoufhasdhflajsdhlfkjahslkfawufaiuwehfuy4i7y10i724y051720469r8qywpoeuigahpsjkd;hajksdn;vas[vaoijspvjkansdkjvanpweufiqihp2i4utypqiw7rypgaywrg97atpsdiufap093846t09w7640t97a60rs7gatypsiudhafpskjhfpqu3i4ipt793rpgya9usphgajshgaljks]"
let testArray: [String] = ["one", "two", "three", longString, "eleventeenth", longString]
// let testDoublesArray: [Double] = [1.0, 2.0, 3.0, 4.0, 5.0]
do {
try arrayToFile(array: testArray, toFile: url)
} catch {
print("Failed to save: \(error)")
}
do {
let result: [String] = try dataFileToArray(url: url)
assert(result[3] == longString)
assert(result[5] == longString)
print(result)
} catch {
print("Failed to read: \(error)")
}
}
testArraySaving()
Specifically, why does this successfully store and retrieve Strings of varying lengths? It relies on MemoryLayout<String>.stride. I understand this would work with types like Bool or Float because they are fixed length - always a certain number of bytes. However, this is not the case for Strings, which can be arbitrarily long. Rather than describing the length of the String, is this instead describing the pointers to the Strings?
This becomes even more confusing when I realize this works too:
let testArray: [Any] = ["one", "two", true, 4.33, longString, "eleventeenth", longString, [1, 2, 3, 4]]
...
let result: [Any] = try dataFileToArray(url: url)
print(result[0]) // one
print(type(of: result[0])) // String
print(result[7]) // [1, 2, 3, 4]
print(type(of: result[7])) // Array<Int>
When the type of array being stored and retrieved is set to Any, it even works for arrays within arrays. What does it mean to have a MemoryLayout<Any>? Each individual element is not an Any?
What is this voodoo magįcks?