typealias Stuff = [[String]] // typically zillions of items
var stuff: [String: Stuff] = [:] // tens of these
When I deep copy† a Stuff,
spare: Stuff = original{
let line = $0.map{ $0 }
return line
}
it takes 1/2 sec on a new phone, so of course to avoid.
Now say I am working with a Stuff, like this calculations(on: "Cats"), strictly reading from stuff["Cats"]
///Strictly reading from Stuff
func calculations(on: String) {
guard stuff[on] != nil else { return }
.. = stuff[on]!.blah.blah
.. = stuff[on]!.blah.blah
..
.. dozens and dozens of reads from stuff[on]!
}
Of course it is much tidier if you
///Strictly reading from Stuff
func calculations(on: String) {
guard let p = stuff[on] else { return }
.. = p.blah.blah
.. = p.blah.blah
..
.. dozens and dozens of reads from p
}
If I do that,
is it indeed not making a deep copy of
stuff["Cats"]?Is that truly reliable, and it will absolutely never do so?
As a related question, I believe, but I'm not sure,
that this would be how you check if indeed p is not a deep copy of stuff["Cats"] ->
withUnsafePointer(to: &p[0][0]) {
print("p is at \($0)")
}
withUnsafePointer(to: &stuff["Cats"][0][0]) {
print("whereas stuff["Cats"][0][0] is at \($0)")
}
Looks right?
† As an aside, I really don't know if that is the best way to deep copy a 2D string array in Swift.
Yes it is guaranteed that no copies of the array storage are made.
Arrayhas copy-on-write behaviour:Though
let p = stuff[on]copies the value ofstuff[on]top, the value of theArraystruct is small - only 8 bytes on my machine (seeMemoryLayout<[[String]]>.size).The 8-byte struct value includes a pointer to some storage location for the array, and
pandstuff[on]would be pointing to the same storage location, as the documentation says. From the standard library source, this would be an instance of the class__ContiguousArrayStorageBase.The array storage will only be copied if you modify
stuff[on]by e.g. adding another[String]to it.pandstuff[on]would now point to different storage locations. But even then, the inner arrays will still share storage, since you didn't modify the inner arrays.Related: How are updates to var arrays handled in Swift memory (confused about CoW)
As for comparing the pointers, your code is comparing the locations of the elements in the inner array. As I said above, the outer array's storage could be copied even when the inner arrays are not, and vice versa, so you might want to compare
&stuff["Cats"][0]and&p["Cats"][0]too.