我有一个非常大的结构,我想确保不会被不必要地复制。如何为它创建一个copy-on-write容器?
答案 0 :(得分:6)
写时复制通常是某个后备对象的struct
包装器。
public final class MutableHeapStore<T>: NonObjectiveCBase
{
public typealias Storage = T
public private(set) var storage: Storage
public init(storage: Storage)
{
self.storage = storage
}
}
public struct COW<T>
{
public typealias Storage = MutableHeapStore<T>
public typealias Value = T
public var storage: Storage
public init(storage: Storage)
{
self.storage = storage
}
public var value: Value
{
get
{
return storage.storage
}
set
{
if isUniquelyReferenced(&storage)
{
storage.storage = newValue
}
else
{
storage = Storage(storage: newValue)
}
}
}
public init(_ value: Value)
{
self.init(storage: Storage(storage: value))
}
}
extension COW: CustomStringConvertible
{
public var description: String
{
return String(value)
}
}
诀窍在于每次盒装值发生变异时断言isUniquelyReferenced
。如果单独引用底层存储对象,则不执行任何操作。但是,如果存在另一个引用,则必须创建新存储。
这段代码是否是线程安全的?它与任何其他值类型一样安全,例如Int
或Bool
。
答案 1 :(得分:2)
这是一个更简单的例子。
struct COWExample1<T> {
private var box = Box<[T]>(value: [T]())
var count: Int {
return box.value.count
}
mutating func append(e: T) {
ensureBoxUniqueRefed()
box.value.append(e)
}
private mutating func ensureBoxUniqueRefed() {
if isUniquelyReferencedNonObjC(&box) == false {
box = box.duplicated()
}
}
}
private final class Box<T> {
var value: T
init(value: T) {
self.value = value
}
func duplicated() -> Box<T> {
return Box(value: value)
}
}
答案 2 :(得分:2)
之前的答案并不错,但这种方法更为简单。 Swift团队有a list of performance tips,他们说:
实现写时复制的最简单方法是组合现有的写时复制数据结构,例如Array。
它并不比那简单得多!